Full Code of jarun/nnn for AI

master 722fc524dce8 cached
117 files
791.5 KB
260.3k tokens
242 symbols
1 requests
Download .txt
Showing preview only (828K chars total). Download the full file or copy to clipboard to get everything.
Repository: jarun/nnn
Branch: master
Commit: 722fc524dce8
Files: 117
Total size: 791.5 KB

Directory structure:
gitextract__6m8rskv/

├── .circleci/
│   └── config.yml
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── config.yml
│   └── workflows/
│       ├── ci.yml
│       ├── codeql.yml
│       └── lock.yml
├── .gitignore
├── CHANGELOG
├── LICENSE
├── Makefile
├── README.md
├── misc/
│   ├── CONTRIBUTING.md
│   ├── auto-completion/
│   │   ├── bash/
│   │   │   └── nnn-completion.bash
│   │   ├── fish/
│   │   │   └── nnn.fish
│   │   └── zsh/
│   │       └── _nnn
│   ├── desktop/
│   │   └── nnn.desktop
│   ├── haiku/
│   │   ├── Makefile
│   │   ├── haiku_interop.h
│   │   ├── nm.cpp
│   │   ├── nnn-master.recipe
│   │   └── nnn.rdef
│   ├── macos-legacy/
│   │   ├── mach_gettime.c
│   │   └── mach_gettime.h
│   ├── musl/
│   │   └── musl-static-ubuntu.sh
│   ├── natool/
│   │   └── natool
│   ├── packagecore/
│   │   └── packagecore.yaml
│   ├── quitcd/
│   │   ├── quitcd.bash_sh_zsh
│   │   ├── quitcd.csh
│   │   ├── quitcd.elv
│   │   ├── quitcd.fish
│   │   ├── quitcd.nu
│   │   └── quitcd.rc
│   └── test/
│       ├── benchmark.sh
│       ├── genfiles.sh
│       ├── mktest.sh
│       ├── plot-bench.py
│       └── verify-du.sh
├── nnn.1
├── patches/
│   ├── README.md
│   ├── check-patches.sh
│   ├── colemak/
│   │   └── mainline.diff
│   ├── gitstatus/
│   │   ├── mainline.diff
│   │   └── namefirst.diff
│   ├── namefirst/
│   │   └── mainline.diff
│   └── restorepreview/
│       └── mainline.diff
├── plugins/
│   ├── .cbcp
│   ├── .iconlookup
│   ├── .nmv
│   ├── .nnn-plugin-helper
│   ├── .ntfy
│   ├── README.md
│   ├── autojump
│   ├── boom
│   ├── bulknew
│   ├── cbcopy-mac
│   ├── cbpaste-mac
│   ├── cdpath
│   ├── chksum
│   ├── cmusq
│   ├── diffs
│   ├── dragdrop
│   ├── dups
│   ├── finder
│   ├── fixname
│   ├── fzcd
│   ├── fzhist
│   ├── fzopen
│   ├── fzplug
│   ├── getplugs
│   ├── gitroot
│   ├── gpgd
│   ├── gpge
│   ├── gpgs
│   ├── gpgv
│   ├── gsconnect
│   ├── gutenread
│   ├── imgresize
│   ├── imgur
│   ├── imgview
│   ├── ipinfo
│   ├── kdeconnect
│   ├── launch
│   ├── mimelist
│   ├── moclyrics
│   ├── mocq
│   ├── mp3conv
│   ├── mtpmount
│   ├── nbak
│   ├── nmount
│   ├── nuke
│   ├── oldbigfile
│   ├── openall
│   ├── organize
│   ├── pdfread
│   ├── preview-tabbed
│   ├── preview-tui
│   ├── pskill
│   ├── renamer
│   ├── ringtone
│   ├── rsynccp
│   ├── splitjoin
│   ├── suedit
│   ├── togglex
│   ├── umounttree
│   ├── upload
│   ├── wallpaper
│   ├── x2sel
│   └── xdgdefault
└── src/
    ├── .clang-tidy
    ├── dbg.h
    ├── icons-hash.c
    ├── icons-in-terminal.h
    ├── icons.h
    ├── nnn.c
    ├── nnn.h
    └── qsort.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .circleci/config.yml
================================================
version: 2

jobs:
  compile:
    docker:
      - image: ubuntu:24.04
        working_directory: ~/nnn
        environment:
          CI_FORCE_TEST: 1
    parallelism: 4
    steps:
      - run:
          command: |
            apt update -qq
            DEBIAN_FRONTEND="noninteractive" TZ="America/New_York" apt-get -y install tzdata
            apt install -y --no-install-recommends software-properties-common wget gpg-agent shellcheck
            apt install -y --no-install-recommends git make pkg-config libncurses-dev libreadline-dev
            apt install -y --no-install-recommends gcc-9 gcc-10 gcc-11 gcc-12 gcc-13 gcc-14
            apt install -y --no-install-recommends clang-14 clang-15 clang-16 clang-17 clang-18
            apt install -y --no-install-recommends clang-tidy-18
      - checkout
      - run:
          command: |
            export CFLAGS=-Werror
            make clean
            echo
            echo "########## gcc-9 ##########"
            CC=gcc-9 make strip
            ls -l nnn
            make clean
            echo
            echo "########## gcc-10 ##########"
            CC=gcc-10 make strip
            ls -l nnn
            make clean
            echo
            echo "########## gcc-11 ##########"
            CC=gcc-11 make strip
            ls -l nnn
            make clean
            echo
            echo "########## gcc-12 ##########"
            CC=gcc-12 make strip
            ls -l nnn
            make clean
            echo
            echo "########## gcc-13 ##########"
            CC=gcc-13 make strip
            ls -l nnn
            make clean
            echo
            echo "########## gcc-14 ##########"
            CC=gcc-14 make strip
            ls -l nnn
            make clean
            echo
            echo "########## clang-14 ##########"
            CC=clang-14 make strip
            ls -l nnn
            make clean
            echo
            echo "########## clang-15 ##########"
            CC=clang-15 make strip
            ls -l nnn
            make clean
            echo
            echo "########## clang-16 ##########"
            CC=clang-16 make strip
            ls -l nnn
            make clean
            echo
            echo "########## clang-17 ##########"
            CC=clang-17 make strip
            ls -l nnn
            make clean
            echo
            echo "########## clang-18 ##########"
            CC=clang-18 make strip
            ls -l nnn
            make clean
            echo
            echo "########## clang-tidy-18 ##########"
            clang-tidy-18 src/* -- -I/usr/include -I/usr/include/ncursesw
            echo "########## shellcheck ##########"
            find plugins/ -type f ! \( -name "*.md" -o -name "*-mac" \) -exec shellcheck {} +

  package-and-publish:
    machine: true
    working_directory: ~/nnn
    steps:
      - checkout
      - run:
          name: "auto-generate packages"
          command: |
            # Create dist directory if it doesn't exist
            mkdir ./dist
            # Clean up
            rm -rf ./dist/*
            # Pack source
            git archive -o ../${CIRCLE_PROJECT_REPONAME}-${CIRCLE_TAG}.tar.gz --format tar.gz --prefix=${CIRCLE_PROJECT_REPONAME}-${CIRCLE_TAG#v}/ ${CIRCLE_TAG}
            # Use latest installed python3 from pyenv
            export PYENV_VERSION="$(pyenv versions | grep -Po '\b3\.\d+\.\d+' | tail -1)"
            #pip install packagecore
            #packagecore -c misc/packagecore/packagecore.yaml -o ./dist/ ${CIRCLE_TAG#v}
            # Move source pack to dist
            mv ../${CIRCLE_PROJECT_REPONAME}-${CIRCLE_TAG}.tar.gz ./dist/

      - run:
          name: "publish to GitHub"
          command: |
            go install github.com/tcnksm/ghr@latest
            ghr -t ${GITHUB_API_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -replace ${CIRCLE_TAG} ./dist/

workflows:
  version: 2

  CircleCI:
    jobs: &all-tests
      - compile

  nightly:
    triggers:
      - schedule:
          cron: "0 0 * * 6"
          filters:
            branches:
              only:
                - master
    jobs: *all-tests

  publish-github-release:
    jobs:
      - package-and-publish:
          filters:
            tags:
              only: /^v.*/
            branches:
              ignore: /.*/


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: jarun


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---

`nnn` comes with excellent documentation (including a Troubleshooting section). If you have a _How to do x_ question, it may have already been answered. Wiki: https://github.com/jarun/nnn/wiki

If it looks like a local environment issue, please try to debug yourself. Debugging local setup issues is not our top priority.

If you are looking for a new feature or program option, ensure you have the correct version with the feature installed. Refer to the release notes to confirm.

Before opening an issue, please try to reproduce on latest master. The bug you noticed might have already been fixed.

Useful links:

- compile `nnn` from source - https://github.com/jarun/nnn/wiki/Usage#from-source
- debugging `nnn` - https://github.com/jarun/nnn/wiki/Developer-guides#debugging-nnn

If the issue can be reproduced on master, log it.

Please provide the environment details. **If that's missing, the issue will be closed without any cited reason.**

If we need more information and there is no communication from the bug reporter within 7 days from the date of request, we will close the issue. If you have relevant information, resume discussion any time.

--- PLEASE DELETE THIS LINE AND EVERYTHING ABOVE ---

#### Environment details (Put `x` in the checkbox along with the information)

- [ ] Operating System:
- [ ] Desktop Environment:
- [ ] Terminal Emulator:
- [ ] Shell:
- [ ] Custom desktop opener (if applicable):
- [ ] Program options used:
- [ ] Configuration options set:
- [ ] Plugins are installed
- [ ] Issue exists on `nnn` master

#### Exact steps to reproduce the issue


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
contact_links:
  - name: Idea, Enhancement, Question, Support
    url: https://github.com/jarun/nnn/discussions
    about: If you have a question, need support or want to discuss new ideas then please open a discussion thread.


================================================
FILE: .github/workflows/ci.yml
================================================
name: GitHubCI

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

jobs:
  macOS-gcc:
    runs-on: macOS-latest
    steps:
      - uses: actions/checkout@v2
      - name: Compile with gcc
        env:
          CC: gcc
        run: |
          export CFLAGS="$CFLAGS -Werror"
          make clean
          make
          make clean
  macOS-clang:
    runs-on: macOS-latest
    steps:
      - uses: actions/checkout@v2
      - name: Compile with clang
        env:
          CC: clang
        run: |
          # see: https://github.com/actions/setup-python/issues/577
          brew update || true
          brew install llvm || true
          brew unlink python@3.11 && brew link python@3.11
          export PATH="/usr/local/opt/llvm/bin:$PATH"
          export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
          export CFLAGS="$CFLAGS -Werror"
          make clean
          make
          make clean
          clang-tidy src/* -- -I/usr/include
  ubuntu-patches:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Compile patches with gcc
        env:
          CC: gcc
        run: |
          sudo apt install libreadline-dev
          make checkpatches
  ubuntu-cppcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Static analysis with cppcheck
        run: |
          sudo apt install cppcheck libreadline-dev
          cppcheck --std="c11" --error-exitcode=1 --enable=performance,portability \
                   --force --inline-suppr --max-ctu-depth=8 -j"$(nproc)" \
                   $(pkg-config --cflags ncurses) src/nnn.c


================================================
FILE: .github/workflows/codeql.yml
================================================
name: "CodeQL"

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]
  schedule:
    - cron: "11 23 * * 3"

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: [ cpp, python ]

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v2
        with:
          languages: ${{ matrix.language }}
          queries: +security-and-quality

      - name: Autobuild
        uses: github/codeql-action/autobuild@v2
        if: ${{ matrix.language == 'cpp' || matrix.language == 'python' }}

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v2
        with:
          category: "/language:${{ matrix.language }}"


================================================
FILE: .github/workflows/lock.yml
================================================
name: 'Lock threads'

on:
  schedule:
    - cron: '0 0 * * *'
  workflow_dispatch:

permissions:
  issues: write
  pull-requests: write
  discussions: write

concurrency:
  group: lock-threads

jobs:
  lock:
    runs-on: ubuntu-latest
    steps:
      - uses: dessant/lock-threads@v5
        with:
          github-token: ${{ github.token }}
          issue-inactive-days: '30'
          issue-lock-reason: ''
          pr-inactive-days: '30'
          pr-lock-reason: ''


================================================
FILE: .gitignore
================================================
*.o
*.dSYM
nnn
src/icons-generated*.h
src/icons-hash-gen


================================================
FILE: CHANGELOG
================================================
nnn v5.2 Blue Hawaii
2026-02-14

- enable 8 contexts (saved sessions may no longer be usable, users need to re-create the sessions)
- massive [du performance improvement](https://github.com/jarun/nnn/wiki/Performance#02-feb-2026)
- floating window
  - render file stats (<kbd>f</kbd>) in a navigable floating window
  - support rendering output of command run as plugin within floating window (prefix `>`)
- support in order fuzzy search
- with no selection, allow user input on _Copy here_ or _Move here_ e.g. to copy the system clipboard
- double confirm when removing more than 10 selected files using `rm`
- auto-complete hovered file name on pressing <kbd>TAB</kbd> at the end of prompt input
- fix: scroll down arrow indicator not showing when down arrow is pressed with filter
- fix: refresh directory after selection edits
- support PCRE2 compile-in (`make O_PCRE2=1`), remove PCRE1 support (no longer being developed)
- support jelliz in preview-tui
- history file for native prompt

-------------------------------------------------------------------------------

nnn v5.1 Moscow Mule
2025-03-23

- add support for custom trash function
- remember history of last 16 commands executed in the native prompt in the current session
- count files from selection file when no file is selected during selection removal
- show session name in help
- show current entry in reversed bold
- show current (non-auto) session name at save session prompt
- show `F` in the status bar when filter is inactive in _type-to-nav_ mode
- restore correct filter function on session load, switch filter function on context changes
- extend xreadline() with some by-word movement
- added plugins gpgs and gpgv
- add icon for `lzip` files, more emoji icons
- suffix the current context number with `*` in help screen

-------------------------------------------------------------------------------

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 <kbd>X</kbd> 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

- config option `NNN_ARCHMNT` to specify archive mounter utility
- key <kbd>^y</kbd> to jump to next young file
- filter adjustment when opening context from plugin
- properly update mode after `chmod`
- pre-fill selected file name to create link if sel is preferred over hovered
- fix crash when `PWD` is empty
- make `quitcd.bash_zsh` POSIX-compliant
- `nmount` - support `udiskctl` as default
- `preview-tui` - support wezterm split size percentage
- `preview-tui` - move to bash for environment manipulation through arrays
- `fzopen` - handle empty selection
- `finder` - use default path to find
- add icons for `djvu` files
- support Nerd Fonts v3.0.0 and above (older versions are broken by v3.0.0)

-------------------------------------------------------------------------------

nnn v4.8 Spritz
2023-04-13

- show total size (key <kbd>S</kbd>) of non-filtered selection in a directory
- fix tilde (~) handling in file name
- plugin `.nmv` now respects `-u` flag
- env var `$NNN_PREFER_SELECTION` exported to all plugins
- support for wezterm in `preview-tui`
- create new file or directory (tree) on startup
- run command as plugin now supports exported variables
- use `"$nnn"` anywhere when running command as plugin
- set defaults for some prompts on <kbd>Enter</kbd>
- improve archive, rename and create new workflows
- optimize link creation
- allow overwriting regular files on new empty file creation
- add patch for colemak keyboard (existing renamed to colemak-dh)
- add correct check for Wayland in clipboard plugins
- add quitcd script for nushell
- plugin `kdeconnect` - send multiple files
- plugin `preview-tui`: add `chafa` as preferred image viewer, multiple fixes
- plugin `nmount` - misc. improvements
- add icon for jxl files

-------------------------------------------------------------------------------

nnn v4.7 Cuba libre
2022-11-24


- fix <kbd>^N</kbd> not working sometimes (#1449)
- fix file remove confirmation prompt
- bring back `atool` as the default archive handler
- add option `-B` to use `bsdtar` as the archive utility
- find and list mode improvements
  ntinue even if max paths/data size limit is exceeded
  eed improvements
  pport listing maximum 16K paths of 64 MiB of data
- key <kbd>J</kbd> to jump to an entry or relative offset from current entry
- prefill the hard link creation prompt when there's a single target (#1507)
- documented workaround for docker container crash (#1407, #1476)
- plugin `imgview`: handle arguments as strings (#1509)
- plugin `wallpaper`: support Wayland (#1512)
- plugin `upload`: handle selection using `ffsend` (#1523)
- add Rust icons (#1502)

-------------------------------------------------------------------------------

nnn v4.6 Absinthe
2022-07-26

- icon handling overhaul (#1432, #1436)
  - better performance, memory usage and reduced binary size
- emoji support for supporting distros and terminals (#1346)
- open the target directory of symlinked bookmarks (#1353)
- enable show hidden when a hidden file is passed as argument
- add Colemak-DH layout keybinds to patch framework (#1421)
- set `bsdtar` as the default archive utility
- support 4 byte unicode keybinds (#1428)
- enable directory auto-enter during filter operation (`-A` to disable)
- enable filter prompt inside the bookmark/plugin dirs
- show volume usage information in help
- add new icon colors for mp4 and flac files
- use `stat -x` for file details on *BSD and macOS (#1389)
- interpret suffix `$nnn` when paging (#1355)
- disable key <kbd>e</kbd> (edit file) in explorer mode (#1394)
- fix double order chars on filter case match change
- `.cbcp`: more verbose message on paste without a selection
- plugin `preview-tui`: scale-up kitty previews
- plugin `preview-tui`: account for ueberzug offset
- plugin `preview-tui`: support `SPLIT_SIZE` for preview pane (#1431)
- plugin `autojump`: support z.lua
- new Makefile target `shellcheck` to verify plugins

-------------------------------------------------------------------------------

nnn v4.5 Cachaça
2022-04-26

- disable filter info if file details (option `-i`) enabled
- open previous active context on context quit
- switch <kbd>^J</kbd> and <kbd>+</kbd> functionality:
  - <kbd>+</kbd>: toggle file selection
  - <kbd>^J</kbd>: toggle auto-jump on file open
- allow symlink creation with name `@` to a single file (#1345)
- clear selection on successful operation at native prompt with "%j" (#1330)
- reverse timestamps of entries modified/created within 5 minutes
- avoid using non-portable `xargs` flags on macOS (#1299)
- quitcd script for Elvish shell > 0.17.0 (#1344)
- plugin `openall` to open selected files together (#1333)
- plugin `gitroot` to jump to git root directory from a subtree
- plugin `gsconnect` to send the selected files to Android using gsconnect
- icon for opus and webp files
- `preview-tui` - fix gif conversion and whitespace name
- `preview-tui` - add support for windows terminal split
- `preview-tui` - djvu file previews
- `nuke` - add support for `imv` when named _imv_
- `gsconnect` - support connection to multiple devices
- export `NNN_INCLUDE_HIDDEN` to plugins (#1308)
- respect `NNN_TRASH` in `.nmv` (#1306)
- add GNU sed as a dependency with support for env var `SED`
- use bold `>` to point at current entry in detail mode
- add 2 spaces after icons for better visibility
- documentation refresh
- make option `O_NOSORT` to load directories unsorted on entry

-------------------------------------------------------------------------------

nnn v4.4 Tequila
2021-11-23

- support macOS iterm2 in plugin preview-tui (#1196)
- use selection at native command prompt with `%j` and `%J`
  - docs - https://github.com/jarun/nnn/wiki/concepts#special-variables
- scroll strings longer than columns in rename/new prompts (#1213, #279)
- batch rename symlink targets in listing mode (#1214)
- option for recursive rename in plugin .nmv (#1186)
- more frequent checks for cancellation during du (#1236)
- picker mode: enable auto-proceed
- picker mode: don't pick hovered file on <kbd>Enter</kbd> if selection exists
- picker mode: fix issue in plugin `fzopen` when used to pick files
- send file to explorer FIFO on double left click instead of opening it
- new neovim plugin [nnn.nvim](https://github.com/luukvbaal/nnn.nvim)
  - nvim-only, featuring explorer mode (`-F` flag)
- explorer mode for [nnn.vim](https://github.com/mcchrish/nnn.vim#explorer)
- remove option `-w`: always place HW cursor on current entry
- accept link name when linking a single target (#1201)
- option `-i` to show current file information in info bar
- force GNU sed on *BSD and Solaris
- add `nsxiv` support to nuke, preview-tabbed and imgview (#1230)
- fix preview-tui without `-a` (#1208)
- pass `pts` in env var for preview-tui to use in `tput` (#1235)
- disable editing file in picker mode (#1183)
- save session in picker mode (#1190)
- use nerd icons for gitstatus patch (#1220)

-------------------------------------------------------------------------------

nnn v4.3 Martini
2021-09-29

- cool ASCII art logo in the help screen
- add `bookmarks` directory for flexible symlinked bookmarks
- new key <kbd>B</kbd> to add a symlinked bookmark for current dir
- special variables `$dN`, `$fN` available for plugins/prompt/shell to access
  dir/hovered file in each context
- config `NNN_ORDER` to set directory-specific ordering
- show/hide hidden files as per context state in plugin based batch rename
- retain search filter history for plugin `finder`
- sync multiple instances of `nnn` after operation on selection
- signal CWD change to terminal via OSC-7 (#1147)
- save complete per-context filter when saving sessions
- disable symlink resolution for paths in `NNN_BMS` and arg `PATH`
- do not end selection mode on running plugins/prompt/shell
- plugin `bookmarks` replaced by symlinked bookmarks support
- list open locations in active contexts in help page
- make option `O_MATCHFLTR` to discard filter key if no match
- configurable `NNN_TMPFILE` to _cd on quit_
- disable auto marking directories (use <kbd>-</kbd>)
- picker mode improvements
  - open tty for input if `STDIN` is non-tty
  - truncate output file before writing
  - do not double select a file on <kbd>Enter</kbd>
- legacy macOS (< 10.12.0) support
- no redraw during du calculation, show processed dir name
- plugin `xdgdefault`: add dmenu support
- user patch `restorepreview`: close/restore `preview-tui` for internal edits

-------------------------------------------------------------------------------

nnn v4.2 Mojito
2021-07-21

- `NNN_PLUG` indicator symbol interpretation has **changed**:
  - `!` - _run-cmd-as-plugin_ (earlier `_`)
  - `&` - _run-gui-cmd-as-plugin_ (earlier `|`)
  - `|` (new) - page noninteractive _run-cmd-as-plugin_ output
- persistent selection markers (#1086)
- option _extract to..._ for archives
- mount remote and mount/extract archive to a smart context
- confirm file trashing to avoid accidental press of <kbd>x</kbd> (#1101)
- insert the last command executed at prompt on <kbd>Up</kbd> or <kbd>Down</kbd>
- insert the current file name at empty prompt on <kbd>TAB</kbd>
- handle redraw issue on missed `KEY_RESIZE` (#1067)
- add force-tty capability to spawn and set pagers to it (#1064)
- clear selection mode on deselecting last selected file (#1098)
- remove selected hovered entry from selection on deletion
- disable filtering in empty directories
- ignore last pressed filter character when no matches
- fix broken screen on resize while paging (#1072)
- fix archive not hovered on creation
- remove libgit2 dependency in `gitstatus` patch (#1095)
- add `-G` flag for `gitstatus` patch
- option `-X` for explorer (persistent picker) mode
- option `-F` decommissioned in favour of config `NNN_HELP`
- `-F` redefined to multiplex `NNN_FIFO` to preview or explore
- support paging noninterative _run-cmd-as-plugin_ output
- `nuke` - add option to execute binaries (#1111)
- plugin `fzopen` - call `open` on macOS, add option to use `nuke`
- plugin `fzcd` will not modify selection
- plugin `suedit` - preserve environment
- several `preview-tui` fixes
- plugin `wall` renamed to `wallpaper`
- remove plugin `fzz` - merged into plugin `autojump`
- remove plugin `upgrade` - packaging is on OBS now
- remove plugin `treeview` - needs minor `preview-tui` tweak
- remove plugin `picker` - `nnn -p -` does the same
- remove plugin `pdfview` - needs simple change in `pdfread`
- remove plugin `uidgid` - use program option `-U`
- remove plugins `mediainf`, `hexview` - simple one-liners

-------------------------------------------------------------------------------

nnn v4.1.1 Sake
2021-06-03

- fix segfault on session save (#1041)
- remove redundant `_Atomic` usage
- move [`patches`](../tree/master/patches) directory to top-level
- fix and cleanup gitstatus patch
- plugin `imgview` improvements (#1049)
- restore source-code packing on CircleCI
- add Makefile target to compile with musl

-------------------------------------------------------------------------------

nnn v4.1
2021-06-02

- a patch management model for approved patches
- multi-threaded disk usage calculation using pthreads and FTS
- dynamic view update when calculating disk usage
- <kbd>Bksp</kbd>/<kbd>Del</kbd> at empty filter prompt to refresh dir
- Try to create new context with <kbd>Shift-TAB</kbd>, else reverse cycle
- <kbd>Alt+Esc</kbd> to quit context from filter prompt
- fix zombies left behind after running plugins (#999)
- named persistent sessions (mcchrish/nnn.vim#43)
- consider nanosecond resolution when sorting by time (#978)
- check external selection in `'c'urrent / 's'el` prompt (#976)
- show number of files selected in local selection buffer, if any
- `nnn` & picker plugin (e.g. `fzopen`) sync (mcchrish/nnn.vim#82)
- make batch rename interactive (#971)
- cached uid/gid for performance improvement
- fixes for `nnn` with `netbsd-curses`, `musl-fts`, `musl` (#998)
- script to statically compile `nnn` with `musl gcc` on Ubuntu
- restore hovered file when plugin is chosen from plugin dir
- support QuickLook on WSL in `preview-tui` (#959)
- toggle `preview-tui` with the same _custom_ plugin key
- smoother preview toggling in `preview-tui` (#966)
- `listen_on` should be set in kitty.conf for `preview-tui` (#970)
- minimal `bat` style in `preview-tui`, honors `$BAT_STYLE`
- plugin `preview-tui-ext` supersedes `preview-tui` (#1033)
- plugin `fzcd` can now fuzzy search multiple directories
- plugin `imgview` supersedes `imgthumb` and `vidthumb`
- plugin `umounttree`: unmount remote mntpoint from within
- plugin `xdgdefault`: set the default app for hovered file type
- plugin `fzplug`: fuzzy find, preview and run other plugins
- plugin `cmusq`: queue/play music in `cmus`
- plugin `mocplay` renamed to `mocq`
- plugin `cleanfilename` renamed to `fixname`
- go to last dir on <kbd>~</kbd> (HOME) or <kbd>`</kbd> (ROOT) key repeat
- ambiguous key <kbd>^Space</kbd> to select/clear range dropped (#998)
- user wiki page for [Themes](https://github.com/jarun/nnn/wiki/Themes)
- show selection mark (`+`) in reverse bold for improved visibility
- reverse block replaces `>` to mark hovered entry in detail mode
- make option `O_CKBOARD` removed
- make option `O_NOLOC` renamed to `O_NOLC`
- ignore `O_NOLC` if `O_ICONS` or `O_NERD` is specified (#1026)
- unicode arrow indicators if `O_ICONS` or `O_NERD` is specified
- make option `NOX11`: disable notis, sel-clipboard sync, xterm title
- retain filter in _nav-to-type_ mode after file open
- fix no files picked with `NNN_TMPFILE` exported and <kbd>q</kbd> to quit
- disable xterm title setting in picker mode (#974)

-------------------------------------------------------------------------------

nnn v4.0 Sushi
2021-04-13

- show xterm title on option `-x`

-------------------------------------------------------------------------------

nnn v3.7
2021-04-13

- allow plugins to clear selection (#884, #889, #917)
- do not clear selection on hovered file deletion
- resurrect `'c'urrent/'s'el` prompt and option `-u` (#889)
- show only file name in reverse in detail mode
- more file/mime types supported in `preview-tui-ext`
- plugin `mtpmount` - (un)mount MTP devices
- plugin `cleanfilename` - more shell-friendly file names
- plugin `rsynccp` - copy-paste with visual progress
- replace `$HOME` by `~` in address bar
- show current path in terminal title (#911)
- total links and inode number of hardlink in statusbar
- fix symlink to text file not opening in CLI editor (#890)
- fix symlink size shown as 0B in statusbar (#888)
- show symlink target in statusbar (#893)
- show correct disk free/total on macOS (#888)
- fix directory disk usage showing as 0 on macOS (#941)
- fix name col len with `-C` and icons compiled-in (#936)
- refactor printing entries in light/detail modes (#934)
- make option `O_CKBOARD` for checker board as indicator

-------------------------------------------------------------------------------

nnn v3.6 Nina
2021-03-16

- REPL command prompt (<kbd>Esc</kbd> or <kbd>Enter</kbd> to exit)
- invert selection with <kbd>A</kbd>
- option `-u` removed (always prefer selection to hovered)
- visit start dir on <kbd>@</kbd> when start path is a file
- exit filter mode and redraw on <kbd>^L</kbd> if no last filter
- plugin `fzcd` now selects the chosen file (#876)
- `ueberzug` support in plugin `preview-tui`
- new plugin `preview-tui-ext` with extra preview support
- clear selection after successful plugin invocation
- add method to sync subshell `$PWD` in WIki
- clear selection on single file deletion (#812)
- copy between instances not working (#864)
- plugin `togglex` to toggle exe mode of a selection (#813)
- fix `memccpy()` buffer overlap fault on macOS (#786)
- show `0 selected` msg on cp/mv with empty selection (#855)
- fix frozen terminal caused by opener (#858)
- migrate macOS CI to GitHub workflows, retire Travis

-------------------------------------------------------------------------------

nnn v3.5 Freddie
2020-11-17

- compile-in Alexey Tourbin's QSORT macro
- support Nerd Font patched icons [`make O_NERD=1`]
- auto-generate static binaries with icons support
- audit and adapt all plugins for macOS
- enhance plugin `dups` to delete duplicates interactively
- plugin `autojump` now supports `jump` and `zoxide`
- support `gio trash` to Trash [`export NNN_TRASH=2`] (#740)
- quit program on double <kbd>Esc</kbd> in normal mode (#775)
- <kbd>^Space</kbd> replaces <kbd>^K</kbd> for range selection/clear selection
- show selection symbol (`+`) next to filename in detail mode (#741)
- error & quit on <kbd>Q</kbd> if no selection, else pick to stdout
- repeat <kbd>^T</kbd> to cycle sort by time, size and clear
- option `-U` to show user & group info in status bar
- option `-J` to disable auto-proceed on select (#713)
- option `-D` to show dirs in context color with `NNN_FCOLORS`
- honor option `-C` for context colors
- show indicators if more entries above/below listing (#744)
- show missing utility name in flash msg (#753)
- exit `preview-tabbed` on <kbd>^C</kbd> (#727)
- invoke GNU sed (_gsed_) on macOS (#728)
- fix HW cursor moves to wrong line (#735)
- fix rollover bug with multiline scroll (#743)
- fix input stream not listed with `-s`/`-S` (#777)
- fix locker not being invoked
- make target `upx` for additional binary compression
- compress auto-generated static binaries with upx
- make variable `O_NOSSN` to compile out sessions
- make variable `O_NOUG` to compile out user & group info

-------------------------------------------------------------------------------

nnn v3.4 Emilia
2020-08-18

- icons with icon-specific colors (thanks @KlzXS)
- enhanced `NNN_COLORS` with xterm 256 colors support
- new colorscheme with `NNN_FCOLORS` (file type specific colors)
- switch `-C` to force earlier colorscheme (dirs follow context color)
- updates for Haiku (thanks @CodeforEvolution)
- fix XFS navigation issue (thanks @ucs1)
- optimize archive extension matching on file open
- show location in context color
- support `host[:dir]` format for remote mounts
- clear selection after copy
- support traversal on file/dir creation
- show selection in reverse in status bar
- show status bar indicator `H` when hidden files are listed
- show and confirm archive command output
- support _cd on quit_ in picker mode

-------------------------------------------------------------------------------

nnn v3.3
2020-07-14

- subdir `mounts` for remote and archive mounts
- remove mount point on successful unmount of remote/archive
- show error and prompt user if `cp`/`mv`/`rm` operation fails
- support absolute/relative paths in cp/mv as
- mark current path automatically on archive/remote mount
- mark current path automatically on target file visit in _find and list_ mode
- option `-C` to place HW cursor on hovered for screen readers and braille displays
- option `-u` to use selection (if available) and skip `current/sel` prompt
- key <kbd>Alt+Esc</kbd> to clear filter prompt and redraw
- support <kbd>Esc</kbd> to cancel remove operation
- `gpge` & `gpgd`: encrypt and decrypt with GPG
- `blknew`: create new files and directories in bulk
- `preview-tui`
  - unified to support `tmux`/`kitty`/`xterm`/`$TERMINAL`
  - auto-determine split orientation based on terminal height and width
  - provision to use [`scope.sh`](https://github.com/ranger/ranger/blob/master/ranger/data/scope.sh) and [`pistol`](https://github.com/doronbehar/pistol)
- various other improvements
- `upload`: send to Firefox Send if [`ffsend`](https://github.com/timvisee/ffsend) is found
- `hexview`: add [`hx`](https://github.com/krpors/hx) as alternative hex viewer
- `nuke` and `imgview`: add [`imv`](https://github.com/eXeC64/imv) as alternative image viewer
- add find (with `fd`) and grep (with `rg`) examples in plugins doc
- key <kbd>Esc</kbd> or left click to resend hovered file path to `NNN_FIFO`
- show `+` instead of `s` in status bar on selection
- <kbd>F5</kbd> removed (misfit for toggle hidden), <kbd>^S</kbd> removed (often masked, redundant)
- handle abnormal program termination and remove NNN_PIPE and/or NNN_FIFO
- clear selection after successful batch rename, link creation
- make option `O_CTX8` for 8 contexts (NOT backward compatible with 4 contexts)
- fix issue with child window resize (see #656)
- fix issue with `NNNLVL` on macOS (see #639)
- fix issue with restoring session with du/au enabled

-------------------------------------------------------------------------------

nnn v3.2
2020-05-26

- an official logo
- previews
  - config `NNN_FIFO` to write hovered file paths a previewer can read
  - plugin `preview-tabbed`: [tabbed](https://tools.suckless.org/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](https://github.com/jarun/nnn/wiki/Live-previews) 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`
  - <kbd>Right</kbd> or <kbd>l</kbd> 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 <kbd>'</kbd> (followed by <kbd>'</kbd> or <kbd>char</kbd>)
- 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](https://github.com/jarun/nnn/wiki/Usage#graphical-map)
- let `NNN_COLORS` override `NO_COLOR`
- plugins
  - option `-P`: run plugin by key at start
  - run plugins with <kbd>Alt+key</kbd>
  - 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`

-------------------------------------------------------------------------------

nnn v3.1
2020-04-13

- unlimited bookmarks and plugin keys
- status bar text in context color
- support config `NO_COLOR` to disable colors
- config `NNN_OPTS` to specify binary options to `nnn`
- config `NNN_MCLICK` to emulate configurable key
- toggle selection on right click
- ignore hard links when calculating disk usage
- dim (hard/sym) link names (symlink to file has `@`)
- more special keys at empty filter prompt in _type-to-nav_
- key <kbd>></kbd> to export file list
- option `-F` to show fortune in help and settings screen
- option `-T` to specify sort order (obsoletes `-v`)
- option to clear sort order
- key <kbd>T</kbd> to change time type (access/change/mod)
- `.nmv` - internal fully-functional batch renamer plugin
- make var `O_NOBATCH` to disable native batch renamer
- `nuke` & `imgview` - open all images in directory sxiv
- `nuke` - open log files in vi
- plugin `x2sel` - system clipboard to selection copier
- plugin `fzy` - cd using z database
- plugin `fzopen` - support `FZF_DEFAULT_COMMAND`
- create new context on TAB without prompt
- hover and connect by dir name (within config dir)
- move to next entry on current file delete
- on single file copy/move, select the copied/moved file
- option `-f` to use readline history file (off by default)
- use `s` in status bar to indicate selection in progress
- make var `O_NOMOUSE` to disable mouse support
- do not store `NNN_TRASH` and `-Q` in config/session
- add sample .desktop file for XDG compatible DEs
- rename _nav-as-you-type_ to _type-to-nav_ mode
- fix PCRE case-insensitive regex search
- fix no error msg when filter length limit exceeded
- fix static package generation
- fix broken abort message when started in du-mode
- fix filter lost on context switch in non _type-to-nav_ mode
- fix broken readline prompt
- fix long strings treated as action keys in filter prompt
- fix `NNNLVL` not reset when spawned shell is exited

-------------------------------------------------------------------------------

nnn v3.0
2020-02-12

- take list of files as input and show
- option `-e` replaces `NNN_USE_EDITOR`
- option `-t` replaces `NNN_IDLE_TIMEOUT`
- PCRE support
- more readline bindings for native prompts
- run GUI app as plugin
- attempt lazy unmount when regular unmount fails
- fix unmount on macOS: use `umount`
- detect `sshfs` and `rclone` to prompt intelligently
- auto-proceed on file open (toggle key <kbd>+</kbd>)
- quit with error code on <kbd>Q</kbd>
- additional key <kbd>F5</kbd> to toggle hidden
- key <kbd>e</kbd> to edit in EDITOR (back on multiple user requests)
- option to edit list of files in selection is changed to <kbd>E</kbd>
- do not end selection on redraw
- `nuke`: [`glow`](https://github.com/charmbracelet/glow) as Markdown viewer
- `nuke`: refactor, handle some common video types by extension
- file name removed from status bar
- static Makefile target
- generate, upload static package on release
- fix crash on entering empty dir, then Down
- fix keypresses lost when showing message
- fix #227: `nnn` creates xdg-open zombies

-------------------------------------------------------------------------------

nnn v2.9
2020-01-15

- all keybinds and options reviewed by the team and frozen (see #422)
  - reduced number of keybinds
- greatly improved help screen readability
- `nuke`: sample opener (CLI-only by default) and plugin
- fast line redraws instead of full screen refresh (thanks @annagrram)
- auto archive handling by extension (see config `NNN_ARCHIVE`)
- Lead key simplified to bookmark key (<kbd>b</kbd> or <kbd>^/</kbd>)
- single key to toggle order (<kbd>t</kbd> or <kbd>^T</kbd>)
- plugins
  - `.cbcp`: copy selection to system clipboard (internal, program option `-x`)
  - `.ntfy`: show noti on cp, mv, rm completion (internal, program option `-x`)
  - `autojump`: navigate using autojump
  - `upload`: paste text files to http://ix.io, upload rest to https://file.io
  - all fuzzy plugins modified to support both `fzf` and `fzy`
- more control on plugins
  - prefix `-` to skip directory refresh after running (cmd as) plugin
  - suffix `*` to skip confirmation after running cmd as plugin
- indicate range selection mode with `*`
- list keys at bookmark and plugin key prompts
- visit to pinned dir like bookmarks (Bookmark key followed by <kbd>,</kbd>)
- toggle executable (key <kbd>*</kbd>)
- show mime along with file details
- more special keys at empty filter prompt:
  - apply the last filter (<kbd>^L</kbd>)
  - toggle between string and regex (<kbd>/</kbd>)
  - toggle case-sensitivity (<kbd>:</kbd>)
- retain filter on <kbd>Esc</kbd>, <kbd>Up</kbd>, <kbd>Down</kbd>
- show filter details when filter is on
- remove option to run filter as cmd on prompt key (can be disruptive)
- program options
  - option `-x`: enable notis and copy selection to system clipboard
  - option `-g`: regex filters (string filter is default now)
  - option `-Q`: quit program without confirmation
  - option `-s`: load session
  - option `-n`: start in nav-as-you-type mode
  - option `-v`: version sort
  - option `-V`: show program version
  - option `-A`: disable dir auto-select
- ISO 8601 compliant date in status bar
- ported to Haiku OS (thanks @annagrram)
- sort only filtered entries (to avoid directory refresh)
- fix `getplugs` to install hidden files
- fix several selection issues (see #400)
- fix detail mode not restored on loading session
- fix symlink to directory not auto-selected
- fix regex error on partial regex patterns
- fix symlink not shown if `stat(2)` on target fails
- fix flags when spawning a CLI opener as default FM
- fix issue with stat flag on Sun (no support for `dirent.d_type`)
- fix current file in current context not saved correctly in session
- signed source distribution on release
- simplified debugging with line numbers in logs

-------------------------------------------------------------------------------

nnn v2.8.1
2019-12-05

- Fix always archiving current file
- More elaborate docs on selection changes

-------------------------------------------------------------------------------

nnn v2.8
2019-12-04

- sessions (thanks @annagrram)
- `rclone` support for remote access (mount _any_ cloud storage!!!)
- toggle selection with <kbd>Space</kbd> or <kbd>^J</kbd>
- ignore events during selection so the `+` symbol is not lost
- run custom (non-shell-interpreted) commands like plugins
- configure _cd-on-quit_ as the default behaviour
- create parent dirs for new files and dirs, duplicate a file/dir anywhere
- _copy/move as_ workflow (thanks @KlzXS)
- edit , flush selection buffer (thanks @KlzXS)
- support xargs with minimal options (as in BusyBox) (thanks @KlzXS)
- changed the key to size sort to <kbd>z</kbd>
- additional key <kbd>]</kbd> to show command prompt
- mount archives using `archivemount`
- smoother double click handling
- program option `-R` to disable rollover at edges
- keybind collision checker (for custom keybind config) (thanks @annagrram)
- show size of file in bytes in status bar in disk usage mode
- pass unresolved path as second argument (`$2`) to plugin
- mechanism for plugins to control active directory
- all binary questions are confirmed by <kbd>y</kbd> or <kbd>Y</kbd>
- plugins
  - some plugins renamed
  - integrated `shellcheck` in CI, POSIX-compliance fixes (thanks @koalaman)
  - `getplugs` - detect modifications in exiting plugin file (thanks @KlzXS)
  - `drag-file` & `drop-file`: drag & drop files using dragon
  - `gutenread`: browse, download and read from Project Gutenberg
  - `suedit` - edit file with superuser permissions
  - `fzhist` - fuzzy select commands from history, edit and run
  - `fzcd` - change to a fuzzy-searched directory
  - `rename` - batch rename directory or selection using qmv or vidir
  - `pskill` - fuzzy list a process or zombies by name and kill
  - `exetoggle` - toggle executable status of hovered file
  - `treeview` - informative tree output with file permissions and size
  - `chksum` - recursively calculate checksum for files in hovered directory
  - `fzopen` renamed to `fzopen`
  - `imgsxiv` instructions added to browse and rename images
- create link to current file
- additional key <kbd>;</kbd> to execute plugin
- more explicit force removal message
- force non-detachable internal edits in $EDITOR (option `-E`)
- export current file as `$nnn` (instead of `$NN`)
- fix file open failure from browser when configured as default FM

-------------------------------------------------------------------------------

nnn v2.7
2019-10-06

- plugins for image preview, image and video thumbnails
- redesigned selection workflow
- drop path prefix for files in current dir for selection based archives
- custom direct keybinds for plugins
- libreadline `.history` file moved to `nnn` config directory
- export current entry as `$NN` at command prompt
- more informative status bar in light/detail modes
- auto-proceed to next file on single file select
- path clipping for long paths
- completely revamped wiki
- new program options:
  - `-a` to use file access time throughout the program
  - `-c` to indicate cli-only opener
  - `-f` to run filter as command on <kbd>^P</kbd>
  - `-o` replaces config `NNN_RESTRICT_NAV_OPEN`
  - `-t` replaces config `NNN_NO_AUTOSELECT`
  - `-r` replaces config `NNN_OPS_PROG`
- plugin changes:
  - `vidthumb` - show video thumbnails in terminal
  - `mediainf` - show media info (decoupled as a plugin)
  - `notes` - open a quick notes file/dir in `$EDITOR` (decoupled as a plugin)
  - `dups` - list duplicate files in the current directory
  - `oldbigfile` - list large files by access time
  - `moclyrics` - show lyrics of the track currently playing in MOC
  - `uidgid` list uid and gid of files in directory
  - `mocplay` - now detects if a track is playing or not
  - `organize` - categorize files and move to respective directories
  - `pastebin` - now uses ix.io paste service
  - `fzy-edit` - merged into `fzy-open`
  - `viuimg` - fix directory view
  - `checksum` - fixed POSIX compliance issues
  - `boom` - play music in MOC
- keybind changes:
  - select entry: <kbd>Space</kbd> and <kbd>^J</kbd>
  - select range (or clear selection): <kbd>m</kbd> and <kbd>^K</kbd>
  - select all in dir: <kbd>a</kbd>
  - list selection: <kbd>M</kbd>
  - <kbd>^N</kbd> replaces <kbd>^T</kbd> to toggle _nav-as-you-type_
  - <kbd>Shift TAB</kbd> to reverse context cycle
  - <kbd>'</kbd> to jump to first file in dir
  - <kbd>S</kbd> for du, <kbd>A</kbd> for apparent du
  - additional key <kbd>:</kbd> to run plugin
  - additional key <kbd>F2</kbd> to rename file
  - additional key <kbd>F5</kbd> to redraw
  - quit context key <kbd>Leadq</kbd> is removed
- Leader key combinations:
  - <kbd>Lead'</kbd> to jump to first file in dir
  - <kbd>Lead]</kbd> go to next active context
  - <kbd>Lead[</kbd> go to prev active context
  - <kbd>Lead.</kbd> toggle show hidden files
- improved duplicate file workflow
- improved batch rename workflow when a selection exists
- removed the wild load option (`-w`)
- removed quick notes (added plugin `notes`)
- fix #225 (thanks @KlzXS)
- fix `tar`/`bsdtar` always creating tar archives (and not by suffix)
- fix single mouse click to select file not working
- fix symlink to dir removed on batch rename
- fix detail mode not set with program option `-S`

-------------------------------------------------------------------------------

nnn v2.6
2019-08-06

- new plugins
   - view image or browse a directory of images in terminal
   - show image thumbnails
   - PDF and text file reader
   - calculate and verify checksum of selection or file
   - append (and play) selection/dir/file music in MOC
   - variable bitrate mp3 ringtone generator
   - split current file or join selection
- better experience on Termux (and touch based devices)
   - mouse scrolling support (with ncursesw6.0 and above)
   - tap/left click to visit parent, toggle nav-as-you-type mode
- light mode set as default
- show status bar and use reverse video in light mode
- changed program options
  - `-d`: detail mode
  - `-H`: show hidden files
  - `-l` is retired
- support `XDG_CONFIG_HOME`
- support <kbd>/</kbd> as an additional Leader key when filter is on
- sort by file extension
- use zip/unzip/tar if atool/bsdtar not found
- support duplicate file (key <kbd>^R</kbd>, same as rename file)
- new config option `NNN_SSHFS_OPTS` to specify `sshfs` options
- restrict opening 0 byte files (`NNN_RESTRICT_0B` is obsolete)
- critical defects fixed
   - fix #276 - crash with variable length inotify event handling
   - fix #285 - hang after deleting/moving current directory
   - fix #274 - a broken prompt on empty input with libreadline
   - fix #304 - list selection from another instance
- `cmatrix` as locker fallback
- wait for user input after running a command from prompt
- scrolloff set to 3 from 5

-------------------------------------------------------------------------------

nnn v2.5
2019-05-27

- mouse support
- new location for config files - `~/.config/nnn`
  - plugin dir location: `~/.config/nnn/plugins`
  - selection file `.nnncp` is now `~/.config/nnn/.selection`
- plugins:
  - pdfview: view a PDF in pager
  - nmount: (un)mount a storage device
  - ndiff: file and directory diff for selection
  - hexview: view a file in hex
  - imgresize: batch resize images to desktop resolution
  - ipinfo: check your IP address and whois information
  - transfer: upload a file to transfer.in
  - pastebin: paste the contents of a text file to paste.ubuntu.com
  - boom: play random music from a directory
  - nwal: set an image as wallpaper using nitrogen
  - pywal: set selected image as wallpaper, change terminal color scheme
  - getplugs: update plugins
- SSHFS support
- support `bsdtar`, simplify `patool` integration
- native batch rename support (`vidir` dependency dropped)
- changes to support [configuration](https://github.com/jarun/nnn/wiki/nnn-as-default-file-manager) as the default file manager
- per-context detail/light mode
- case-insensitive version compare
- shortcut to visit `/` - <kbd>`</kbd> (backtick)
- vim-like scrolloff support
- <kbd>^D</kbd> & <kbd>^U</kbd>: scroll half page, <kbd>PgDn</kbd> & <kbd>PdUp</kbd>: scroll full page
- fix selection across contexts
- recognize <kbd>Home</kbd> and <kbd>End</kbd> keys at prompt for editing
- fix broken program option `-b`
- POSIX-compliant user-scripts (wherever possible)
- `NNN_SCRIPT` is retired (replaced by plugins)

-------------------------------------------------------------------------------

nnn v2.4
2019-03-19

- FreeDesktop.org compliant trashing
- mark selected entries with `+`
- _wild_ mode (option `-w`, key <kbd>^W</kbd>) for _nav-as-you-type_
- POSIX-compliant GUI app launcher with drop-down menu (key <kbd>=</kbd>)
- new scripts:
  - upload image to imgur
  - send selection to Android using kdeconnect-cli
- show permissions in detail mode
- cp, mv progress bar for Linux (needs advcpmv) [BSD, macOS shows on <kbd>^T</kbd>]
- make libreadline an optional dep (reduces memory usage)
- minimize the number of redraws
- handle screen resize gracefully
- option `-d` to show hidden files (`NNN_SHOW_HIDDEN` is removed)
- additional key <kbd>K</kbd> to toggle selection
- change visit start dir key to <kbd>@</kbd>
- option `-C` to disable colors removed
- per-context initial directory replaced by program start dir
- marker msg when spawning new shell removed
- rename debug file to `nnndbg`

-------------------------------------------------------------------------------

nnn v2.3
2019-02-19

- file picker mode
- repo of user-contributed scripts
- substring search for filters (option `-s`)
- version sort (option `-n`)
- disk usage calculation abort with <kbd>^C</kbd>
- create sym/hard link(s) to files in selection
- archiving of selection
- show dir symlinks along with dirs in top
- fixed CJK character handling at prompts
- key `N` (1 <= N <= 4) to switch to context N
- bring back `NNN_OPENER` to specify file opener
- env var `NNN_NOTE` and keybind <kbd>^N</kbd> for quick notes
- handle multiple arguments in VISUAL/EDITOR
- show the current directory being scanned in `du` mode
- select all files (<kbd>Y</kbd>)
- show command prompt (<kbd>^P</kbd>)
- key <kbd>,</kbd> replaces <kbd>`</kbd> as alternative Leader Key
- keybind for visit pinned directory is now <kbd>^B</kbd>
- additional key <kbd>^V</kbd> to run or select custom script
- use libreadline for command prompt
- reduce delay on <kbd>Esc</kbd> press
- config option to avoid unexpected behaviour on 0-byte file open (see #187)
- rename config option `DISABLE_FILE_OPEN_ON_NAV` to `NNN_RESTRICT_NAV_OPEN`
- keys removed - <kbd>$</kbd>, <kbd>^</kbd>, <kbd>Backspace</kbd>, <kbd>^H</kbd>, <kbd>^P</kbd>, <kbd>^M</kbd>, <kbd>^W</kbd>, <kbd>`</kbd>

-------------------------------------------------------------------------------

nnn v2.2
2019-01-01

What's in?
- (neo)vim plugin [nnn.vim](https://github.com/mcchrish/nnn.vim)
- macOS fixes
  - Fix issues with file copy, move, remove
  - Handle <kbd>Del</kbd> in rename prompt
  - Pass correct `file` option to identify mime
- Support selection across directories and contexts
- Offer option `force` before file remove
- Keys <kbd>Tab</kbd>, <kbd>^I</kbd> to go to next active context
- Per-context directory color specified by `$NNN_CONTEXT_COLORS`
  - Option `-c` is removed
- Option `-C` to disable colors
- Choose script to run from a script directory
- Run a command (or launch an application)
- Run file as executable (key <kbd>C</kbd>)
- Documentation on lftp integration for remote file transfers
- Support a _combined_ set of arguments to `$EDITOR`, `$PAGER` and `$SHELL`
- Handle > 2 GB files on 32-bit ARM
- Env var `$DISABLE_FILE_OPEN_ON_NAV` to disable file open on <kbd>Right</kbd> or <kbd>l</kbd>
- `NUL`-terminated file paths in selection list instead of `LF`
- Better support for Termux and Cygwin environments
- Remapped keys
  - <kbd>^I</kbd> - go to next active context
  - <kbd>^T</kbd> - toggle _navigate-as-you-type_

-------------------------------------------------------------------------------

nnn v2.1
2018-11-23

What's in?
- Inclusion in several distros including Arch Linux official repo
- Multiple contexts (_aka_ tabs _aka_ workspaces) [max 4]
- Copy, move, remove selected files, remove current file
- [Leader key](https://github.com/jarun/nnn#leader-key) (like vim)
- In-built  GUI app launcher with up to 2 arguments (key <kbd>o</kbd>)
- List copy selection (key <kbd>y</kbd>)
- Env var `NNN_NO_AUTOSELECT` to disable dir auto-select
- Key <kbd>Esc</kbd> exits prompt, <kbd>^L</kbd> clears prompt
- Program runtime help revamped
- Static code analysis integration
- gcc-8 warnings fixed
- Remapped keys:
  - <kbd>^W</kbd> - go to pinned dir
  - <kbd>^X</kbd> - delete current entry
  - <kbd>^Q</kbd> - quit program
- `nlay` is retired (functionality built into `nnn`)
- `chdir` prompt is retired
- Env var `NNN_NO_X` retired, selection now works out of the box
- Only single-char bookmark keys (to work with Leader key)

-------------------------------------------------------------------------------

nnn v2.0
2018-10-19

What's in?
- Mode to show apparent size (key `S`)
- Script to integrate `patool` instead of `atool`
- Support `bashlock` (OS X) and `lock` (BSD) as terminal locker
- Symbol `@/` for symlink to dir
- Dependency on `libreadline` removed

-------------------------------------------------------------------------------

nnn v1.9
2018-08-10

What's in?
- Support unlimited number of scripts
- Pass currently selected filename as first argument to custom scripts
- Support directory auto-select in _navigate-as-you-type_ mode
- Show selection name in archive name prompt
- Support Cygwin opener
- Better support on RHEL 25 with earlier version on curses
- Sample script for `fzy` integration
- Now available on OpenBSD
- Disabled package generation for Ubuntu 17.10

-------------------------------------------------------------------------------

nnn v1.8
2018-05-02

What's in?
- Run a custom script
- Archive selected file/directory
- Show number of cherry-picked files in multi-copy mode
- Env var `NNN_SHOW_HIDDEN` to show hidden files by default
- Additional information in help screen
- Give preference to env var VISUAL, if defined, over EDITOR
- New/changed/remapped shortcuts
  - <kbd>^]</kbd> - spawn a new shell in current directory
  - <kbd>r</kbd> - edit directory entries in vidir
  - <kbd>R</kbd> - run a custom script
  - <kbd>^I</kbd> - toggle navigate-as-you-type mode
  - <kbd>L</kbd> - lock the current terminal (Linux-only)
- All Ctrl shortcuts enabled in navigate-as-you-type mode
- Fix: GUI programs closing when parent terminal is closed
- Recognize `~`, `-` and `&` at bookmark prompt
- Recognize ruby (.rb) files as text files
- Efficient integer-only file size calculation
- Official inclusion on openSUSE and Fedora
- Package generation for Ubuntu 18.04

-------------------------------------------------------------------------------

nnn v1.7
2018-02-28

What's in?
- Batch rename/move/delete files in vidir from [moreutils](https://joeyh.name/code/moreutils/)
- Copy multiple file paths
- Copy file paths when X is unavailable
- Optionally quote individual file paths with single quotes on copy
- Use ISO 8601 date format in file details
- New/changed/remapped shortcuts:
  - <kbd>^B</kbd> - show bookmark prompt (replaces <kbd>b</kbd>)
  - <kbd>b</kbd> - pin current dir (replaces <kbd>^B</kbd>)
  - <kbd>^J</kbd> - toggle du mode
  - <kbd>R</kbd> - batch rename files in vidir
  - <kbd>^F</kbd> - extract archive (replaces <kbd>^X</kbd>)
  - <kbd>^G</kbd> - quit nnn and change dir
  - <kbd>^X</kbd> - quit nnn (replaces <kbd>^Q</kbd>)
- Extra shortcuts enabled in nav-as-you-type mode:
  - <kbd>^K</kbd>, <kbd>^Y</kbd> (file path copy)
  - <kbd>^T</kbd> (toggles quoted file path copy)
  - <kbd>^R</kbd> (rename)
  - <kbd>^O</kbd> (open with...)
  - <kbd>^B</kbd> (show bookmark prompt)
  - <kbd>^V</kbd> (visit pinned dir)
  - <kbd>^J</kbd> (toggle du mode)
  - <kbd>^/</kbd> (open desktop opener)
  - <kbd>^F</kbd> (extract archive)
  - <kbd>^L</kbd> (refresh)
  - <kbd>^G</kbd> (quit nnn and change dir)
  - <kbd>^X</kbd> (quit nnn)

-------------------------------------------------------------------------------

nnn v1.6
2017-12-25

What's in?
- Shortcut `^O` to open file with custom application
- Option `-b` to open bookmarks directly at start
- Huge performance improvements around file name storing and handling
- Several large static buffers removed or reduced
- Several internal algorithms fine tuned for performance/resource usage

-------------------------------------------------------------------------------

nnn v1.5
2017-10-05

What's in?
- File and directory creation (`n`)
- Env variable `NNN_NOWAIT` to unblock nnn when opening files (DE-specific)
- Show current entry number in status bar
- Support archive listing (`F`) and extraction (`Ctrl-X`) [using `atool`]
- Show correct file size on i386 for large files (> 2GB)

-------------------------------------------------------------------------------

nnn v1.4
2017-09-04

What's in?
- Monitor directory changes
- In-place file rename
- Pin (`Ctrl-B`) a directory and visit (`Ctrl-V`) it anytime
- Auto-completion scripts
- Show volume capacity and free in help
- Auto-fallback to light mode if too few columns (< 35)
- PackageCore integration
- Unsupported Function keys (they never work universally):
  - `F2` (rename), use `Ctrl-R`
  - `F5` (refresh), use `Ctrl-L`

-------------------------------------------------------------------------------

nnn v1.3
2017-07-26

What's in?
- Show directories in custom color (default: enabled in blue)
- Option `-e` to use exiftool instead of mediainfo
- Fixed #34: nftw(3) broken with too many open descriptors
- More concise help screen

-------------------------------------------------------------------------------

nnn v1.2
2017-06-29

What's in?
- Use the desktop opener (xdg-open on Linux, open(1) on OS X) to open files
- Option `NNN_USE_EDITOR` to open text files in EDITOR (fallback vi)
- Bookmark support (maximum 10, key `b`)
- *Navigate-as-you-type* mode (key `Insert` or option `-i`)
- Subtree search: gnome-search-tool, fallback catfish (key `^/`) (customizable)
- Show current directory content size and file count in disk usage mode
- Add detail view mode as default, use `-l` to start in light mode
- Shortcuts `F2` and `^L` to refresh and unfilter
  Note: if filter is empty, `Enter` *opens* the currently selected file now
- Help screen shows bookmarks and configuration
- Show a message when calculating disk usage
- Show the spawned shell level
- Linux only: use vlock as the locker on timeout (set using `NNN_IDLE_TIMEOUT`)

-------------------------------------------------------------------------------

nnn v1.1
2017-05-12

News
- Introducing nlay - a highly customizable bash script to handle media type
- nnn is on [Homebrew](http://braumeister.org/formula/nnn) now
- RPM packages for CentOS 7 and Fedora 24 generated on release

What's in?
- *Search-as-you-type*
- Unicode support
- Option `-S` to start in disk usage analyzer mode
- Show media information (using mediainfo)
- Use readline at change directory prompt
- Jump to prev directories using `cd .....` (with `.` as PWD)
- Jump to initial directory using `&`
- Show help, mediainfo and file info in PAGER
- Several optimizations

-------------------------------------------------------------------------------

nnn v1.0
2017-04-13

Modifications
- Behaviour and navigation
  - Detail view (default: disabled) with:
    - file type (directory, regular, symlink etc.)
    - modification time
    - human-readable file size
    - current item in reverse video
    - number of items in current directory
    - full name of currently selected file in 'bar'
  - Show details of the currently selected file (stat, file)
  - Disk usage analyzer mode (within the same fs, doesn't follow symlinks)
  - Directories first (even with sorting)
  - Sort numeric names in numeric order
  - Case-insensitive alphabetic content listing instead of upper case first
  - Key `-` to jump to last visited directory
  - Roll over at the first and last entries of a directory (with Up/Down keys)
  - Removed navigation restriction with relative paths (and let permissions handle it)
  - Sort entries by file size (largest to smallest)
  - Shortcut to invoke file name copier (set using environment variable `NNN_COPIER`)
- File association
  - Set `NNN_OPENER` to let a desktop opener handle it all. E.g.:
        export NNN_OPENER=xdg-open
        export NNN_OPENER=gnome-open
        export NNN_OPENER=gvfs-open
  - Selective file associations (ignored if `NNN_OPENER` is set):
    - Associate plain text files (determined using file) with vi
    - Associate common audio and video mimes with mpv
    - Associate PDF files with [zathura](https://pwmt.org/projects/zathura/)
    - Removed `less` as default file opener (there is no universal standalone opener utility)
    - You can customize further (see [how to change file associations](#change-file-associations))
  - `NNN_FALLBACK_OPENER` is the last line of defense:
    - If the executable in static file association is missing
    - If a file type was not handled in static file association
    - This may be the best option to set your desktop opener to
  - To enable the desktop file manager key, set `NNN_DE_FILE_MANAGER`. E.g.:
        export NNN_DE_FILE_MANAGER=thunar
- Optimization
  - All redundant buffer removal
  - All frequently used local chunks now static
  - Removed some redundant string allocation and manipulation
  - Simplified some roundabout procedures
  - Compiler warnings fixed
  - strip the final binary

-------------------------------------------------------------------------------


================================================
FILE: LICENSE
================================================
BSD 2-Clause License

Copyright (c) 2014-2016, Lazaros Koromilas <lostd@2f30.org>
Copyright (c) 2014-2016, Dimitris Papastamos <sin@2f30.org>
Copyright (c) 2016-2026, Arun Prakash Jana <engineerarun@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: Makefile
================================================
VERSION = $(shell grep -m1 VERSION $(SRC) | cut -f 2 -d'"')

PREFIX ?= /usr/local
MANPREFIX ?= $(PREFIX)/share/man
DESKTOPPREFIX ?= $(PREFIX)/share/applications
DESKTOPICONPREFIX ?= $(PREFIX)/share/icons/hicolor
STRIP ?= strip
PKG_CONFIG ?= pkg-config
INSTALL ?= install
CP ?= cp

CFLAGS_OPTIMIZATION ?= -O3

O_DEBUG := 0  # debug binary
O_NORL := 1  # no readline support
O_PCRE2 := 0  # link with PCRE2 library
O_NOLC := 0  # no locale support
O_NOMOUSE := 0  # no mouse support
O_NOBATCH := 0  # no built-in batch renamer
O_NOFIFO := 0  # no FIFO previewer support
O_ICONS := 0  # support icons-in-terminal
O_NERD := 0  # support icons-nerdfont
O_EMOJI := 0  # support emoji
O_QSORT := 0  # use Alexey Tourbin's QSORT implementation
O_BENCH := 0  # benchmark mode (stops at first user input)
O_NOSSN := 0  # disable session support
O_NOUG := 0  # disable user, group name in status bar
O_NOX11 := 0  # disable X11 integration
O_NOSORT := 0  # disable sorting entries on dir load
O_DIMFILTERED := 1  # dim characters matching filter (default: enabled)

# User patches
O_COLEMAK := 0 # change key bindings to colemak compatible layout
O_GITSTATUS := 0 # add git status to detail view
O_NAMEFIRST := 0 # print file name first, add uid and guid to detail view
O_RESTOREPREVIEW := 0 # add preview pipe to close and restore preview pane

T_ICONS := 0 # test if multiple icons options are set and fail

# convert targets to flags for backwards compatibility
ifneq ($(filter debug,$(MAKECMDGOALS)),)
	O_DEBUG := 1
endif
ifneq ($(filter norl,$(MAKECMDGOALS)),)
	O_NORL := 1
endif
ifneq ($(filter nolc,$(MAKECMDGOALS)),)
	O_NORL := 1
	O_NOLC := 1
endif

ifeq ($(strip $(O_DEBUG)),1)
	CPPFLAGS += -DDEBUG
	CFLAGS += -g3
endif

ifeq ($(strip $(O_NORL)),1)
	CPPFLAGS += -DNORL
else ifeq ($(strip $(O_STATIC)),1)
	CPPFLAGS += -DNORL
else
	LDLIBS += -lreadline
endif

ifeq ($(strip $(O_PCRE2)),1)
	CPPFLAGS += -DPCRE2
	LDLIBS += -lpcre2-8
endif

ifeq ($(strip $(O_NOLC)),1)
	ifeq ($(strip $(O_ICONS)),1)
$(info *** Ignoring O_NOLC since O_ICONS is set ***)
	else ifeq ($(strip $(O_NERD)),1)
$(info *** Ignoring O_NOLC since O_NERD is set ***)
	else ifeq ($(strip $(O_EMOJI)),1)
$(info *** Ignoring O_NOLC since O_EMOJI is set ***)
	else
		CPPFLAGS += -DNOLC
	endif
endif

ifeq ($(strip $(O_NOMOUSE)),1)
	CPPFLAGS += -DNOMOUSE
endif

ifeq ($(strip $(O_NOBATCH)),1)
	CPPFLAGS += -DNOBATCH
endif

ifeq ($(strip $(O_NOFIFO)),1)
	CPPFLAGS += -DNOFIFO
endif

ifeq ($(strip $(O_ICONS)),1)
	ICONS_INCLUDE = icons-generated-icons-in-term.h
	CPPFLAGS += -DICONS_IN_TERM -DICONS_INCLUDE=\"$(ICONS_INCLUDE)\"
ifeq ($(strip $(T_ICONS)),1)
$(error Choose only one system for icons (O_ICONS, O_NERD or O_EMOJI))
endif
	T_ICONS := 1
endif

ifeq ($(strip $(O_NERD)),1)
	ICONS_INCLUDE = icons-generated-nerd.h
	CPPFLAGS += -DNERD -DICONS_INCLUDE=\"$(ICONS_INCLUDE)\"
ifeq ($(strip $(T_ICONS)),1)
$(error Choose only one system for icons (O_ICONS, O_NERD or O_EMOJI))
endif
	T_ICONS := 1
endif

ifeq ($(strip $(O_EMOJI)),1)
	ICONS_INCLUDE = icons-generated-emoji.h
	CPPFLAGS += -DEMOJI -DICONS_INCLUDE=\"$(ICONS_INCLUDE)\"
ifeq ($(strip $(T_ICONS)),1)
$(error Choose only one system for icons (O_ICONS, O_NERD or O_EMOJI))
endif
	T_ICONS := 1
endif

ifeq ($(strip $(O_QSORT)),1)
	CPPFLAGS += -DTOURBIN_QSORT
endif

ifeq ($(strip $(O_BENCH)),1)
	CPPFLAGS += -DBENCH
endif

ifeq ($(strip $(O_NOSSN)),1)
	CPPFLAGS += -DNOSSN
endif

ifeq ($(strip $(O_NOUG)),1)
	CPPFLAGS += -DNOUG
endif

ifeq ($(strip $(O_NOX11)),1)
	CPPFLAGS += -DNOX11
endif

ifeq ($(strip $(O_NOSORT)),1)
	CPPFLAGS += -DNOSORT
endif

ifeq ($(strip $(O_DIMFILTERED)),1)
	CPPFLAGS += -DDIM_FILTERED
endif

ifeq ($(shell $(PKG_CONFIG) ncursesw && echo 1),1)
	CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncursesw)
	LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs   ncursesw)
else ifeq ($(shell $(PKG_CONFIG) ncurses && echo 1),1)
	CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncurses)
	LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs   ncurses)
else
	LDLIBS_CURSES ?= -lncurses
endif

CFLAGS += -std=c11 -Wall -Wextra -Wshadow
CFLAGS += $(CFLAGS_OPTIMIZATION)
CFLAGS += $(CFLAGS_CURSES)

LDLIBS += $(LDLIBS_CURSES) -lpthread

# static compilation needs libgpm development package
ifeq ($(strip $(O_STATIC)),1)
	LDFLAGS += -static
	LDLIBS += -lgpm
endif

DISTFILES = src nnn.1 Makefile README.md LICENSE
SRC = src/nnn.c
HEADERS = src/nnn.h
BIN = nnn
DESKTOPFILE = misc/desktop/nnn.desktop
LOGOSVG = misc/logo/logo.svg
LOGO64X64 = misc/logo/logo-64x64.png

COLEMAK = patches/colemak
GITSTATUS = patches/gitstatus
NAMEFIRST = patches/namefirst
RESTOREPREVIEW = patches/restorepreview

# test if we are on Mac OS X and get X.Y.Z OS version with system binary /usr/bin/sw_vers
MACOS_VERSION := $(strip $(shell command -v sw_vers >/dev/null && [ "`sw_vers -productName`" = "Mac OS X" ] && sw_vers -productVersion))
# if Mac OS X detected, test if its version is below 10.12.0 relying on "sort -c" returning "disorder" message if the input is not sorted
ifneq ($(MACOS_VERSION),)
	MACOS_BELOW_1012 := $(if $(strip $(shell printf '10.12.0\n%s' "$(MACOS_VERSION)" | sort -ct. -k1,1n -k2,2n -k3,3n 2>&1)),1)
endif
# if Mac OS X version is below 10.12.0, compile in the replacement clock_gettime and define MACOS_BELOW_1012 so that it's included in nnn.c
ifneq ($(MACOS_BELOW_1012),)
	GETTIME_C = misc/macos-legacy/mach_gettime.c
	GETTIME_H = misc/macos-legacy/mach_gettime.h
	SRC += $(GETTIME_C)
	HEADERS += $(GETTIME_H)
	CPPFLAGS += -DMACOS_BELOW_1012
endif

ifeq ($(strip $(O_DEBUG)),1)
	HEADERS += src/dbg.h
endif
ifeq ($(strip $(O_QSORT)),1)
	HEADERS += src/qsort.h
endif
ifeq ($(strip $(O_EMOJI)),1)
	HEADERS += src/icons.h src/$(ICONS_INCLUDE)
endif
ifeq ($(strip $(O_NERD)),1)
	HEADERS += src/icons.h src/$(ICONS_INCLUDE)
endif
ifeq ($(strip $(O_ICONS)),1)
	HEADERS += src/icons.h src/$(ICONS_INCLUDE) src/icons-in-terminal.h
endif

all: $(BIN)

$(BIN): $(SRC) $(HEADERS) Makefile
	@$(MAKE) --silent prepatch
	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(GETTIME_C) $< $(LDLIBS)
	@$(MAKE) --silent postpatch

# targets for backwards compatibility
debug: $(BIN)
norl: $(BIN)
nolc: $(BIN)

src/$(ICONS_INCLUDE): src/icons-hash.c src/icons.h src/icons-in-terminal.h
	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -DICONS_GENERATE -o src/icons-hash-gen src/icons-hash.c
	./src/icons-hash-gen > $@

install-desktop: $(DESKTOPFILE)
	$(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPPREFIX)
	$(INSTALL) -m 0644 $(DESKTOPFILE) $(DESTDIR)$(DESKTOPPREFIX)
	$(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps
	$(INSTALL) -m 0644 $(LOGOSVG) $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps/nnn.svg
	$(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPICONPREFIX)/64x64/apps
	$(INSTALL) -m 0644 $(LOGO64X64) $(DESTDIR)$(DESKTOPICONPREFIX)/64x64/apps/nnn.png

uninstall-desktop:
	$(RM) $(DESTDIR)$(DESKTOPPREFIX)/$(DESKTOPFILE)
	$(RM) $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps/nnn.svg
	$(RM) $(DESTDIR)$(DESKTOPICONPREFIX)/64x64/apps/nnn.png

install: all
	$(INSTALL) -m 0755 -d $(DESTDIR)$(PREFIX)/bin
	$(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(PREFIX)/bin
	$(INSTALL) -m 0755 -d $(DESTDIR)$(MANPREFIX)/man1
	$(INSTALL) -m 0644 $(BIN).1 $(DESTDIR)$(MANPREFIX)/man1

uninstall:
	$(RM) $(DESTDIR)$(PREFIX)/bin/$(BIN)
	$(RM) $(DESTDIR)$(MANPREFIX)/man1/$(BIN).1

strip: $(BIN)
	$(STRIP) $^

upx: $(BIN)
	$(STRIP) $^
	upx -qqq $^

static:
	# regular static binary
	make O_STATIC=1 strip
	mv $(BIN) $(BIN)-static
	# static binary with icons-in-terminal support
	make O_STATIC=1 O_ICONS=1 strip
	mv $(BIN) $(BIN)-icons-static
	# static binary with patched nerd font support
	make O_STATIC=1 O_NERD=1 strip
	mv $(BIN) $(BIN)-nerd-static
	# static binary with emoji support
	make O_STATIC=1 O_EMOJI=1 strip
	mv $(BIN) $(BIN)-emoji-static

musl:
	cp misc/musl/musl-static-ubuntu.sh .
	./musl-static-ubuntu.sh 1
	rm ./musl-static-ubuntu.sh

shellcheck:
	find ./plugins/ -type f -not -name "*.md" -exec shellcheck {} +

dist:
	mkdir -p nnn-$(VERSION)
	$(CP) -r $(DISTFILES) nnn-$(VERSION)
	tar -cf - nnn-$(VERSION) | gzip > nnn-$(VERSION).tar.gz
	$(RM) -r nnn-$(VERSION)

sign:
	git archive -o nnn-$(VERSION).tar.gz --format tar.gz --prefix=nnn-$(VERSION)/ v$(VERSION)
	gpg --detach-sign --yes nnn-$(VERSION).tar.gz
	rm -f nnn-$(VERSION).tar.gz

upload-local: sign static musl
	$(eval ID=$(shell curl -s 'https://api.github.com/repos/jarun/nnn/releases/tags/v$(VERSION)' | jq .id))
	$(eval PKG_STATIC=$(BIN)-static)
	$(eval PKG_ICONS=$(BIN)-icons-static)
	$(eval PKG_NERD=$(BIN)-nerd-static)
	$(eval PKG_EMOJI=$(BIN)-emoji-static)
	$(eval PKG_MUSL=$(BIN)-musl-static)
	$(eval PKG_MUSL_EMOJI=$(BIN)-musl-emoji-static)
	$(eval ARCH=x86_64)

	# upload sign file
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=nnn-$(VERSION).tar.gz.sig' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/pgp-signature' \
	    --upload-file nnn-$(VERSION).tar.gz.sig

	# upx compress all static binaries
	upx -qqq $(PKG_STATIC)
	upx -qqq $(PKG_ICONS)
	upx -qqq $(PKG_NERD)
	upx -qqq $(PKG_EMOJI)
	upx -qqq $(PKG_MUSL)
	upx -qqq $(PKG_MUSL_EMOJI)

	# upload static binary
	tar -zcf $(PKG_STATIC)-$(VERSION).$(ARCH).tar.gz $(PKG_STATIC)
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=$(PKG_STATIC)-$(VERSION).$(ARCH).tar.gz' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/x-sharedlib' \
	    --upload-file $(PKG_STATIC)-$(VERSION).$(ARCH).tar.gz

	# upload icons-in-terminal compiled static binary
	tar -zcf $(PKG_ICONS)-$(VERSION).$(ARCH).tar.gz $(PKG_ICONS)
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=$(PKG_ICONS)-$(VERSION).$(ARCH).tar.gz' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/x-sharedlib' \
	    --upload-file $(PKG_ICONS)-$(VERSION).$(ARCH).tar.gz

	# upload patched nerd font compiled static binary
	tar -zcf $(PKG_NERD)-$(VERSION).$(ARCH).tar.gz $(PKG_NERD)
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=$(PKG_NERD)-$(VERSION).$(ARCH).tar.gz' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/x-sharedlib' \
	    --upload-file $(PKG_NERD)-$(VERSION).$(ARCH).tar.gz

	# upload emoji compiled static binary
	tar -zcf $(PKG_EMOJI)-$(VERSION).$(ARCH).tar.gz $(PKG_EMOJI)
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=$(PKG_EMOJI)-$(VERSION).$(ARCH).tar.gz' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/x-sharedlib' \
	    --upload-file $(PKG_EMOJI)-$(VERSION).$(ARCH).tar.gz

	# upload musl static binary
	tar -zcf $(PKG_MUSL)-$(VERSION).$(ARCH).tar.gz $(PKG_MUSL)
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=$(PKG_MUSL)-$(VERSION).$(ARCH).tar.gz' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/x-sharedlib' \
	    --upload-file $(PKG_MUSL)-$(VERSION).$(ARCH).tar.gz

	# upload musl emoji static binary
	tar -zcf $(PKG_MUSL_EMOJI)-$(VERSION).$(ARCH).tar.gz $(PKG_MUSL_EMOJI)
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=$(PKG_MUSL_EMOJI)-$(VERSION).$(ARCH).tar.gz' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/x-sharedlib' \
	    --upload-file $(PKG_MUSL_EMOJI)-$(VERSION).$(ARCH).tar.gz

clean:
	$(RM) -f $(BIN) nnn-$(VERSION).tar.gz *.sig $(BIN)-static $(BIN)-static-$(VERSION).x86_64.tar.gz $(BIN)-icons-static $(BIN)-icons-static-$(VERSION).x86_64.tar.gz $(BIN)-nerd-static $(BIN)-nerd-static-$(VERSION).x86_64.tar.gz $(BIN)-emoji-static $(BIN)-emoji-static-$(VERSION).x86_64.tar.gz $(BIN)-musl-static $(BIN)-musl-static-$(VERSION).x86_64.tar.gz $(BIN)-musl-emoji-static $(BIN)-musl-emoji-static-$(VERSION).x86_64.tar.gz src/icons-hash-gen src/icons-generated-*.h

checkpatches:
	./patches/check-patches.sh

prepatch:
ifeq ($(strip $(O_NAMEFIRST)),1)
	patch --forward $(PATCH_OPTS) --strip=1 --input=$(NAMEFIRST)/mainline.diff
ifeq ($(strip $(O_GITSTATUS)),1)
	patch --forward $(PATCH_OPTS) --strip=1 --input=$(GITSTATUS)/namefirst.diff
endif
else ifeq ($(strip $(O_GITSTATUS)),1)
	patch --forward $(PATCH_OPTS) --strip=1 --input=$(GITSTATUS)/mainline.diff
endif
ifeq ($(strip $(O_RESTOREPREVIEW)),1)
	patch --forward $(PATCH_OPTS) --strip=1 --input=$(RESTOREPREVIEW)/mainline.diff
endif
ifeq ($(strip $(O_COLEMAK)),1)
	patch --forward $(PATCH_OPTS) --strip=1 --input=$(COLEMAK)/mainline.diff
endif

postpatch:
ifeq ($(strip $(O_NAMEFIRST)),1)
ifeq ($(strip $(O_GITSTATUS)),1)
	patch --reverse $(PATCH_OPTS) --strip=1 --input=$(GITSTATUS)/namefirst.diff
endif
	patch --reverse $(PATCH_OPTS) --strip=1 --input=$(NAMEFIRST)/mainline.diff
else ifeq ($(strip $(O_GITSTATUS)),1)
	patch --reverse $(PATCH_OPTS) --strip=1 --input=$(GITSTATUS)/mainline.diff
endif
ifeq ($(strip $(O_RESTOREPREVIEW)),1)
	patch --reverse $(PATCH_OPTS) --strip=1 --input=$(RESTOREPREVIEW)/mainline.diff
endif
ifeq ($(strip $(O_COLEMAK)),1)
	patch --reverse $(PATCH_OPTS) --strip=1 --input=$(COLEMAK)/mainline.diff
endif

skip: ;

.PHONY: all install uninstall strip static dist sign upload-local clean install-desktop uninstall-desktop


================================================
FILE: README.md
================================================
<h3 align="center"><img src="misc/logo/logo-128x128.png" alt="nnn"><br>nnn - <i>Supercharge your productivity!</i></h3>

<p align="center">
<a href="https://github.com/jarun/nnn/releases/latest"><img src="https://img.shields.io/github/release/jarun/nnn.svg?maxAge=600&label=rel" alt="Latest release" /></a>
<a href="https://repology.org/project/nnn/versions"><img src="https://repology.org/badge/tiny-repos/nnn.svg?header=repos" alt="Availability"></a>
<a href="https://circleci.com/gh/jarun/workflows/nnn"><img src="https://img.shields.io/circleci/project/github/jarun/nnn.svg?label=CircleCI" alt="Circle CI Status" /></a>
<a href="https://github.com/jarun/nnn/actions"><img src="https://github.com/jarun/nnn/actions/workflows/ci.yml/badge.svg?branch=master" alt="GitHub CI Status" /></a>
<a href="https://en.wikipedia.org/wiki/Privacy-invasive_software"><img src="https://img.shields.io/badge/privacy-✓-crimson?maxAge=2592000" alt="Privacy Awareness" /></a>
<a href="https://github.com/jarun/nnn/blob/master/LICENSE"><img src="https://img.shields.io/badge/©-BSD%202--Clause-important.svg?maxAge=2592000" alt="License" /></a>
</p>

<p align="center"><a href="https://github.com/user-attachments/assets/541ca36d-ae26-49fb-97da-d1f7a12d4b9a"><img src="https://github.com/user-attachments/assets/a8ee4689-1552-4fb1-997e-b16fe8ef5086"></a></p>

<h3 align="center">[<a
href="https://github.com/jarun/nnn#features">Features</a>] [<a
href="https://github.com/jarun/nnn#quickstart">Quickstart</a>] [<a
href="https://github.com/jarun/nnn/tree/master/plugins#nnn-plugins">Plugins</a>] [<a
href="https://github.com/jarun/nnn/wiki">Wiki</a>]</h3>

`nnn` (_n³_) is a full-featured terminal file manager. It's tiny, nearly 0-config and [incredibly fast](https://github.com/jarun/nnn/wiki/Performance).

It is designed to be unobtrusive with smart workflows to match the trains of thought.

`nnn` can analyze disk usage, batch rename, launch apps and pick files. The plugin repository has tons of plugins to extend the capabilities further e.g. [live previews](https://github.com/jarun/nnn/wiki/Live-previews), (un)mount disks, find & list, file/dir diff, upload files. A [patch framework](https://github.com/jarun/nnn/tree/master/patches) hosts sizable user-submitted patches which are subjective in nature.

Independent (neo)vim plugins - [nnn.vim](https://github.com/mcchrish/nnn.vim), [vim-floaterm nnn wrapper](https://github.com/voldikss/vim-floaterm#nnn) and [nnn.nvim](https://github.com/luukvbaal/nnn.nvim) (neovim exclusive).

Runs on the Pi, [Termux](https://www.youtube.com/embed/AbaauM7gUJw) (Android), Linux, macOS, BSD, Haiku, Cygwin, WSL, across DEs or a strictly CLI env.

[_(more use cases)_](https://github.com/jarun/nnn/wiki/Basic-use-cases#the_nnn-magic)

## Features

- Quality
  - Privacy-aware (no unconfirmed user data collection)
  - POSIX-compliant, follows Linux kernel coding style
  - Highly optimized, static analysis integrated code
- Frugal
  - Typically needs less than 3.5MB resident memory
  - Works with 8 colors (and xterm 256 colors)
  - Disk-IO sensitive (few disk reads and writes)
  - No FPU usage (all integer maths, even for file size)
  - Minimizes screen refresh with fast line redraws
  - Tiny binary (typically around 100KB)
  - 1-column mode for smaller terminals and form factors
  - Hackable - compile in/out features and dependencies
- Portable
  - Language-agnostic plugins
  - Static binary available (no need to install)
  - Minimal library deps, easy to compile
  - No config file, minimal config with sensible defaults
  - Plugin to backup configuration
  - Widely available on many packagers
  - Touch enabled, handheld-friendly shortcuts
  - Unicode support
- Modes
  - Light (default), detail
  - Disk usage analyzer (block/apparent)
  - File picker, (neo)vim plugin
- Navigation
  - Filter with automatic dir entry on unique match
  - *Type-to-nav* (turbo navigation/always filter) mode
  - Jump to an entry with visible relative offset
  - Contexts (_aka_ tabs/workspaces) with custom colors
  - Sessions, bookmarks, mark and visit a dir
  - Remote mounts (needs `sshfs`, `rclone`)
  - Familiar shortcuts (arrows, <kbd>~</kbd>, <kbd>-</kbd>, <kbd>@</kbd>), quick look-up
  - `cd` on quit (*easy* shell integration)
  - Proceed to next file on file open and selection
- Search
  - Instant filtering with *search-as-you-type*
  - Fuzzy, regex (POSIX/PCRE2) and string (default) filters
  - Subtree search plugin to open or edit files
- Sort
  - Ordered pure numeric names by default (visit `/proc`)
  - Case-insensitive version (_aka_ natural) sort
  - By name, access/change/mod (default) time, size, extn
  - Reverse sort
  - Directory-specific ordering
- Mimes
  - Preview hovered files in FIFO-based previewer
  - Open with desktop opener or specify a custom opener
  - File-specific colors (or minimal _dirs in context color_)
  - Icons and Emojis support (customize and compile-in)
  - Plugin for image, video and audio thumbnails
  - Create, list, extract (to), mount (FUSE based) archives
  - Option to open all text files in `$EDITOR`
- Convenience
  - Detailed file stats and mime information
  - Run plugins and custom commands with hotkeys
  - FreeDesktop compliant trash utility integration
  - Cross-dir file/all/range selection
  - Create (with parents), rename, duplicate files and dirs
  - Create new file or directory (tree) on startup
  - Batch renamer for selection or dir
  - List input stream of file paths from stdin or plugin
  - Copy (as), move (as), delete, archive, link selection
  - Easily copy, move paths in system clipboard to current dir
  - Dir updates, notification on `cp`, `mv`, `rm` completion
  - Copy file paths to system clipboard on select
  - Launch apps, run commands, spawn a shell, toggle exe
  - Access context paths/files at prompt or spawned shell
  - Lock terminal after configurable idle timeout
  - Capture and show output of a program in help screen
  - Basic support for screen readers and braille displays

## Quickstart

1. [Install](https://github.com/jarun/nnn/wiki/Usage) `nnn` and the dependencies you need.
2. The desktop opener is default. Use `-e` to open text files in the terminal. Optionally [open detached](https://github.com/jarun/nnn/wiki/Basic-use-cases#detached-text).
3. Configure [`cd` on quit](https://github.com/jarun/nnn/wiki/Basic-use-cases#configure-cd-on-quit).
4. [Sync subshell `$PWD`](https://github.com/jarun/nnn/wiki/Basic-use-cases#sync-subshell-pwd) to `nnn`.
5. [Install plugins](https://github.com/jarun/nnn/tree/master/plugins#installation).
6. Use `-x` to sync selection to clipboard, show notis on `cp`, `mv`, `rm` and set xterm title.
7. For a CLI-only environment, set [`NNN_OPENER`](https://github.com/jarun/nnn/wiki/Usage#configuration) to [`nuke`](https://github.com/jarun/nnn/blob/master/plugins/nuke). Use option `-c`.
8. Bid `ls` goodbye! `alias ls='nnn -de'` :sunglasses:
9. Visit the [Live previews](https://github.com/jarun/nnn/wiki/Live-previews) and [Troubleshooting](https://github.com/jarun/nnn/wiki/Troubleshooting) Wiki pages.

Don't memorize! Arrows, <kbd>/</kbd>, <kbd>q</kbd> suffice. <kbd>Tab</kbd> creates and/or cycles contexts. <kbd>?</kbd> lists shortcuts.

[![](https://github.com/user-attachments/assets/e93f7571-8b8d-4703-bef1-93fc804adf7d)](https://www.youtube.com/embed/-knZwdd1ScU)

[![Wiki](https://img.shields.io/badge/RTFM-nnn%20Wiki-important?maxAge=2592000)](https://github.com/jarun/nnn/wiki)

## Videos

- [nnn file manager on Termux (Android)](https://www.youtube.com/embed/AbaauM7gUJw)
- [NNN File Manager](https://www.youtube.com/embed/1QXU4XSqXNo)
- [This Week in Linux 114 - TuxDigital](https://www.youtube.com/watch?v=5W9ja0DQjSY&t=2059s)
- [nnn file manager basics - Linux](https://www.youtube.com/embed/il2Fm-KJJfM)
- [I'M GOING TO USE THE NNN FILE BROWSER! 😮](https://www.youtube.com/embed/U2n5aGqou9E)
- [NNN: Is This Terminal File Manager As Good As People Say?](https://www.youtube.com/embed/KuJHo-aO_FA)
- [nnn - A File Manager (By Uoou, again.)](https://www.youtube.com/embed/cnzuzcCPYsk)

## Elsewhere

- [AddictiveTips](https://www.addictivetips.com/ubuntu-linux-tips/navigate-linux-filesystem/)
- [ArchWiki](https://wiki.archlinux.org/index.php/Nnn)
- [FOSSMint](https://www.fossmint.com/nnn-linux-terminal-file-browser/)
- [gHacks Tech News](https://www.ghacks.net/2019/11/01/nnn-is-an-excellent-command-line-based-file-manager-for-linux-macos-and-bsds/)
- Hacker News [[1](https://news.ycombinator.com/item?id=18520898)] [[2](https://news.ycombinator.com/item?id=19850656)]
- [It's FOSS](https://itsfoss.com/nnn-file-browser-linux/)
- [Linux Format Issue 265; Manage files with nnn](https://linuxformat.com/archives?issue=265)
- LinuxLinks [[1](https://www.linuxlinks.com/nnn-fast-and-flexible-file-manager/)] [[2](https://www.linuxlinks.com/bestconsolefilemanagers/)] [[3](https://www.linuxlinks.com/excellent-system-tools-nnn-portable-terminal-file-manager/)]
- [Linux Magazine; FOSSPicks](https://www.linux-magazine.com/Issues/2017/205/FOSSPicks/(offset)/15)
- [Make Tech Easier](https://www.maketecheasier.com/nnn-file-manager-terminal/)
- [Opensource.com](https://opensource.com/article/22/12/linux-file-manager-nnn)
- [Open Source For You](https://www.opensourceforu.com/2019/12/nnn-this-feature-rich-terminal-file-manager-will-enhance-your-productivity/)
- [PCLinuxOS Magazine Issue June 2021](https://pclosmag.com/html/Issues/202106/page08.html)
- [Suckless Rocks](https://suckless.org/rocks/)
- [Ubuntu Full Circle Magazine Issue 135; Review: nnn](https://fullcirclemagazine.org/issue-135/)
- [Using and Administering Linux: Volume 2: Zero to SysAdmin: Advanced Topics](https://books.google.com/books?id=MqjDDwAAQBAJ&pg=PA32)
- [Wikipedia](https://en.wikipedia.org/wiki/Nnn_(file_manager))

## Developers

- [Arun Prakash Jana](https://github.com/jarun) (Copyright © 2016-2026)
- [0xACE](https://github.com/0xACE)
- [Anna Arad](https://github.com/annagrram)
- [KlzXS](https://github.com/KlzXS)
- [Léo Villeveygoux](https://github.com/leovilok)
- [Luuk van Baal](https://github.com/luukvbaal)
- [NRK](https://codeberg.org/NRK)
- [Sijmen J. Mulder](https://github.com/sjmulder)
- and other contributors

Visit the [Tracker](https://github.com/jarun/nnn/issues/1546) thread for a list of features in progress and anything up for grabs. Feel free to [discuss](https://github.com/jarun/nnn/discussions) new ideas or enhancement requests.


================================================
FILE: misc/CONTRIBUTING.md
================================================
# Contributing
Contributions to nnn are welcome! There's always an open issue with the current ToDo list, which contains the proposed features for the next release you can get your hands on. Any small changes or ideas should go in there, rather than in a separate issue.

Before suggesting changes, please read a bit about [the design principles nnn follows](https://github.com/jarun/nnn/wiki/concepts#design), and make sure you aren't breaking any of them.

Feel free to join the [Discussions](https://github.com/jarun/nnn/discussions). We highly recommended a discussion before raising a PR.

## Coding standard

`nnn` follows the Linux kernel coding style closely. The C source code uses TABs and the plugins use 4 spaces for indentation.

- Code changes should not break the patch framework. Please run `make checkpatches` to ensure.
- Run `make shellcheck` if adding/modifying plugins.

CI runs patch framework sanity test and `shellcheck`. Please watch out for any failures after raising the PR.

## Resources
The [wiki](https://github.com/jarun/nnn/wiki/Developer-guides) has some resources for developers you might be interested in: building, debugging...

## Communication
* [Gitter chat](https://gitter.im/jarun/nnn)
* [GitHub team](https://github.com/nnn-devs) (if you plan on contributing regularly, ask for an invitation).


================================================
FILE: misc/auto-completion/bash/nnn-completion.bash
================================================
#
# Rudimentary Bash completion definition for nnn.
#
# Author:
#   Arun Prakash Jana <engineerarun@gmail.com>
#

_nnn ()
{
    COMPREPLY=()
    local IFS=$'\n'
    local cur=$2 prev=$3
    local -a opts
    opts=(
        -a
        -A
        -b
        -B
        -c
        -C
        -d
        -D
        -e
        -E
        -f
        -g
        -H
        -i
        -J
        -K
        -l
        -n
        -o
        -p
        -P
        -Q
        -r
        -R
        -s
        -S
        -t
        -T
        -u
        -U
        -V
        -x
        -z
        -0
        -h
    )
    if [[ $prev == -b ]]; then
        local bookmarks=$(echo $NNN_BMS | awk -F: -v RS=\; '{print $1}')
        COMPREPLY=( $(compgen -W "$bookmarks" -- "$cur") )
    elif [[ $prev == -l ]]; then
        return 1
    elif [[ $prev == -p ]]; then
        COMPREPLY=( $(compgen -f -d -- "$cur") )
    elif [[ $prev == -P ]]; then
        local plugins=$(echo $NNN_PLUG | awk -F: -v RS=\; '{print $1}')
        COMPREPLY=( $(compgen -W "$plugins" -- "$cur") )
    elif [[ $prev == -s ]]; then
        local sessions_dir=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/sessions
        COMPREPLY=( $(cd "$sessions_dir" && compgen -f -d -- "$cur") )
    elif [[ $prev == -t ]]; then
        return 1
    elif [[ $prev == -T ]]; then
        local keys=$(echo "a d e r s t v" | awk -v RS=' ' '{print $0}')
        COMPREPLY=( $(compgen -W "$keys" -- "$cur") )
    elif [[ $cur == -* ]]; then
        COMPREPLY=( $(compgen -W "${opts[*]}" -- "$cur") )
    else
        COMPREPLY=( $(compgen -f -d -- "$cur") )
    fi
}

complete -o filenames -F _nnn nnn


================================================
FILE: misc/auto-completion/fish/nnn.fish
================================================
#
# Fish completion definition for nnn.
#
# Author:
#   Arun Prakash Jana <engineerarun@gmail.com>
#

if test -n "$XDG_CONFIG_HOME"
    set sessions_dir $XDG_CONFIG_HOME/.config/nnn/sessions
else
    set sessions_dir $HOME/.config/nnn/sessions
end

complete -c nnn -s a    -d 'auto-create NNN_FIFO'
complete -c nnn -s A    -d 'disable dir auto-enter'
complete -c nnn -s b -r -d 'bookmark key to open' -x -a '(echo $NNN_BMS | awk -F: -v RS=\; \'{print $1"\t"$2}\')'
complete -c nnn -s B    -d 'use bsdtar for archives'
complete -c nnn -s c    -d 'cli-only opener'
complete -c nnn -s C    -d 'color by context'
complete -c nnn -s d    -d 'start in detail mode'
complete -c nnn -s D    -d 'dirs in context color'
complete -c nnn -s e    -d 'open text files in $VISUAL/$EDITOR/vi'
complete -c nnn -s E    -d 'use EDITOR for undetached edits'
complete -c nnn -s f    -d 'use history file'
complete -c nnn -s g    -d 'regex filters'
complete -c nnn -s H    -d 'show hidden files'
complete -c nnn -s i    -d 'show current file info'
complete -c nnn -s J    -d 'no auto-advance on selection'
complete -c nnn -s K    -d 'detect key collision and exit'
complete -c nnn -s l -r -d 'lines to move per scroll'
complete -c nnn -s n    -d 'start in type-to-nav mode'
complete -c nnn -s o    -d 'open files only on Enter'
complete -c nnn -s p -r -d 'copy selection to file' -a '-\tstdout'
complete -c nnn -s P -r -d 'plugin key to run' -x -a '(echo $NNN_PLUG | awk -F: -v RS=\; \'{print $1"\t"$2}\')'
complete -c nnn -s Q    -d 'disable quit confirmation'
complete -c nnn -s r    -d 'show cp, mv progress (Linux-only)'
complete -c nnn -s R    -d 'disable rollover at edges'
complete -c nnn -s s -r -d 'load session by name' -x -a '@\t"last session" (ls $sessions_dir)'
complete -c nnn -s S    -d 'persistent session'
complete -c nnn -s t -r -d 'timeout in seconds to lock'
complete -c nnn -s T -r -d 'sort order' -x -a "a\t'apparent disk usage' d\t'disk usage' e\t'extension' r\t'reverse' s\t'size' t\t'time' v\t'version'"
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 z    -d 'in order fuzzy filters'
complete -c nnn -s 0    -d 'use null separator in picker mode'
complete -c nnn -s h    -d 'show program help'


================================================
FILE: misc/auto-completion/zsh/_nnn
================================================
#compdef nnn
#
# Completion definition for nnn.
#
# Author:
#   Arun Prakash Jana <engineerarun@gmail.com>
#

setopt localoptions noshwordsplit noksharrays
local -a args
args=(
    '(-a)-a[auto-create NNN_FIFO]'
    '(-A)-A[disable dir auto-enter]'
    '(-b)-b[bookmark key to open]:key char'
    '(-B)-B[use bsdtar for archives]'
    '(-c)-c[cli-only opener]'
    '(-C)-C[color by context]'
    '(-d)-d[start in detail mode]'
    '(-D)-D[dirs in context color]'
    '(-e)-e[open text files in $VISUAL/$EDITOR/vi]'
    '(-E)-E[use EDITOR for undetached edits]'
    '(-f)-f[use history file]'
    '(-F)-F[fifo notification mode]:mode:(( 0\:"notify as previewer" 1\:"notify as explorer" ))'
    '(-g)-g[regex filters]'
    '(-H)-H[show hidden files]'
    '(-i)-i[show current file info]'
    '(-J)-J[no auto-advance on selection]'
    '(-K)-K[detect key collision and exit]'
    '(-l)-l[lines to move per scroll]:val'
    '(-n)-n[start in type-to-nav mode]'
    '(-o)-o[open files only on Enter]'
    '(-p)-p[copy selection to file]:file name'
    '(-P)-P[plugin key to run]:key char'
    '(-Q)-Q[disable quit confirmation]'
    '(-r)-r[show cp, mv progress (Linux-only)]'
    '(-R)-R[disable rollover at edges]'
    '(-s)-s[load session]:session name'
    '(-S)-S[persistent session]'
    '(-t)-t[timeout to lock]:seconds'
    '(-T)-T[sort order]:key:(( a\:"apparent disk usage" d\:"disk usage" e\:"extension" r\:"reverse" s\:"size" t\:"time" v\:"version" ))'
    '(-u)-u[use selection (no prompt)]'
    '(-U)-U[show user and group]'
    '(-V)-V[show program version and exit]'
    '(-x)-x[notis, sel to system clipboard, xterm title]'
    '(-z)-z[in order fuzzy filters]'
    '(-0)-0[use null separator in picker mode]'
    '(-h)-h[show program help]'
    '*:filename:_files'
)
_arguments -S -s $args


================================================
FILE: misc/desktop/nnn.desktop
================================================
[Desktop Entry]
Type=Application
Name=nnn
Comment=Terminal file manager
Exec=nnn %f
Terminal=true
Icon=nnn
MimeType=inode/directory
Categories=System;FileTools;FileManager;ConsoleOnly
Keywords=File;Manager;Management;Explorer;Launcher


================================================
FILE: misc/haiku/Makefile
================================================
VERSION = $(shell grep -m1 VERSION $(SRC) | cut -f 2 -d'"')

PREFIX ?= /boot/system/non-packaged
MANPREFIX ?= $(PREFIX)/documentation/man
STRIP ?= strip
PKG_CONFIG ?= pkg-config
INSTALL ?= install
CP ?= cp

CFLAGS_OPTIMIZATION ?= -O3

O_DEBUG := 0  # debug binary
O_NORL := 0  # no readline support
O_PCRE := 0  # link with PCRE library
O_NOLC := 0  # no locale support
O_NOMOUSE := 0  # no mouse support
O_NOBATCH := 0  # no built-in batch renamer
O_NOFIFO := 0  # no FIFO previewer support
O_ICONS := 0  # support icons-in-terminal
O_NERD := 0  # support icons-nerdfont
O_QSORT := 0  # use Alexey Tourbin's QSORT implementation
O_BENCH := 0  # benchmark mode (stops at first user input)
O_NOSSN := 0  # disable session support
O_NOUG := 0  # disable user, group name in status bar
O_NOX11 := 0  # disable X11 integration
O_MATCHFLTR := 0  # allow filters without matches

# User patches
O_GITSTATUS := 0 # add git status to detail view
O_NAMEFIRST := 0 # print file name first, add uid and guid to detail view

ifeq ($(strip $(O_GITSTATUS)),1)
	LDLIBS += -lgit2
endif

# convert targets to flags for backwards compatibility
ifneq ($(filter debug,$(MAKECMDGOALS)),)
	O_DEBUG := 1
endif
ifneq ($(filter norl,$(MAKECMDGOALS)),)
	O_NORL := 1
endif
ifneq ($(filter nolc,$(MAKECMDGOALS)),)
	O_NORL := 1
	O_NOLC := 1
endif

ifeq ($(strip $(O_DEBUG)),1)
	CPPFLAGS += -DDEBUG
	CFLAGS += -g
	LDLIBS += -lrt
endif

ifeq ($(strip $(O_NORL)),1)
	CPPFLAGS += -DNORL
else ifeq ($(strip $(O_STATIC)),1)
	CPPFLAGS += -DNORL
else
	LDLIBS += -lreadline
endif

ifeq ($(strip $(O_PCRE)),1)
	CPPFLAGS += -DPCRE
	LDLIBS += -lpcre
endif

ifeq ($(strip $(O_NOLC)),1)
	ifeq ($(strip $(O_ICONS)),1)
$(info *** Ignoring O_NOLC since O_ICONS is set ***)
	else ifeq ($(strip $(O_NERD)),1)
$(info *** Ignoring O_NOLC since O_NERD is set ***)
	else
		CPPFLAGS += -DNOLC
	endif
endif

ifeq ($(strip $(O_NOMOUSE)),1)
	CPPFLAGS += -DNOMOUSE
endif

ifeq ($(strip $(O_NOBATCH)),1)
	CPPFLAGS += -DNOBATCH
endif

ifeq ($(strip $(O_NOFIFO)),1)
	CPPFLAGS += -DNOFIFO
endif

ifeq ($(strip $(O_ICONS)),1)
	CPPFLAGS += -DICONS
endif

ifeq ($(strip $(O_NERD)),1)
	CPPFLAGS += -DNERD
endif

ifeq ($(strip $(O_QSORT)),1)
	CPPFLAGS += -DTOURBIN_QSORT
endif

ifeq ($(strip $(O_BENCH)),1)
	CPPFLAGS += -DBENCH
endif

ifeq ($(strip $(O_NOSSN)),1)
	CPPFLAGS += -DNOSSN
endif

ifeq ($(strip $(O_NOUG)),1)
	CPPFLAGS += -DNOUG
endif

ifeq ($(strip $(O_NOX11)),1)
	CPPFLAGS += -DNOX11
endif

ifeq ($(strip $(O_MATCHFLTR)),1)
	CPPFLAGS += -DMATCHFLTR
endif

ifeq ($(shell $(PKG_CONFIG) ncursesw && echo 1),1)
	CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncursesw)
	LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs   ncursesw)
else ifeq ($(shell $(PKG_CONFIG) ncurses && echo 1),1)
	CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncurses)
	LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs   ncurses)
else
	LDLIBS_CURSES ?= -lncurses
endif

ifeq ($(shell uname -s), Haiku)
	LDLIBS_HAIKU ?= -lstdc++ -lgnu -lbe
	SRC_HAIKU ?= misc/haiku/nm.cpp
	OBJS_HAIKU ?= misc/haiku/nm.o
endif

CFLAGS += -std=c11 -Wall -Wextra -Wshadow
CFLAGS += $(CFLAGS_OPTIMIZATION)
CFLAGS += $(CFLAGS_CURSES)

LDLIBS += $(LDLIBS_CURSES) -lpthread $(LDLIBS_HAIKU)
# static compilation needs libgpm development package
ifeq ($(strip $(O_STATIC)),1)
	LDFLAGS += -static
	LDLIBS += -lgpm
endif

DISTFILES = src nnn.1 Makefile README.md LICENSE
SRC = src/nnn.c
HEADERS = src/nnn.h
BIN = nnn
OBJS := nnn.o $(OBJS_HAIKU)

GITSTATUS = patches/gitstatus
NAMEFIRST = patches/namefirst

all: $(BIN)

ifeq ($(shell uname -s), Haiku)
$(OBJS_HAIKU): $(SRC_HAIKU)
	$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
endif

nnn.o: $(SRC) $(HEADERS)
	$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<

$(BIN): $(OBJS)
	@$(MAKE) --silent prepatch
	$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
	@$(MAKE) --silent postpatch

# targets for backwards compatibility
debug: $(BIN)
norl: $(BIN)
nolc: $(BIN)

install: all
	$(INSTALL) -m 0755 -d $(DESTDIR)$(PREFIX)/bin
	$(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(PREFIX)/bin
	$(INSTALL) -m 0755 -d $(DESTDIR)$(MANPREFIX)/man1
	$(INSTALL) -m 0644 $(BIN).1 $(DESTDIR)$(MANPREFIX)/man1

uninstall:
	$(RM) $(DESTDIR)$(PREFIX)/bin/$(BIN)
	$(RM) $(DESTDIR)$(MANPREFIX)/man1/$(BIN).1

strip: $(BIN)
	$(STRIP) $^

static:
	# regular static binary
	make O_STATIC=1 strip
	mv $(BIN) $(BIN)-static

dist:
	mkdir -p nnn-$(VERSION)
	$(CP) -r $(DISTFILES) nnn-$(VERSION)
	mkdir -p nnn-$(VERSION)/misc
	$(CP) -r misc/haiku nnn-$(VERSION)/misc
	tar -cf - nnn-$(VERSION) | gzip > nnn-$(VERSION).tar.gz
	$(RM) -r nnn-$(VERSION)

sign:
	git archive -o nnn-$(VERSION).tar.gz --format tar.gz --prefix=nnn-$(VERSION)/ v$(VERSION)
	gpg --detach-sign --yes nnn-$(VERSION).tar.gz
	rm -f nnn-$(VERSION).tar.gz

upload-local: sign static
	$(eval ID=$(shell curl -s 'https://api.github.com/repos/jarun/nnn/releases/tags/v$(VERSION)' | jq .id))
	# upload sign file
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=nnn-$(VERSION).tar.gz.sig' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/pgp-signature' \
	    --upload-file nnn-$(VERSION).tar.gz.sig
	tar -zcf $(BIN)-static-$(VERSION).x86_64.tar.gz $(BIN)-static
	# upload static binary
	curl -XPOST 'https://uploads.github.com/repos/jarun/nnn/releases/$(ID)/assets?name=$(BIN)-static-$(VERSION).x86_64.tar.gz' \
	    -H 'Authorization: token $(NNN_SIG_UPLOAD_TOKEN)' -H 'Content-Type: application/x-sharedlib' \
	    --upload-file $(BIN)-static-$(VERSION).x86_64.tar.gz

clean:
	$(RM) -f $(BIN) nnn-$(VERSION).tar.gz *.sig $(BIN)-static $(BIN)-static-$(VERSION).x86_64.tar.gz

prepatch:
ifeq ($(strip $(O_NAMEFIRST)),1)
	patch --forward --strip=1 --input=$(NAMEFIRST)/mainline.diff
ifeq ($(strip $(O_GITSTATUS)),1)
	patch --forward --strip=1 --input=$(GITSTATUS)/namefirst.diff
endif
else ifeq ($(strip $(O_GITSTATUS)),1)
	patch --forward --strip=1 --input=$(GITSTATUS)/mainline.diff
endif

postpatch:
ifeq ($(strip $(O_NAMEFIRST)),1)
ifeq ($(strip $(O_GITSTATUS)),1)
	patch --reverse --strip=1 --input=$(GITSTATUS)/namefirst.diff
endif
	patch --reverse --strip=1 --input=$(NAMEFIRST)/mainline.diff
else ifeq ($(strip $(O_GITSTATUS)),1)
	patch --reverse --strip=1 --input=$(GITSTATUS)/mainline.diff
endif

skip: ;

.PHONY: all install uninstall strip static dist sign upload-local clean


================================================
FILE: misc/haiku/haiku_interop.h
================================================
#ifdef __cplusplus
extern "C" {
#endif

typedef struct haiku_nm_t *haiku_nm_h;
haiku_nm_h haiku_init_nm();
void haiku_close_nm(haiku_nm_h hnd);
int haiku_watch_dir(haiku_nm_h hnd, const char *path);
int haiku_stop_watch(haiku_nm_h hnd);
int haiku_is_update_needed(haiku_nm_h hnd);

#ifdef __cplusplus
}
#endif


================================================
FILE: misc/haiku/nm.cpp
================================================
#include <Directory.h>
#include <Looper.h>
#include <NodeMonitor.h>
#include <MessageFilter.h>

#include "haiku_interop.h"

filter_result dir_mon_flt(BMessage *message, BHandler **hnd, BMessageFilter *fltr) {
	(void) hnd;
	(void) fltr;

	if (message->what == B_NODE_MONITOR) {
		int32 val;
		message->FindInt32("opcode", &val);

		switch (val) {
			case B_ENTRY_CREATED:
			case B_ENTRY_MOVED:
			case B_ENTRY_REMOVED:
				return B_DISPATCH_MESSAGE;
		}
	}

	return B_SKIP_MESSAGE;
}

class DirectoryListener : public BLooper {
public:
	bool recv_reset() {
		Lock();
		bool val = _ev_on;
		_ev_on = false;
		Unlock();

		return val;
	}
private:
	void MessageReceived(BMessage * message) override {
		Lock();
		_ev_on = true;
		Unlock();
		BLooper::MessageReceived(message);
	}

	bool _ev_on = false;
};

struct haiku_nm_t {
	haiku_nm_t() {
		dl = new DirectoryListener();
		flt = new BMessageFilter(B_PROGRAMMED_DELIVERY, B_LOCAL_SOURCE, dir_mon_flt);
		dl->AddCommonFilter(flt);
		dl->Run();
	}

	DirectoryListener *dl;
	BMessageFilter *flt;
	node_ref nr;
};

haiku_nm_h haiku_init_nm() {
	return new haiku_nm_t();
}

void haiku_close_nm(haiku_nm_h hnd) {
	delete hnd->flt;
	// This is the way of deleting a BLooper
	hnd->dl->PostMessage(B_QUIT_REQUESTED);
	delete hnd;
}
int haiku_watch_dir(haiku_nm_h hnd, const char *path) {
	BDirectory dir(path);
	dir.GetNodeRef(&(hnd->nr));

	return watch_node(&(hnd->nr), B_WATCH_DIRECTORY, nullptr, hnd->dl);
}
int haiku_stop_watch(haiku_nm_h hnd) {
	return watch_node(&(hnd->nr), B_STOP_WATCHING, nullptr, hnd->dl);
}

int haiku_is_update_needed(haiku_nm_h hnd) {
	return hnd->dl->recv_reset();
}


================================================
FILE: misc/haiku/nnn-master.recipe
================================================
SUMMARY="A blazing-fast lightweight terminal file manager"
DESCRIPTION="nnn is a full-featured terminal file manager. It's tiny and \
nearly 0-config with an incredible performance.

nnn is also a du analyzer, an app launcher, a batch renamer and a file picker. \
The plugin repository has tons of plugins and documentation to extend the \
capabilities further. You can plug new functionality and play with a \
custom keybind instantly. There's an independent (neo)vim plugin.

It runs smoothly on the Raspberry Pi, Termux on Android, Linux, macOS, BSD, \
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-2026 Arun Prakash Jana"
LICENSE="BSD (2-clause)"
REVISION="1"
SOURCE_URI="git://github.com/jarun/nnn.git"

ARCHITECTURES="!x86_gcc2 x86_64"
SECONDARY_ARCHITECTURES="x86"

PROVIDES="
	nnn$secondaryArchSuffix = $portVersion
	cmd:nnn = $portVersion
	"
REQUIRES="
	haiku$secondaryArchSuffix
	file$secondaryArchSuffix
	lib:libncurses$secondaryArchSuffix
	lib:libreadline$secondaryArchSuffix
	"

BUILD_REQUIRES="
	haiku${secondaryArchSuffix}_devel
	devel:libncurses$secondaryArchSuffix
	devel:libreadline$secondaryArchSuffix
	"
BUILD_PREREQUIRES="
	cmd:g++$secondaryArchSuffix
	cmd:gcc$secondaryArchSuffix
	cmd:install
	cmd:ld$secondaryArchSuffix
	cmd:make
	cmd:pkg_config$secondaryArchSuffix
	"

BUILD()
{
	make -f misc/haiku/Makefile $jobArgs
}

INSTALL()
{
	make -f misc/haiku/Makefile install PREFIX=$prefix

	addResourcesToBinaries misc/haiku/nnn.rdef $prefix/bin/nnn
}


================================================
FILE: misc/haiku/nnn.rdef
================================================

// How to apply this resource definition file manually (Haiku only):
// First, make sure that nnn is compiled.
// Next, run "rc nnn.rdef -o nnn.rsrc" to compile this resource file.
// Then, run "xres -o nnn nnn.rsrc" to apply the resource file to nnn.
// Finally, run "mimeset -f nnn" to refresh Haiku's MIME database.

resource app_signature "application/x-vnd.Jarun-nnn";

resource app_version {
	major  = 5,
	middle = 2,
	minor  = 0,

	variety = B_APPV_DEVELOPMENT,
	internal = 0,

	short_info = "nnn",
	long_info  = "A blazing-fast lightweight terminal file manager"
};

resource app_flags B_MULTIPLE_LAUNCH | B_BACKGROUND_APP | B_ARGV_ONLY;

resource file_types message {
    "types" = "application/x-vnd.Be-directory"
};

resource vector_icon {
	$"6E6369660805FF032E343602011202B8E0C339BAC3B985CFB8B7E549F5FF4994"
	$"000000FFFF0000020112023745BA3659FABA87063B846942D03049EBF80000FF"
	$"FF0000020112033BE54D39FE49B857E23A493A4A91FF489000000000AF0000FF"
	$"00FF020112022D299A3B3A49BCE2FF2ED4134A65A94C096A0000FFFF00000201"
	$"1202365425358147B6C63037AFB14669664AB9F30000FFFF0000020112023673"
	$"5235AC4EB7FB7138A81D481E6A48C2C50000FFFF00000F0241BE60B360BE60B3"
	$"60BE5FB360BE3EB364BE46B362BE2AB369BE17B371BE1FB36DBE03B379BDF3B3"
	$"85BDFCB37EBDE3B38EBDCEB3A0BDD9B398BDB8B3B1BD8BB3DDBDA4B3C5BD58B4"
	$"0EBCCDB4A0BD17B450BC93B4DBBC36B539BC61B50DBC35B537BC32B536BC34B5"
	$"37BBE6B50ABB0FB48BBB7EB4CEBA9EB448B9E8B3DDBA36B40AB9C1B3C5B987B3"
	$"A5B9A0B3B3B97AB39FB967B394B971B399B961B391B954B38CB95DB390B94FB3"
	$"89B942B385B94CB388B93FB382B92FB37EB939B381B926B37DB8FFB379B900B3"
	$"79B8E9B379B87FB3A4B8B1B37DB84CB3C8B82FB418B838B3FBB81FB453B826B4"
	$"89B825B466B827B4CDB841B5F9B82FB534B848B656B854B6F9B84EB6B1B85AB7"
	$"41B85CB776B85CB782B85CB75BB83AB7A7B860B772B814B7DBB767B88FB7CEB8"
	$"29B6E7B90DB65CB9D1B694B955B626BA4CB62ABB5AB62CBAB9B629BC54B606BC"
	$"9DB634BC1BB5CDBD3EB4B1BEF5B597BDA1B445BF96B3B0C089B3DDC033B31AC1"
	$"A4B318C3DAB2D2C2D1B371C536B61FC639B4ABC60FB641C680B698C6F2B65CC6"
	$"CFB698C6F2B69AC6F2B69AC6F2B71EC742B838C6F9B7BDC733B8B2C6BEB96CC5"
	$"E2B919C65DB99BC59FBA11C4C4B9D8C530BA78C400BB14C34ABAB4C3A1BB75C2"
	$"F2BD20C209BC0BC29ABDDEC1A6BED6C108BE5244BED6C121BED8C151BED9C139"
	$"BECCC24CBE29C3E9BE9AC307BDC3C4B6BC1DC63ABD84C4F7BB43C700BA57C7FA"
	$"BAB9C781B9F5C872B99DC966B9BCC8EBB961CA48B95ECBBBB955CB0830CBFDB9"
	$"65CC7FB962CC3DBFC3CC7F60CC7FC621CC7FCC7ECBDECC7ACA9BCC7CCB3CCC6F"
	$"C6D6CA63BE51CB9AC1F5C98736C731B8ADC899BA16C5F2B76EC2C4B648C477B6"
	$"A1C212B625BFF7B63643B625C013B634C04A28C02FB631C027B5E2BFE0B546C0"
	$"04B593BFAFB4D8BF5EB436BF81B47BBF4DB415BF30B3E0BF3FB3F8BF28B3D3BF"
	$"18B3BBBF22B3C9BF11B3B4BEFFB39DBF0CB3ABBEF8B398BEE2B385BEF1B390BE"
	$"DAB380BEC5B375BED1B37ABEB9B36EBE96B364BE96B364BE96B364BE95B364BE"
	$"95B364BE93B364BE93B364BE93B364BE93B364BE60B360BE60B360BE60B36002"
	$"23BCA6C6D2BCA6C6D2BE0FC58CBEDFC443BE70C523BF5BC34EBFA3C159BF97C2"
	$"6DBFAAC0AEBF80BFC2BF99BFDABF7ABFBBBF34BFE33FBFC7BEA9C048BCC3C154"
	$"BDD9C0C2BA90C277B95BC467BA2FC2CFB926C4CCB8C5C56FB8E2C542B83EC636"
	$"B702C644B780C68FB6CEC624B6A8C5B6B6B4C5FDB6A1C587B660C581B69CC584"
	$"B510C56EB3DDC3A7B426C4C2B3ACC2EDB465C0E9B3E0C1E1B481C0B1B55ABF67"
	$"B4F0C005B642BE10B6C7BCE0B689BD92B6F5BC5DB6F6BB5AB6F5BC55B6F7BA1A"
	$"B7F5B921B6F5BA1EB8CDB84DB928B776B928B7CEB928B757B90CB5E9B91BB6A4"
	$"B8EBB45DB8FFB446B8EBB446B907B446BAA6B53A31B4B4BB85B5C0BC54B62FBC"
	$"47B62FBC6128BD60B52BBCDBB5BABDF2B491BE6BB42BBE5EB428BE78B42EBF27"
	$"B59ABEC3B4C2BF5DB613BFCBB704BF95B68DBFDEB703C005B702BFF2B702C0F0"
	$"B6F1C29CB70FC229B6F9C42AB761C6A0B93DC57CB818C7F0BA8FC9A0BE92C8CC"
	$"BC13CACFC21CCBAECA9DCBA3C6F5CBAFCAFBCBB15ECBB0CB56C5D85EBA295EC0"
	$"015EBA21CB0FBA61C99A32CA68BA97C8CBBCA6C6D2BAF4C858BCA6C6D20215C8"
	$"1C5EC81C5EC80FCB23C7DAC9A7C805CA9DC79EC84BC6E7C4FBC747C6A251C353"
	$"C5B5C054C61BC1ACC54FBEF9C4A1BD7F4DBDEFC457BD12C3C3BC5FC40EBCB4C3"
	$"79BC0DC2D8BB87C32B36C285BB4BC1C8BAF0C22BBB19C195BADDC120BAC444BA"
	$"D2C13EBADEC177BB1CC15CBAF6C19EBB66C1B9BC18C1B5BBBAC1BCBC74C184BD"
	$"41C1ABBCD8C15CBDA9C0C1BE85C11DBE17C0683EBF5CBFD2BFF2BF64BF69BFCD"
	$"BF80BFC2BF7EBFBFBF99BFDABFA3C159BFAAC0AEBF97C26DBEE1C443BF5BC34E"
	$"BE70C523BCA6C6D2BE0FC58CBAF4C858BA61C99ABA97C8CB32CA68BA295EBA21"
	$"CB0FBECF5EC81C5EC3755EC81C5E021CBE6BB42BBE6BB42BBE5EB428BD60B52B"
	$"BDF2B491BCDBB5BABC54B62FBC6128BC47B62FBAA6B53ABB85B5C031B4B4B8FF"
	$"B446B907B446B8EBB446B90CB5E9B8EBB45DB91BB6A4B928B776B928B757B928"
	$"B7CEB7F5B921B8CDB84DB6F5BA1EB6F6BB5AB6F7BA1AB6F5BC55B6C7BCE0B6F5"
	$"BC5DB689BD92B55ABF67B642BE10B4F0C005B465C0E9B481C0B1B3E0C1E1B3DD"
	$"C3A7B3ACC2EEB426C4C2B660C581B510C56EB680C583B697C58AB68FC583B74F"
	$"C477B90545B815C32CB9FCC041BC10BD70BB07BEB8BC94BCCCBD99BBBBBD18BC"
	$"36BE19BB41BF0DBAA0BE96BADFBF49BA82BFBBBA5FBF82BA6BBFF3BA52C05CBA"
	$"59C028BA50C090BA6143BA94C0C2BA75C103BA9FC120BAC4C110BAB6C125BAC5"
	$"C130BAC7C12ABAC6C0BBB986BFCEB704C043B846BFCDB704BFCBB704BFCDB704"
	$"BF95B68BBF27B59ABF5DB613BEC4B4C2BE6BB42BBE78B42EBE6BB42B0207BFCE"
	$"B704BFCEB704C063B85EC18FBB10C0F9B9B7C1C2BB1DC2BCBB74C28DBB61C6B9"
	$"BBACC6A0B93DCB98BF33C57CB818C29CB70FC42AB761C229B6F9C005B702C0F0"
	$"B6F1BFF3B702BFCEB704BFDFB703BFCEB7040207BCA6C6D2BCA6C6D2474ACB64"
	$"C69E5149CB91C805CBAECA9DCBABC963CBAFCAFBCBB15ECBB0CB56C5D85EBA29"
	$"5EC0015EBA21CB0FBA61C99A32CA68BA97C8CBBCA6C6D2BAF4C858BCA6C6D206"
	$"04BFB67CC579B67CC579B7C1C49BB900C2AFB8F9C22FB906C32EB6F5C5CDB841"
	$"C6ABB5AA4DB67CC5790211BD5BC297BD5BC297BDC5C279BEE5C244BE49C25EBF"
	$"83C22BC0E8C21FC02EC21FC19DC21FC2AAC26CC234C238C323C29CC3C4C33EC3"
	$"81C2E1C40BC399C45BC485C43EC405C478C502C487C626C487C58DC487C7BCC4"
	$"87CAE7C487C9514ACAE746CAE7C2EFCAE746C96B46C67346C7EF46C5A0C1DDC4"
	$"ABC20BC508C1AFC44FC0C2C421C151C421C097C421C040C424C06D4BC018C428"
	$"BFBFC434BFEEC42CBFBFC66FBFBFCAE7BFBFC8ACBEF3CAE7BD5BCAE7BE27CAE7"
	$"BD5BC821BD5BC297BD5BC55BBD5BC2970211BE27C363BE27C363BE91C345BFB1"
	$"C310BF16C32AC050C2F7C1B4C2EBC0FAC2EBC269C2EBC376C338C300C304C3EF"
	$"C368C490C40AC44DC3ADC4D7C465C527C551C50AC4D1C544C5CE4EC6F24EC659"
	$"4EC8454ECAE74EC9964CCAE748CAE74ACAE748C9C548C77F48C8A148C6B9C2A9"
	$"C5D4C2D7C62BC27BC57FC18EC553C21DC553C163C553C10CC557C1394EC0E4C5"
	$"5A42C565C0BAC55E42C73A42CAE742C91140CAE73CCAE73ECAE73CC866BE27C3"
	$"63BE27C5E4BE27C3630206B669C28FB669C28FB669C25DB613C207B642C21EB5"
	$"8645B4F5C338B507C245B4F1C374B4F7C3BEB4F3C3B2B503C3DAB59DC370B507"
	$"C3D7B632C309B669C28FB669C2CAB669C28F0207BAE6BC94BAE6BC94BC1EBB5D"
	$"BD8EB8BBBD8EB948BD8EB89BBD1AB854BD5AB86DBBF7B7E7B988B975BA7DB85F"
	$"B902BA0EB763BDFCB82DBAE5B751BE42B7F5BEBCB6C13FB92ABE1DBAE6BC94B9"
	$"EDBD8CBAE6BC940207B9EABBF2B9EABBF2BA4CBB90BABFBABCBABFBAE9BABFBA"
	$"B2BA9BBA9CBAAEBAA3BA40BA79B97BBAF7B9C8BA9EB952BB27B85BBCCCB85BBC"
	$"B7B85BBCE3B8FCBC9EB89BBCCFB95EBC6CB9EABBF2B99CBC3FB9EABBF2020FC0"
	$"E42CC0E42CC0BFB7C942B801C09DB7E0C07BB825C096B86CC080B84DC0ADB889"
	$"C0F8B893C0D4B899C2D4B862C515B9BAC413B8E0C617BA94C789BD20C6D6BBD2"
	$"C7CFBDA0C8EFC1C5C869BF62C977C428CA19CA85C9F2C73ACA1BCAABCA4FCADD"
	$"CA30CACCCA6FCAEDCAB5CAD7CA97CAEBCAD4CAC4CAE5CA7DCAE7CAA1CABDC722"
	$"59C19ACA3FC408C92DBF2BC83CBCC0C89FBD76C786BB6DC599B920C6BEBA17C4"
	$"73B827C0E42CC2EEB794C0E42C020AC70ABC69C70ABC69C1BB3BC864C462C353"
	$"50C8CFC440C982C3CEC930C411C983C3CDC984C3CCC983C3CCC985C3CAC987C3"
	$"C7C986C3C9C9D4C384CA37C2CDCA13C32DCA59C272CA1945CA19C220C9B33FC8"
	$"5ABC98C9B33DC85ABC98C859BC98C859BC98C7F2BC76C70ABC69C785BC69C70A"
	$"BC690220C6E2C242C6E2C242C740C242C7A5C216C782C234C7CCC1F8C7DFC1AB"
	$"C7DFC1D6C7DFC141C6C8C10CC782C10CC690C10CC622C10CC659C10CC622C0A1"
	$"C622BFC8C622C035C659BFC8C6C8BFC8C690BFC8C705BFC8C75FBFA5C738BFBD"
	$"C785BF8DC798BF35C798BF67C798BEE3C6EBBEB9C75FBEB9C6ADBEB9C635BED9"
	$"C66FBEC3C5FABEEEC587BF1BC5BFBF03C555BEB4C4F0BDE5C523BE4CC532BDBA"
	$"C5E5BD79C584BD98C64ABD5AC709BD4AC6ABBD4AC774BD4AC814BD6CC7CDBD54"
	$"C85EBD84C8C6BDCEC89ABDA5C8F1BDF5C922BE5CC911BE24C935BE91C93DBF04"
	$"C93DBECAC93DBF3EC916BFA5C931BF73C8FEBFD4C89AC038C8D4C005C8EEC05D"
	$"58C0D7C92CC092C975C117C988C1B0C988C160C988C1FAC966C27CC97DC23EC9"
	$"4EC2BBC8F1C321C927C2F1C8BCC34DC821C38BC878C370C7CCC3A5C6E7C3B4C7"
	$"63C3B4C68DC3B4C5C5C399C62EC3AAC562C384C4D6C348C511C36AC4F5C2D4C5"
	$"34C1EAC515C25EC58CC210C616C236C5D7C229C653C23EC6E2C242C698C242C6"
	$"E2C2420F0A000100000A010101000A020102000A030103000A040104000A0501"
	$"05000A060106000A010107000A000108000A000109000A07010A000A00010B00"
	$"0A00010C000A01010D000A00010E00"
};


================================================
FILE: misc/macos-legacy/mach_gettime.c
================================================
#include "mach_gettime.h"
#include <mach/mach_time.h>

#define MT_NANO (+1.0E-9)
#define MT_GIGA UINT64_C(1000000000)

// TODO create a list of timers,
static double mt_timebase = 0.0;
static uint64_t mt_timestart = 0;

int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
	kern_return_t retval = KERN_SUCCESS;

	if (clk_id == TIMER_ABSTIME) {
		if (!mt_timestart) { // only one timer, initialized on the first call to the TIMER
			mach_timebase_info_data_t tb;
			mach_timebase_info(&tb);
			mt_timebase = tb.numer;
			mt_timebase /= tb.denom;
			mt_timestart = mach_absolute_time();
		}

		double diff = (mach_absolute_time() - mt_timestart) * mt_timebase;
		tp->tv_sec = diff * MT_NANO;
		tp->tv_nsec = diff - (tp->tv_sec * MT_GIGA);
	} else { // other clk_ids are mapped to the corresponding mach clock_service
		clock_serv_t cclock;
		mach_timespec_t mts;

		host_get_clock_service(mach_host_self(), clk_id, &cclock);
		retval = clock_get_time(cclock, &mts);
		mach_port_deallocate(mach_task_self(), cclock);

		tp->tv_sec = mts.tv_sec;
		tp->tv_nsec = mts.tv_nsec;
	}

	return retval;
}

/*  Copyright (c) 2015-2018 Alf Watt - Open Source - https://opensource.org/licenses/MIT */


================================================
FILE: misc/macos-legacy/mach_gettime.h
================================================
#ifndef mach_time_h
#define mach_time_h

#include <sys/types.h>
#include <sys/_types/_timespec.h>
#include <mach/mach.h>
#include <mach/clock.h>

/* The opengroup spec isn't clear on the mapping from REALTIME to CALENDAR
 being appropriate or not.
 http://pubs.opengroup.org/onlinepubs/009695299/basedefs/time.h.html */

// XXX only supports a single timer
#define TIMER_ABSTIME -1
#define CLOCK_REALTIME CALENDAR_CLOCK
#define CLOCK_MONOTONIC SYSTEM_CLOCK

typedef int clockid_t;

/* the mach kernel uses struct mach_timespec, so struct timespec
	is loaded from <sys/_types/_timespec.h> for compatibility */
// struct timespec { time_t tv_sec; long tv_nsec; };

int clock_gettime(clockid_t clk_id, struct timespec *tp);

#endif

/*  Copyright (c) 2015-2018 Alf Watt - Open Source - https://opensource.org/licenses/MIT */


================================================
FILE: misc/musl/musl-static-ubuntu.sh
================================================
#!/usr/bin/env sh

# Statically compile nnn with netbsd-curses, musl-fts and musl libc on Ubuntu
#
# netbsd-curses: https://github.com/sabotage-linux/netbsd-curses
# musl-fts: https://github.com/void-linux/musl-fts
# musl libc: https://www.musl-libc.org/
#
# Dependencies: git
#
# Usage: musl-static-ubuntu.sh [no_run]
#        # optional argument - do not to execute the binary after compilation
#
# Notes:
#   - run the script within the top-level nnn directory
#   - installs musl & gits netbsd-curses, musl-fts libs
#
# Tested on Ubuntu 20.04 x86_64
# Author: Arun Prakash Jana

# Exit on first failure
set -e

# Output binary names
BIN=nnn-musl-static
EMOJIBIN=nnn-musl-emoji-static

# Install musl
sudo apt install -y --no-install-recommends musl musl-dev musl-tools

# Get netbsd-curses
[ ! -d "./netbsd-curses" ] && git clone https://github.com/sabotage-linux/netbsd-curses

# Enter the library dir
cd netbsd-curses

# Get the last known working version
git checkout v0.3.2

# Compile the static netbsd-curses libraries
if [ ! -d "./libs" ]; then
    mkdir libs
else
    rm -vf -- libs/*
fi
make CC=musl-gcc CFLAGS=-O3 LDFLAGS=-static all-static -j$(($(nproc)+1))
cp -v libcurses/libcurses.a libterminfo/libterminfo.a libs/

# Get musl-fts library
cd ..
[ ! -d "./musl-fts" ] && git clone https://github.com/void-linux/musl-fts --depth=1

# Compile the static musl-fts library
cd musl-fts
./bootstrap.sh
./configure
make CC=musl-gcc CFLAGS=-O3 LDFLAGS=-static -j$(($(nproc)+1))

cd ..

# Compile nnn with Emoji
[ -d "./netbsd-curses" ] && [ -d ./musl-fts ] || rm -- "$EMOJIBIN"
musl-gcc -DEMOJI -std=c11 -Wall -Wextra -Wshadow -O3 -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DICONS_GENERATE -o src/icons-hash-gen src/icons-hash.c
./src/icons-hash-gen > src/icons-generated-emoji.h
musl-gcc -O3 -DNORL -DNOMOUSE -DEMOJI -DICONS_INCLUDE=\"icons-generated-emoji.h\" -std=c11 -Wall -Wextra -Wshadow -I./netbsd-curses/libcurses -I./musl-fts -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -o "$EMOJIBIN"  src/nnn.c -Wl,-Bsymbolic-functions -lpthread -L./netbsd-curses/libs -lcurses -lterminfo -static -L./musl-fts/.libs -lfts

# Compile nnn
[ -d "./netbsd-curses" ] && [ -d ./musl-fts ] || rm -- "$BIN"
musl-gcc -O3 -DNORL -DNOMOUSE -std=c11 -Wall -Wextra -Wshadow -I./netbsd-curses/libcurses -I./musl-fts -o "$BIN" src/nnn.c -Wl,-Bsymbolic-functions -lpthread -L./netbsd-curses/libs -lcurses -lterminfo -static -L./musl-fts/.libs -lfts
strip "$BIN"

if [ -z "$1" ]; then
    # Run the binary with it selected
    ./"$BIN" -d "$BIN"
fi


================================================
FILE: misc/natool/natool
================================================
#!/usr/bin/env python3

# #############################################################################
# natool: a wrapper script to patool to list, extract and create archives
#
# usage: natool [-a] [-l] [-x] [archive] [file/dir]
#
# Examples:
# - create archive : natool -a archive.7z archive_dir
# - list archive   : natool -l archive.7z
# - extract archive: natool -x archive.7z
#
# Brief:
# natool is written to integrate patool (instead of the default atool) with nnn
# A copies of this file should be dropped somewhere in $PATH as atool
#
# Author: Arun Prakash Jana
# Email: engineerarun@gmail.com
# Homepage: https://github.com/jarun/nnn
# Copyright © 2019 Arun Prakash Jana
# #############################################################################

import sys
from subprocess import Popen, PIPE

if len(sys.argv) < 3:
    print('usage: natool [-a] [-l] [-x] [archive] [file/dir]')
    sys.exit(0)

if sys.argv[1] == '-a':
    cmd = ['patool', '--non-interactive', 'create', sys.argv[2]]
    cmd.extend(sys.argv[3:])
elif sys.argv[1] == '-l':
    cmd = ['patool', '--non-interactive', 'list']
    cmd.extend(sys.argv[2:])
elif sys.argv[1] == '-x':
    cmd = ['patool', '--non-interactive', 'extract']
    cmd.extend(sys.argv[2:])
else:
    sys.exit(0)

pipe = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
out, err = pipe.communicate()
print(out.decode())
print(err.decode())


================================================
FILE: misc/packagecore/packagecore.yaml
================================================
name: nnn
maintainer: Arun Prakash Jana <engineerarun@gmail.com>
license: BSD 2-Clause
summary: The unorthodox terminal file manager.
homepage: https://github.com/jarun/nnn
commands:
  install:
    - make PREFIX="/usr" strip install DESTDIR="${BP_DESTDIR}"
packages:
  centos7.5:
    builddeps:
      - make
      - gcc
      - pkgconfig
      - ncurses-devel
      - readline-devel
    deps:
      - ncurses
      - readline
    commands:
      pre:
        - yum install epel-release
  centos7.6:
    builddeps:
      - make
      - gcc
      - pkgconfig
      - ncurses-devel
      - readline-devel
    deps:
      - ncurses
      - readline
    commands:
      pre:
        - yum install epel-release
  centos7.7:
    builddeps:
      - make
      - gcc
      - pkgconfig
      - ncurses-devel
      - readline-devel
    deps:
      - ncurses
      - readline
    commands:
      pre:
        - yum install epel-release
  centos8.0:
    builddeps:
      - make
      - gcc
      - pkgconfig
      - ncurses-devel
      - readline-devel
    deps:
      - ncurses
      - readline
    commands:
      pre:
        - yum install epel-release
  debian9:
    builddeps:
      - make
      - gcc
      - pkg-config
      - libncursesw5-dev
      - libreadline-dev
    deps:
      - libncursesw5
      - readline-common
  debian10:
    builddeps:
      - make
      - gcc
      - pkg-config
      - libncurses-dev
      - libreadline-dev
    deps:
      - libncursesw6
      - readline-common
  fedora32:
    builddeps:
      - make
      - gcc
      - pkg-config
      - ncurses-devel
      - readline-devel
    deps:
      - ncurses
      - readline
#  opensuse15.2:
#    builddeps:
#      - make
#      - gcc
#      - pkg-config
#      - readline-devel
#      - ncurses-devel
#    deps:
#      - libncurses6
#      - libreadline7
#  opensuse.tumbleweed:
#    builddeps:
#      - make
#      - gcc
#      - pkg-config
#      - readline-devel
#      - ncurses-devel
#    deps:
#      - libncurses6
#      - libreadline8
  ubuntu16.04:
    builddeps:
      - make
      - gcc
      - pkg-config
      - libncursesw5-dev
      - libreadline6-dev
    deps:
      - libncursesw5
      - libreadline6
  ubuntu18.04:
    builddeps:
      - make
      - gcc
      - pkg-config
      - libncursesw5-dev
      - libreadline-dev
    deps:
      - libncursesw5
      - libreadline7
  ubuntu20.04:
    builddeps:
      - make
      - gcc
      - pkg-config
      - libncurses-dev
      - libreadline-dev
    deps:
      - libncursesw6
      - libreadline8


================================================
FILE: misc/quitcd/quitcd.bash_sh_zsh
================================================
n ()
{
    # Block nesting of nnn in subshells
    [ "${NNNLVL:-0}" -eq 0 ] || {
        echo "nnn is already running"
        return
    }

    # The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
    # If NNN_TMPFILE is set to a custom path, it must be exported for nnn to
    # see. To cd on quit only on ^G, remove the "export" and make sure not to
    # use a custom path, i.e. set NNN_TMPFILE *exactly* as follows:
    #      NNN_TMPFILE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.lastd"
    export NNN_TMPFILE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.lastd"

    # Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn
    # stty start undef
    # stty stop undef
    # stty lwrap undef
    # stty lnext undef

    # The command builtin allows one to alias nnn to n, if desired, without
    # making an infinitely recursive alias
    command nnn "$@"

    [ ! -f "$NNN_TMPFILE" ] || {
        . "$NNN_TMPFILE"
        rm -f -- "$NNN_TMPFILE" > /dev/null
    }
}


================================================
FILE: misc/quitcd/quitcd.csh
================================================
# NOTE: set NNN_TMPFILE correctly if you use 'XDG_CONFIG_HOME'

# The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
# If NNN_TMPFILE is set to a custom path, it must be exported for nnn to see.
# To cd on quit only on ^G, set NNN_TMPFILE after the nnn invocation, and make
# sure not to use a custom path.
set NNN_TMPFILE=~/.config/nnn/.lastd

# Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn
# stty start undef
# stty stop undef
# stty lwrap undef
# stty lnext undef

# The backslash allows one to alias n to nnn if desired without making an
# infinitely recursive alias
alias n '\nnn; source "$NNN_TMPFILE"; rm -f -- "$NNN_TMPFILE"'


================================================
FILE: misc/quitcd/quitcd.elv
================================================
# Append this file to ~/.elvish/rc.elv (Elvish > 0.17.0)

use path

fn n {|@a|
	# Block nesting of nnn in subshells
	if (has-env NNNLVL) {
		try {
			if (>= $E:NNNLVL 1) {
				echo "nnn is already running"
				return
			}
		} catch e {
			nop
		}
	}

	# The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
  # If NNN_TMPFILE is set to a custom path, it must be exported for nnn to
  # see.
  if (has-env XDG_CONFIG_HOME) {
		set-env NNN_TMPFILE $E:XDG_CONFIG_HOME/nnn/.lastd
	} else {
		set-env NNN_TMPFILE $E:HOME/.config/nnn/.lastd
	}

	# Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn
  # stty start undef
  # stty stop undef
  # stty lwrap undef
  # stty lnext undef

	# The e: prefix allows one to alias n to nnn if desired without making an
	# infinitely recursive alias
	e:nnn $@a

	if (path:is-regular $E:NNN_TMPFILE) {
		eval (slurp < $E:NNN_TMPFILE)
		rm -- $E:NNN_TMPFILE
	}
}


================================================
FILE: misc/quitcd/quitcd.fish
================================================
# Rename this file to match the name of the function
# e.g. ~/.config/fish/functions/n.fish
# or, add the lines to the 'config.fish' file.

function n --wraps nnn --description 'support nnn quit and change directory'
    # Block nesting of nnn in subshells
    if test -n "$NNNLVL" -a "$NNNLVL" -ge 1
        echo "nnn is already running"
        return
    end

    # The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
    # If NNN_TMPFILE is set to a custom path, it must be exported for nnn to
    # see. To cd on quit only on ^G, remove the "-x" from both lines below,
    # without changing the paths.
    if test -n "$XDG_CONFIG_HOME"
        set -x NNN_TMPFILE "$XDG_CONFIG_HOME/nnn/.lastd"
    else
        set -x NNN_TMPFILE "$HOME/.config/nnn/.lastd"
    end

    # Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn
    # stty start undef
    # stty stop undef
    # stty lwrap undef
    # stty lnext undef

    # The command function allows one to alias this function to `nnn` without
    # making an infinitely recursive alias
    command nnn $argv

    if test -e $NNN_TMPFILE
        source $NNN_TMPFILE
        rm -- $NNN_TMPFILE
    end
end


================================================
FILE: misc/quitcd/quitcd.nu
================================================
# Run nnn with dynamic changing directory to the environment.
#
# $env.XDG_CONFIG_HOME sets the home folder for `nnn` folder and its $env.NNN_TMPFILE variable.
# See manual NNN(1) for more information.
#
# Import module using `use quitcd.nu n` to have `n` command in your context.
export def --env n [
	...args : string # Extra flags to launch nnn with.
	--selective = false # Change directory only when exiting via ^G.
]: nothing -> nothing {

	# The behaviour is set to cd on quit (nnn checks if $env.NNN_TMPFILE is set).
	# Hard-coded to its respective behaviour in `nnn` source-code.
	let nnn_tmpfile = $env
		| default '~/.config/' 'XDG_CONFIG_HOME'
		| get 'XDG_CONFIG_HOME'
		| path join 'nnn/.lastd'
		| path expand

	# Launch nnn. Add desired flags after `^nnn`, ex: `^nnn -eda ...$args`,
	# or make an alias `alias n = n -eda`.
	if $selective {
		^nnn ...$args
	} else {
		NNN_TMPFILE=$nnn_tmpfile ^nnn ...$args
	}

	if ($nnn_tmpfile | path exists) {
		# Remove <cd '> from the first part of the string and the last single quote <'>.
		# Fix post-processing of nnn's given path that escapes its single quotes with POSIX syntax.
		let path = open $nnn_tmpfile
			| str replace --all --regex `^cd '|'$` ``
			| str replace --all `'\''` `'`

		^rm -- $nnn_tmpfile

		cd $path
	}
}


================================================
FILE: misc/quitcd/quitcd.rc
================================================
# The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
# If NNN_TMPFILE is set to a custom path, it must be exported for nnn to see.
# To cd on quit only on ^G, set NNN_TMPFILE after the nnn invocation, and make
# sure not to use a custom path.
NNN_TMPFILE='$HOME/.config/nnn/.lastd'

fn n {
    command nnn
    eval `( cat $NNN_TEMPFILE )
    rm -f -- $NNN_TMPFILE
}


================================================
FILE: misc/test/benchmark.sh
================================================
#!/bin/sh
#
# Usage: ./misc/test/benchmark.sh ./nnn /tmp/testdir1 ./testdir2 ...
#
# Don't forget to build nnn in benchmark mode: make O_BENCH=1

# Use a test dir filled with genfiles.sh to get interesting output
# (or maybe /usr/lib/)

LANG=C

TIME_VAL=${TIME_VAL:-"real"}

SAMPLES=${SAMPLES:-100}

EXE=$1

bench_val () {
    (time "$1" "$2") 2>&1 |\
    awk '$1=="'"$TIME_VAL"'"{match($2, /[0-9]*\.[0-9]*/) ; print substr($2, RSTART, RLENGTH)}'
}

bench_dir () {
    i=$SAMPLES
    printf "$2"
    while [ $((i--)) -gt 0 ] ; do
        printf "\t%s" "$(bench_val "$1" "$2")"
    done
    printf "\n"
}

shift

for dir in "$@" ; do
    bench_dir "$EXE" "$dir"
done



================================================
FILE: misc/test/genfiles.sh
================================================
#!/bin/sh

# Generates 100000 files in the current directory

i=1; while [ $i -le 100000 ]; do
    mktemp -p . -t 'XXXXXXXXXXXXXXXXXXXXX'
    i=$(( i + 1 ))
done


================================================
FILE: misc/test/mktest.sh
================================================
#!/bin/sh

# Create test files and directories

test -e outdir && {
    echo "Remove 'outdir' and try again"
    exit 1
}

mkdir -p outdir && cd outdir || exit 1

echo 'It works!' > normal.txt
echo 'Με δουλέβει;' > 'κοινό.txt'
ln -sf normal.txt ln-normal.txt
ln -sf normal.txt ln-normal
mkdir -p normal-dir
ln -sf normal-dir ln-normal-dir
ln -sf nowhere ln-nowhere
mkfifo mk-fifo
touch no-access && chmod 000 no-access
mkdir -p no-access-dir && chmod 000 no-access-dir
ln -sf ../normal.txt normal-dir/ln-normal.txt
ln -sf ../normal.txt normal-dir/ln-normal
echo 'int main(void) { *((char *)0) = 0; }' > ill.c
make ill > /dev/null
echo 'test/ill' > ill.sh
mkdir -p empty-dir
mkdir -p cage
echo 'chmod 000 test/cage' > cage/lock.sh
echo 'chmod 755 test/cage' > cage-unlock.sh
mkdir -p cage/lion
echo 'chmod 000 test/cage' > cage/lion/lock.sh
mkdir -p korean
touch 'korean/[ENG sub] PRODUCE48 울림ㅣ김채원ㅣ행복 나눠주는 천사소녀 @자기소개_1분 PR 180615 EP.0-Cgnmr6Fd82'
touch 'korean/[ENG sub] PRODUCE48 [48스페셜] 윙크요정, 내꺼야!ㅣ김채원(울림) 180615 EP.0-K7ulTiuJZK8.mp4'
touch 'korean/[FULL ENG SUB] 181008 SALEWA x IZ_ONE Long Padding Photoshoot Behind Film-[오늘의 시구] 아이즈원 (IZONE) 장원영&미야와키 사쿠라! 시구 시타! (10.06)-VmDl5eBJ3x0.mkv'
touch 'korean/IZ_ONE (아이즈원) - 1st Mini Album [COLOR_IZ] Highlight Medley-w9V2xFrYIgk.web'
touch 'korean/IZ_ONE (아이즈원) - 1st Mini Album [COLOR_IZ] MV TEASER 1-uhnJLBNBNto.mkv'
touch 'korean/IZ_ONE CHU [1회] ′순도 100%′ 우리즈원 숙소 생활 ★최초 공개★ 181025 EP.1-pcutrQN1Sbg.mkv'
touch 'korean/IZ_ONE CHU [1회_예고] 아이즈원 데뷔 준비 과정 ★독점 공개★ 아이즈원 츄 이번주 (목) 밤 11시 첫방송 181025'
touch 'korean/IZ_ONE CHU [1회] 도치기현 1호 이모 팬과의 만남! 181025 EP.1-5kYoReT5x44.mp4'
touch 'korean/IZ_ONE CHU [1회] ′12명 소녀들의 새로운 시작′ 앞으로 아이즈원 잘 부탁해♥ 181025 EP.1-RVNvgbdLQLQ'
touch 'korean/IZ_ONE CHU [1회] ′앗..그것만은!′ 자비없는 합숙생활 폭로전 181025 EP.1-AmP5KzpoI38.mkv'
touch 'korean/IZ_ONE CHU [1회] 휴게소 간식 내기 노래 맞히기 게임 181025 EP.1-LyNDKflpWYE.mp4'
touch 'korean/IZ_ONE CHU [1회] 2018 아이즈원 걸크러시능력시험 (feat. 치타쌤) 181025 EP.1-9qHWpbo0eB8.mp4'
touch 'korean/IZ_ONE CHU [1회] ′돼지요′ 아니죠, ′되지요′ 맞습니다! (feat. 꾸라먹방) 181025EP.1-WDLFqMWiKn'
touch 'korean/IZ_ONE CHU [1회] ′두근두근′ 첫 MT를 앞둔 비글력 만렙의 아이즈원 181025 EP.1'
mkdir -p unicode
touch 'unicode/Malgudi Days - मालगुडी डेज - E05. Swami and Friends - स्वामी और उसके दोस्त (Part 1)'
touch 'unicode/Malgudi Days - मालगुडी डेज - E05. Swami and Friends - स्वामी और उसके दोस्त (Part 2)'
touch 'unicode/Malgudi Days - मालगुडी डेज - E05. Swami and Friends - स्वामी और उसके दोस्त (Part 3)'
chmod +x 'unicode/Malgudi Days - मालगुडी डेज - E05. Swami and Friends - स्वामी और उसके दोस्त (Part 2)'
touch 'unicode/Führer'
touch 'unicode/Eso eso aamar ghare eso ♫ এসো এসো আমার ঘরে এসো ♫ Swagatalakshmi Dasgupta'
touch 'max_chars_filename_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'


================================================
FILE: misc/test/plot-bench.py
================================================
#!/usr/bin/env python3
#
# Usage: ./plot-bench.py datafile
# (where datafile is the output of benchmark.sh)

import matplotlib.pyplot as plt
import sys

def bench_file_to_lists(infile):
    return [[float(entry) for entry in line.split('\t')[1:]] for line in infile.readlines()]

def plot_data(data):
    fig = plt.figure()
    ax = fig.add_axes([0,0,1,1])
    ax.violinplot(data)
    plt.savefig("plot.svg")

filename = sys.argv[1]

plot_data(bench_file_to_lists(open(filename)))


================================================
FILE: misc/test/verify-du.sh
================================================
#!/bin/sh
# Verify disk usage: run du from a path and print in GB for comparison with nnn.
# Usage: ./verify-du.sh [path]
# Default path: current directory (.)
# Compare the output with nnn's du display when run from the same path.

path="${1:-.}"
echo "Path: $path"
echo ""

# Count files (like nnn does)
# nnn counts all non-directory entries: regular files, symlinks, devices, pipes, sockets, etc.
# nnn also counts files it cannot stat (permission denied) as non-directories
# -P: do not follow symbolic links
# -xdev: do not cross filesystem boundaries
# ! -type d: count everything except directories
# Do NOT suppress errors - count entries we can't access too
if command -v find >/dev/null 2>&1; then
	echo "File count (all non-directory entries):"
	# First, try to count including permission errors
	# find will still list the path even if it can't stat it
	file_count=$(find -P "$path" -xdev ! -type d 2>&1 | grep -v "Permission denied" | wc -l)

	# Alternative: count accessible files + count permission denied entries
	accessible=$(find -P "$path" -xdev ! -type d 2>/dev/null | wc -l)
	denied=$(find -P "$path" -xdev 2>&1 >/dev/null | grep -c "Permission denied" || echo 0)

	echo "  Accessible: $accessible files"
	echo "  Permission denied: $denied entries"
	echo "  Estimated total: $((accessible + denied)) files"

	# Debug: show breakdown by type
	echo ""
	echo "  Breakdown of accessible files:"
	echo "    Regular files: $(find -P "$path" -xdev -type f 2>/dev/null | wc -l)"
	echo "    Symlinks: $(find -P "$path" -xdev -type l 2>/dev/null | wc -l)"
	echo "    Other (devices, pipes, sockets): $(find -P "$path" -xdev \( -type c -o -type b -o -type p -o -type s \) 2>/dev/null | wc -l)"
	echo ""

	# Count directories
	echo "Directory count:"
	dir_count=$(find -P "$path" -xdev -type d 2>/dev/null | wc -l)
	echo "  $dir_count directories"
	echo ""
fi

# GNU du: -s = summary, default block size 1024 bytes
# So "du -s" output * 1024 = bytes
if command -v du >/dev/null 2>&1; then
	echo "du -s (1024-byte blocks, same as 'du -sh'):"
	blocks=$(du -s "$path" 2>/dev/null | cut -f1)
	if [ -n "$blocks" ]; then
		# bytes = blocks * 1024; GB = bytes / 1024^3
		bytes=$((blocks * 1024))
		gb=$(echo "scale=3; $bytes / 1073741824" | bc 2>/dev/null)
		echo "  $blocks 1K-blocks"
		echo "  ${gb} GB (bytes: $bytes)"
	else
		echo "  (failed or permission denied)"
	fi
	echo ""

	# Also show in 512-byte blocks (st_blocks units, what nnn uses for disk usage)
	echo "Equivalent in 512-byte blocks (nnn st_blocks units):"
	if [ -n "$blocks" ]; then
		blocks512=$((blocks * 2))
		echo "  $blocks512 512-byte blocks"
	fi
fi


================================================
FILE: nnn.1
================================================
.Dd Feb 14, 2026
.Dt NNN 1
.Os
.Sh NAME
.Nm nnn
.Nd The unorthodox terminal file manager.
.Sh SYNOPSIS
.Nm
.Op Ar -aAcCdDeEfgHJKnQrRSuUVxz0h
.Op Ar -b key
.Op Ar -F val
.Op Ar -l val
.Op Ar -p file
.Op Ar -P key
.Op Ar -s name
.Op Ar -t secs
.Op Ar -T key
.Op Ar PATH
.Sh DESCRIPTION
.Nm
.Pq Nnn's Not Noice
is a performance-optimized, feature-packed fork of noice
.Em http://git.2f30.org/noice/
with seamless desktop integration, simplified navigation,
.Em type-to-nav
mode with dir auto-enter, disk usage analyzer mode, bookmarks,
contexts, application launcher, familiar navigation shortcuts,
subshell spawning and much more. It remains a simple and
efficient file manager that stays out of your way.
.Pp
.Nm
opens the current working directory if
.Ar PATH
is not specified. If
.Ar PATH
is specified and it exists,
.Nm
will open it. If the
.Ar PATH
doesn't exist and ends with a \fB/\fR,
.Nm
will attempt to create the directory tree and open it. Otherwise,
.Ar PATH
is considered a path to a regular file and
.Nm
attempts to create the complete directory tree to the file, open
the parent directory and prompt to create the new file in it with
the base filename.
.Sh KEYBINDS
.Pp
Press
.Ql \fB?\fR
in
.Nm
to see the list of keybinds.
.Sh OPTIONS
.Pp
.Nm
supports the following options:
.Pp
.Fl a
        auto-setup temporary \fBNNN_FIFO\fR (refer to the \fBENVIRONMENT\fR section)
.Pp
.Fl A
        disable directory auto-enter on unique filter match
.Pp
.Fl "b key"
        specify bookmark key to open
.Pp
.Fl B
        use bsdtar for archives (default: atool)
.Pp
.Fl c
        indicates that the opener is a cli-only opener (overrides \fB-e\fR)
.Pp
.Fl C
        8-color scheme - color directories by context, disable file colors
.Pp
.Fl d
        detail mode
.Pp
.Fl D
        show directories in context color with \fBNNN_FCOLORS\fR set
.Pp
.Fl e
        open text files in $VISUAL (else $EDITOR, fallback vi) [preferably CLI]
.Pp
.Fl E
        use $EDITOR for internal undetached edits
.Pp
.Fl f
        use history file
.Pp
.Fl "F val"
        fifo notification mode
        0: notify as previewer, 1: notify as explorer
.Pp
.Fl g
        use regex filters instead of substring match
.Pp
.Fl H
        show hidden files
.Pp
.Fl i
        show current file information in info bar (may be slow)
.Pp
.Fl J
        disable auto-advance on selection
        (eg. selecting an entry will no longer move cursor to the next entry)
.Pp
.Fl K
        test for keybind collision and exit
.Pp
.Fl "l val"
        number of lines to move per mouse wheel scroll
.Pp
.Fl n
        start in type-to-nav mode
.Pp
.Fl o
        open files only on Enter key
.Pp
.Fl "p file"
        copy (or \fIpick\fR) selection to file, or stdout if file='-'
.Pp
.Fl "P key"
        specify plugin key to run
.Pp
.Fl Q
        disable confirmation on quit with multiple contexts active
.Pp
.Fl r
        show cp, mv progress
        (Linux-only, needs \fIadvcpmv\fR; \fB^T\fR shows the progress on BSD/macOS)
.Pp
.Fl R
        disable rollover at edges (eg. pressing \fBdown\fR while on the last
        entry will no longer move cursor to the first entry and vice\-versa)
.Pp
.Fl "s name"
        load a session by name
.Pp
.Fl S
        persistent session
.Pp
.Fl "t secs"
        idle timeout in seconds to lock terminal
.Pp
.Fl "T key"
        sort order (refer to the \fBSORTING\fR section)
        keys: 'a'pparent disk usage / 'd'isk usage / 'e'xtension / 'r'everse / 's'ize / 't'ime / 'v'ersion
        capitalize to reverse (except 'r')
.Pp
.Fl u
        use selection if available, don't prompt to choose between selection and hovered entry
.Pp
.Fl U
        show user and group names in status bar
.Pp
.Fl V
        show version and exit
.Pp
.Fl x
        show notifications on selection cp, mv, rm completion (requires the \fB.ntfy\fR plugin)
        copy path to system clipboard on selection (requires the \fB.cbcp\fR plugin)
        show xterm title (if non-picker mode)
.Pp
.Fl z
        use fuzzy filters (fuzzy match: all characters in filter appear in order)
.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
There is no configuration file. Associated files are at
.Pp
.Pa ${XDG_CONFIG_HOME:-$HOME/.config}/nnn/
.Pp
Configuration is done using a few optional (set if you need) environment
variables. Refer to the \fBENVIRONMENT\fR section.
.Pp
.Nm
uses \fBxdg-open\fR (on Linux), \fBopen(1)\fR (on macOS), \fBcygstart\fR on
(Cygwin) and \fBopen\fR on (Haiku) as the desktop opener. It's also possible
to specify a custom opener. Refer to the \fBENVIRONMENT\fR section.
.Sh CONTEXTS
Open multiple locations with 8 contexts. The status is shown in the top left
corner:
.Pp
- the current context is in reverse video
.br
- other active contexts are underlined
.br
- rest are inactive
.Pp
A new context copies the state of the previous context. Each context can have
its own color. Refer to the \fBENVIRONMENT\fR section.
.Sh 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.
.Pp
- When a session is loaded at runtime, the last working state is saved
automatically to a dedicated "auto session" session file. Session option
\fIrestore\fR would restore the "auto session".
.br
- The persistent session option is global. If it is used, the last active session
will be updated with the final state at program quit.
.br
- The "auto session" is used in persistent session mode if no session is active.
.br
- Listing input stream and opening a bookmark by key have a higher priority to
session options (\fB-s\fR/\fB-S\fR).
.Pp
All the session files are located by session name in the directory
.Pp
\fB${XDG_CONFIG_HOME:-$HOME/.config}/nnn/sessions\fR
.Pp
"@" is the "auto session" file.
.Sh FILTERS
Filters are strings (or regex patterns) to find matching entries in the current
directory instantly (\fIsearch-as-you-type\fR). Matches are case-insensitive by
default. The last filter in each context is persisted at runtime or in saved
sessions.
.br
When there's a unique match and it's a directory,
.Nm
auto enters the directory. Use the relevant program option to disable this.
.Pp
Special keys at filter prompt:
.Bd -literal
-------- + ---------------------------------------
  Key    |                Function
-------- + ---------------------------------------
 ^char   | Usual keybind functionality
 Esc     | Exit filter prompt but skip dir refresh
 Alt+Esc | Unfilter, quit context
 /       | Enter dir exactly matching filter
-------- + ---------------------------------------
.Ed
.Pp
Special keys at \fBempty\fR filter prompt:
.Bd -literal
------ + -------------------------------------
  Key  |                Function
------ + -------------------------------------
   ?   | Show help and config screen
   /   | Toggle between string, fuzzy, regex
   :   | Toggle case-sensitivity
  ^L   | Clear filter (if prompt is \fBnon-empty\fR)
       | OR apply last filter
  Bksp | Stay at filter prompt and refresh dir
  Del  | Stay at filter prompt and refresh dir
------ + -------------------------------------
.Ed
.Pp
Common regex use cases:
.Pp
(1) To list all matches starting with the filter expression,
    start the expression with a '^' (caret) symbol.
.br
(2) Type '\\.mkv' to list all MKV files.
.br
(3) Use '.*' to match any character (\fIsort of\fR fuzzy search).
.br
(4) Exclude filenames having 'nnn' (compiled with PCRE2 lib): '^(?!nnn)'
.Pp
In the \fItype-to-nav\fR mode directories are opened in filter
mode, allowing continuous navigation.
.Pp
Additional special keys at \fBempty\fR filter prompt
in \fItype-to-nav\fR mode:
.Bd -literal
------ + ------------------------
  Key  |         Function
------ + ------------------------
   '   | Go to first non-dir file
   +   | Toggle file selection
   ,   | Mark CWD
   -   | Go to last visited dir
   .   | Show hidden files
   ;   | Run a plugin by its key
   =   | Launch a GUI application
   >   | Export file list
   @   | Visit start dir
   ]   | Show command prompt
   `   | Visit /
   ~   | Go HOME
------ + ------------------------
.Ed
.Sh SORTING
.Nm
will always show the directories first, followed by the files. String
order is always case-insensitive.
.Pp
The sort key can be set either with the \fB-T\fR program option, or
interactively using \fBt\fR or \fB^T\fR. The following options are available:
.Bl -tag -width 2n
.It Ic a
apparent disk usage, how large the file appears to be, can be bigger than actual
disk usage in sparse files.
.It Ic d
disk usage, amount of data taken on disk, a multiple of the block size.
.It Ic e
extension of the file.
.It Ic r
reverse the current order (not available with \fB-T\fR).
.It Ic s
size of file, amount of data stored in the file.
.It Ic t
time, this depends on the currently selected time type which can be changed
using the \fBT\fR key.
Options are:
.Bl -tag -compact -width 1n
.It Ic a
access, last time the file was accessed.
.It Ic c
change, last time the metadata of the file was changed (e.g. permissions).
.It Ic m
modified, last time the content of the file was changed (default).
.El
.It Ic v
version, sorts by filename while treating digit characters numerically.
For example: j1.png, j02.png, j3.png.
.It Ic c
clear, revert to filename order (not available with \fB-T\fR).
.It Ic ^T
cycle between filename/size/time order (not available with \fB-T\fR).
.El
.Pp
The uppercase version of the option (except \fBr\fR) reverses the default order.
By default, time and size sort keys are ordered in descending order, and
alphabetical fields are ordered in ascending order.
For example, when using the \fBe\fR option, the entries will be ordered by
extension, in ascending order.
Using \fBE\fR would result in descending order of the extensions.
This means that \fBe\fR followed by \fBr\fR is the same as \fBE\fR.
.Sh SELECTION
.Nm
allows file selection across directories and contexts!
.Pp
There are 3 groups of keybinds to add files to selection:
.Pp
(1) hovered file selection toggle
    - deselects if '+' is visible before the entry, else adds to selection
.br
(2) add a range of files to selection
    - repeat the range key on the same entry twice to clear selection completely
.br
(3) add all files in the current directory to selection
.Pp
A selection can be edited, copied, moved, removed, archived or linked.
.Pp
Absolute paths of the selected files are copied to \fB.selection\fR 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
.Nm
\fIopen\fR 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
.Nm
instance where the selection was made on mv/rm (but not on cp).
.Pp
.Nm
clears the selection after a successful operation with the selection. Plugins
are allowed to define the behaviour individually.
.Pp
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.
.Pp
.Nm
can show the total size of non-filtered selected files listed in a
directory. For directories, only the size of the directory is added by
default. To add the size of the contents of a directory, sort by disk usage (aka du mode).
.Sh FIND AND LIST
There are two ways to search and list:
.Pp
- feed a list of file paths as input
.br
- search using a plugin (e.g. \fBfinder\fR) and list the results
.Pp
File paths must be NUL-separated ('\\0'). Paths and can be relative to the
current directory or absolute. Invalid paths in the input are ignored. Input
processing limit is 16,384 paths or 64 MiB (max_paths x max_path_len) of data.
.Pp
To list the input stream, start
.Nm
by writing to its standard input. E.g., to list files in current
directory larger than
1M:
.Bd -literal
    find -maxdepth 1 -size +1M -print0 | nnn
.Ed
.Pp
or redirect a list from a file:
.Bd -literal
    nnn < files.txt
.Ed
.Pp
Handy bash/zsh shell function to list files by mime-type in current directory:
.Bd -literal
    # to show video files, run: list video

    list ()
    {
        find . -maxdepth 1 | file -if- | grep "$1" | awk -F: '{printf "%s%c", $1, 0}' | nnn
    }
.Ed
.Pp
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.
.Pp
\fB>\fR or \fBl\fR on a symlink in the listing dir takes to the target
file. Press \fB-\fR to return to the listing dir. Press \fBEnter\fR to open the symlink.
.Pp
Listing input stream can be scripted. It can be extended to pick (option -p)
selected entries from the listed results.
.Sh BOOKMARKS
There are 2 ways (can be used together) to manage bookmarks.
.Pp
(1) Bookmark keys: See \fBNNN_BMS\fR under \fBENVIRONMENT\fR section on how to set
    bookmark keys.

    The select bookmark key \fBb\fR lists all the bookmark keys set in \fBNNN_BMS\fR
    in the bookmarks prompt.
.Pp
(2) Symlinked bookmarks: A symlinked bookmark to the current directory can
    be created with the \fBB\fR key (or manually under ~/.config/nnn/bookmarks).

    Pressing \fBEnter\fR at the bookmarks prompt takes to this directory.
    If \fBNNN_BMS\fR is not set, the select bookmark key directly opens it.
.Pp
On entering a bookmark, the directory where the select bookmark key was
pressed is set as the previous directory. Press \fB-\fR to return to it.
.Pp
.Sh UNITS
The minimum file size unit is byte (B). The rest are K, M, G, T, P, E, Z, Y
(powers of 1024), same as the default units in \fBls\fR.
.Sh ENVIRONMENT
The SHELL, VISUAL (else EDITOR) and PAGER environment variables are
used. A single combination of arguments is supported for SHELL and PAGER.
.Pp
\fBNNN_OPTS:\fR binary options to
.Nm
.Bd -literal
    export NNN_OPTS="cEnrx"
.Ed
.Pp
\fBNNN_OPENER:\fR specify a custom file opener.
.Bd -literal
    export NNN_OPENER=nuke

    NOTE: \fBnuke\fR is a file opener available in the plugin repository.
.Ed
.Pp
\fBNNN_BMS:\fR bookmark string as \fIkey_char:location\fR pairs
separated by \fB;\fR:
.Bd -literal
    export NNN_BMS="d:$HOME/Docs;u:/home/user/Cam Uploads;D:$HOME/Downloads/"
.Ed
.Pp
These bookmarks are listed in the help and config screen (key \fB?\fR).
.Pp
\fBNNN_PLUG:\fR directly executable plugins as \fIkey_char:plugin\fR pairs
separated by \fB;\fR:
.Bd -literal
    export NNN_PLUG='f:finder;o:fzopen;p:mocplay;d:diffs;t:nmount;v:imgview'

    NOTES:
    1. To run a plugin directly, press \fB;\fR followed by the key.
    2. Alternatively, combine with \fBAlt\fR (i.e. \fBAlt+key\fR).
    3. To skip directory refresh after running a plugin, prefix with \fB-\fR.

    export NNN_PLUG='p:-plugin'
.Ed
.Pp
    To assign keys to arbitrary non-background cli commands and invoke like
    plugins, add \fB!\fR before the command.
.Bd -literal
    export NNN_PLUG='x:!chmod +x "$nnn";g:!git log;s:!smplayer "$nnn"'

    To pick and run an unassigned plugin, press \fBEnter\fR at the plugin prompt.
    To run a plugin at startup, use the option `-P` followed by the plugin key.

    NOTES:
    1. Place $nnn (or exported variables) in double quotes (\fB"$nnn"\fR)
    2. Use single quotes for $NNN_PLUG so "$nnn" is not interpreted
    3. (Again) add \fB!\fR before the command
    4. To disable directory refresh after running a \fIcommand as plugin\fR,
       prefix with \fB-!\fR
    5. To skip user confirmation after command execution, suffix with \fB*\fR
       Note: Do not use \fB*\fR with programs those run and exit e.g. cat

        export NNN_PLUG='y:-!sync*'

    6. To run a \fIGUI app as plugin\fR, add a \fB&\fR after \fB!\fR.

        export NNN_PLUG='m:-!&mousepad "$nnn"'

    7. To show the output of run-and-exit commands which do not need user input,
       add \fB|\fR (pipe) after \fB!\fR
       Note: This option is incompatible with \fB&\fR (terminal output is masked
       for GUI programs) and ignores \fB*\fR (output is already paged for user).

        export NNN_PLUG='m:-!|mediainfo "$nnn";t:-!|tree -ps;l:-!|ls -lah --group-directories-first'

    8. To show the output of run-and-exit commands in a floating window,
       add \fB>\fR (right arrow) after \fB!\fR
       Note: This option is incompatible with \fB&\fR (terminal output is masked
       for GUI programs) and ignores \fB*\fR (output is rendered in a floating
       window).
       Option `-` is ignored with this option. The directory is always refreshed.

        export NNN_PLUG='m:!>mediainfo "$nnn";t:!>tree -ps;l:!>ls -lah --group-directories-first'

    EXAMPLES:
    ------------------------------------ + -------------------------------------------------
                Key:Command              |                   Description
    ------------------------------------ + -------------------------------------------------
    c:!convert "$nnn" png:- | xclip      | Copy image to clipboard
       -sel clipboard -t image/png*      |
    C:!cp -rv "$nnn" "$nnn".cp*          | Create a copy of the hovered file
    e:-!sudo -E vim "$nnn"*              | Edit file as root in vim
    g:-!git diff                         | Show git diff
    h:-!hx "$nnn"*                       | Open hovered file in hx hex editor
    k:-!fuser -kiv "$nnn"*               | Interactively kill process(es) using hovered file
    l:-!git log                          | Show git log
    n:-!vi /home/user/Dropbox/dir/note*  | Take quick notes in a synced file/dir of notes
    p:-!less -iR "$nnn"*                 | Page through hovered file in less
    s:-!&smplayer -minigui "$nnn"        | Play hovered media file, even unfinished download
    x:!chmod +x "$nnn"                   | Make the hovered file executable
    y:-!sync*                            | Flush cached writes
    ------------------------------------ + -------------------------------------------------

    Online docs: https://github.com/jarun/nnn/tree/master/plugins
.Ed
.Pp
\fBNNN_ORDER:\fR directory-specific sort key.
.Bd -literal
    export NNN_ORDER='t:/home/user/Downloads;S:/tmp'

    NOTE: Sort keys can be a/d/e/r/s/t/v (refer to the \fBSORTING\fR section).
          Path must be absolute.

          Timestamps for entries modified/created within 5 minutes are shown in reverse.
.Ed
.Pp
\fBNNN_COLORS:\fR string of color numbers for each context, e.g.:
.Bd -literal
    # 8 color numbers:
    # 0-black, 1-red, 2-green, 3-yellow, 4-blue (default), 5-magenta, 6-cyan, 7-white
    export NNN_COLORS='12341234'

    # xterm 256 color numbers (converted to hex, 2 symbols per context):
    # see https://user-images.githubusercontent.com/1482942/93023823-46a6ba80-f5e1-11ea-9ea3-6a3c757704f4.png
    export NNN_COLORS='#0a1b2c3d0a1b2c3d'

    # both (256 followed by 8 as fallback, separated by ';')
    export NNN_COLORS='#0a1b2c3d0a1b2c3d;12341234'

    NOTE: If only 256 colors are specified and the terminal doesn't support, default is used.
.Ed
.Pp
\fBNNN_FCOLORS:\fR specify file-type specific colors:
.Bd -literal
    export NNN_FCOLORS='c1e2272e006033f7c6d6abc4'

    Specify file-specific colors in xterm 256 color hex numbers (2 symbols per color).
    Order is strict, use 00 to omit/use default terminal color. Defaults:

    ------------------------- + --- + -------------
              Order           | Hex |    Color
    ------------------------- + --- + -------------
    Block device              | c1  | DarkSeaGreen1
    Char device               | e2  | Yellow1
    Directory                 | 27  | DeepSkyBlue1
    Executable                | 2e  | Green1
    Regular                   | 00  | Normal
    Hard link                 | 60  | Plum4
    Symbolic link             | 33  | Cyan1
    Missing OR file details   | f7  | Grey62
    Orphaned symbolic link    | c6  | DeepPink1
    FIFO                      | d6  | Orange1
    Socket                    | ab  | MediumOrchid1
    Unknown OR 0B regular/exe | c4  | Red1
    ------------------------- + --- + -------------

    If the terminal supports xterm 256 colors or more, file-specific colors will be rendered.
    To force the 8-color scheme use option -C.
    If xterm 256 colors aren't supported, 8-color scheme will be used.
.Ed
.Pp
\fBNNN_ARCHIVE:\fR archive extensions to be handled silently (default: bzip2, (g)zip, tar).
.Bd -literal
    export NNN_ARCHIVE="\\\\.(7z|bz2|gz|tar|tgz|zip)$"

    NOTE: Non-default formats may require a third-party utility.
.Ed
.Pp
\fBNNN_ARCHMNT:\fR optional archive mounter utility (default: archivemount).
.Bd -literal
    export NNN_ARCHIVE='fuse-archive'
.Ed
.Pp
\fBNNN_SSHFS:\fR specify custom sshfs command with options:
.Bd -literal
    export NNN_SSHFS='sshfs -o reconnect,idmap=user,cache_timeout=3600'

    NOTE: The options must be comma-separated without any space between them.
.Ed
.Pp
\fBNNN_RCLONE:\fR pass additional options to rclone command:
.Bd -literal
    export NNN_RCLONE='rclone mount --read-only --no-checksum'

    NOTE: The options must be preceded by "rclone" and max 5 flags are supported.
.Ed
.Pp
\fBNNN_TRASH:\fR trash (instead of \fBrm -rf\fR) files to desktop Trash.
.Bd -literal
    export NNN_TRASH=cmd

    NOTES:
    1. \fBcmd\fR is the name/path of the binary that nnn will call for
       trashing files. E.g to use macOS's native `trash' command:
       export NNN_TRASH="trash"
    2. Special value "1" and "2" for cmd will use trash-cli and
       gio trash respectively.
.Ed
.Pp
\fBNNN_SEL:\fR absolute path to custom selection file.
.Bd -literal
    export NNN_SEL='/tmp/.sel'
.Ed
.Pp
\fBNNN_FIFO:\fR path of a named pipe to write the hovered file path:
.Bd -literal
    export NNN_FIFO='/tmp/nnn.fifo'

    NOTES:
    1. Overridden by a temporary path with -a option.
    2. If the FIFO file doesn't exist it will be created,
       but not removed (unless it is generated by -a option).

    Online docs: https://github.com/jarun/nnn/wiki/Live-previews
.Ed
.Pp
\fBNNN_LOCKER:\fR terminal locker program.
.Bd -literal
    export NNN_LOCKER='bmon -p wlp1s0'
    export NNN_LOCKER='cmatrix'
.Ed
.Pp
\fBNNN_TMPFILE:\fR \fIalways\fR cd on quit and write the command in the file specified.
.Bd -literal
    export NNN_TMPFILE='/tmp/.lastd'
.Ed
.Pp
\fBNNN_HELP:\fR run a program and show the output on top of the program help page.
.Bd -literal
    export NNN_HELP='fortune'
.Ed
.Pp
\fBNNN_MCLICK:\fR key emulated by a middle mouse click.
.Bd -literal
    export NNN_MCLICK='^R'

    NOTE: Only the first character is considered if not a \fBCtrl+key\fR combo.
.Ed
.Pp
\fBnnn:\fR this is a special variable.
.Bd -literal
    Set to the hovered file name before starting the command prompt or spawning a shell.
.Ed
.Pp
\fBNO_COLOR:\fR disable ANSI color output (overridden by \fBNNN_COLORS\fR).
.Sh AUTHORS
.An Arun Prakash Jana Aq Mt engineerarun@gmail.com ,
.An Lazaros Koromilas Aq Mt lostd@2f30.org ,
.An Dimitris Papastamos Aq Mt sin@2f30.org .
.Sh HOME
.Em https://github.com/jarun/nnn


================================================
FILE: patches/README.md
================================================
<h1 align="center">User Patch Framework</h1>

This directory contains sizable user submitted patches that were rejected from mainline as they tend to be more subjective in nature.

The patches will be adapted on each release when necessary (v4.1 onwards). Each patch can be applied through its respective make variable during compilation. In case inter-patch merge conflicts occur, a compatibility patch is provided and will automatically be applied.

## List of patches

| Patch (a-z) | Description | Make var |
| --- | --- | --- |
| colemak | Key bindings for Colemak keyboard layout | `O_COLEMAK` |
| gitstatus | Add git status column to the detail view. Provides command line flag `-G` to show column in normal mode. | `O_GITSTATUS` |
| namefirst | Print filenames first in the detail view. Print user/group columns when a directory contains different users/groups. | `O_NAMEFIRST` |
| restorepreview | Add pipe to close and restore [`preview-tui`](https://github.com/jarun/nnn/blob/master/plugins/preview-tui) for internal undetached edits (<kbd>e</kbd> key)| `O_RESTOREPREVIEW` |

To apply a patch, use the corresponding make variable, e.g.:

    make O_NAMEFIRST=1

When contributing/adding a new patch, make sure to add the make variable to the patches array in `./misc/test/check-patches.sh` as well so that patch failures can be easily tested.

## Resolving patch conflicts

Patch conflicts can be checked locally by running `make checkpatches` or by running `./patches/check-patches.sh` manually.

Whenever patch conflicts occur on the latest master, pull requests resolving them are welcome. Let's say a conflict occurs in the `restorepreview` patch. The best way to resolve this conflict would be something along the lines of:

- Ensure you're on latest master and run `PATCH_OPTS="--merge" make O_RESTOREPREVIEW=1`. This will generate the conflict markers in `src/nnn.c`.
- Next edit `src/nnn.c`, resolve the conflicts around the conflict markers(`<<<<<<<`), and save.
- Then run `git diff > patch.diff && sed -i -e "/^$/{r patch.diff" -e "q;}" patches/restorepreview/mainline.diff` to update the patch.


================================================
FILE: patches/check-patches.sh
================================================
#!/bin/bash
#
# Usage: ./misc/test/check-patches.sh
#
# Bash script that checks for any of the patches failing to apply.
# Read patches/README.md for more information.

export PATCH_OPTS="--merge"
patches=("O_COLEMAK" "O_GITSTATUS" "O_NAMEFIRST" "O_RESTOREPREVIEW")
z=$(( 1 << ${#patches[@]} ))
pid=$$
ret=0
trap 'ret=1' SIGUSR1

for ((n=1; n < z; ++n)); do
    for ((i=0; i < ${#patches[@]}; ++i)); do
        printf "%s=%d " "${patches[$i]}" "$(( (n & (1 << i)) != 0 ))"
    done | tee "/dev/stderr" | (
        make clean -s
        if ! xargs make 2>&1; then
            echo "[FAILED]" >&2
            kill -SIGUSR1 "$pid"
        else
            echo "[SUCCESS]" >&2
        fi
        git restore src
    ) >/dev/null
done
exit "$ret"


================================================
FILE: patches/colemak/mainline.diff
================================================
diff --git a/src/nnn.c b/src/nnn.c
index d7c53166..bb7ff3e8 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -5149,12 +5149,12 @@ static void show_help(const char *path)
 	"2(___n))\n"
 	"0\n"
 	"1NAVIGATION\n"
-	       "9Up k  Prev%14PgUp ^U  Page up\n"
-	       "9Dn j  Next%14PgDn ^D  Page down\n"
+	       "9Up e  Prev%14PgUp ^U  Page up\n"
+	       "9Dn n  Next%14PgDn ^D  Page down\n"
 	       "9Lt h  Parent%12~ ` @ -  ~, /, start, prev\n"
-	   "5Ret Rt l  Open%20'  First file/match\n"
-	       "9g ^A  Top%21J  Jump to entry/offset\n"
-	       "9G ^E  End%20^J  Toggle auto-advance on open\n"
+	   "5Ret Rt i  Open%20'  First file/match\n"
+	       "9g ^E  Top%21J  Jump to entry/offset\n"
+	       "9G ^N  End%20^J  Toggle auto-advance on open\n"
 	      "8B (,)  Book(mark)%11b ^/  Select bookmark\n"
 		"a1-4  Context%11(Sh)Tab  Cycle/new context\n"
 	    "62Esc ^Q  Quit%19^y  Next young\n"
@@ -5162,27 +5162,27 @@ static void show_help(const char *path)
 		  "cq  Quit context\n"
 	"0\n"
 	"1FILTER & PROMPT\n"
-		  "c/  Filter%17^N  Toggle type-to-nav\n"
+		  "c/  Filter%17^K  Toggle type-to-nav\n"
 		"aEsc  Exit prompt%12^L  Toggle last filter\n"
 		  "c.  Toggle hidden%05Alt+Esc  Unfilter, quit context\n"
 	"0\n"
 	"1FILES\n"
-	       "9o ^O  Open with%15n  Create new/link\n"
+	       "9o ^O  Open with%15c  Create new/link\n"
 	       "9f ^F  File stats%14d  Detail mode toggle\n"
 		 "b^R  Rename/dup%14r  Batch rename\n"
-		  "cz  Archive%17e  Edit file\n"
+		  "cz  Archive%17y  Edit file\n"
 		  "c*  Toggle exe%14>  Export list\n"
 	    "6Space +  (Un)select%12m-m  Select range/clear\n"
 	          "ca  Select all%14A  Invert sel\n"
 	       "9p ^P  Copy here%12w ^W  Cp/mv sel as\n"
-	       "9v ^V  Move here%15E  Edit sel list\n"
+	       "9v ^V  Move here%15l  Edit sel list\n"
 	       "9x ^X  Delete or trash%09S  Listed sel size\n"
 		  "cX  Delete (rm -rf)%07Esc  Send to FIFO\n"
 	"0\n"
 	"1MISC\n"
 	      "8Alt ;  Select plugin%11=  Launch app\n"
 	       "9! ^]  Shell%19]  Cmd prompt\n"
-		  "cc  Connect remote%10u  Unmount remote/archive\n"
+		  "cC  Connect remote%10u  Unmount remote/archive\n"
 	       "9t ^T  Sort toggles%12s  Manage session\n"
 		  "cT  Set time type%110  Lock\n"
 		 "b^L  Redraw%18?  Help, conf\n"
diff --git a/src/nnn.h b/src/nnn.h
index bd500244..43b7fa22 100644
--- a/src/nnn.h
+++ b/src/nnn.h
@@ -139,12 +139,12 @@ static struct key bindings[] = {
 	{ '\r',           SEL_OPEN },
 	/* Pure navigate inside */
 	{ KEY_RIGHT,      SEL_NAV_IN },
-	{ 'l',            SEL_NAV_IN },
+	{ 'i',            SEL_NAV_IN },
 	/* Next */
-	{ 'j',            SEL_NEXT },
+	{ 'n',            SEL_NEXT },
 	{ KEY_DOWN,       SEL_NEXT },
 	/* Previous */
-	{ 'k',            SEL_PREV },
+	{ 'e',            SEL_PREV },
 	{ KEY_UP,         SEL_PREV },
 	/* Page down */
 	{ KEY_NPAGE,      SEL_PGDN },
@@ -157,11 +157,11 @@ static struct key bindings[] = {
 	/* First entry */
 	{ KEY_HOME,       SEL_HOME },
 	{ 'g',            SEL_HOME },
-	{ CONTROL('A'),   SEL_HOME },
+	{ CONTROL('E'),   SEL_HOME },
 	/* Last entry */
 	{ KEY_END,        SEL_END },
 	{ 'G',            SEL_END },
-	{ CONTROL('E'),   SEL_END },
+	{ CONTROL('N'),   SEL_END },
 	/* Go to first file */
 	{ '\'',           SEL_FIRST },
 	/* Jump to an entry number/offset */
@@ -179,7 +179,7 @@ static struct key bindings[] = {
 	{ 'b',            SEL_BMOPEN },
 	{ CONTROL('_'),   SEL_BMOPEN },
 	/* Connect to server over SSHFS */
-	{ 'c',            SEL_REMOTE },
+	{ 'C',            SEL_REMOTE },
 	/* Cycle contexts in forward direction */
 	{ '\t',           SEL_CYCLE },
 	/* Cycle contexts in reverse direction */
@@ -202,7 +202,7 @@ static struct key bindings[] = {
 	/* Filter */
 	{ '/',            SEL_FLTR },
 	/* Toggle filter mode */
-	{ CONTROL('N'),   SEL_MFLTR },
+	{ CONTROL('K'),   SEL_MFLTR },
 	/* Toggle hide .dot files */
 	{ '.',            SEL_HIDDEN },
 	/* Detailed listing */
@@ -229,7 +229,7 @@ static struct key bindings[] = {
 	/* Invert selection in current dir */
 	{ 'A',            SEL_SELINV },
 	/* List, edit selection */
-	{ 'E',            SEL_SELEDIT },
+	{ 'l',            SEL_SELEDIT },
 	/* Copy from selection buffer */
 	{ 'p',            SEL_CP },
 	{ CONTROL('P'),   SEL_CP },
@@ -247,7 +247,7 @@ static struct key bindings[] = {
 	{ 'o',            SEL_OPENWITH },
 	{ CONTROL('O'),   SEL_OPENWITH },
 	/* Create a new file */
-	{ 'n',            SEL_NEW },
+	{ 'c',            SEL_NEW },
 	/* Show rename prompt */
 	{ CONTROL('R'),   SEL_RENAME },
 	/* Rename contents of current dir */
@@ -259,7 +259,7 @@ static struct key bindings[] = {
 	/* Toggle auto-advance on file open */
 	{ CONTROL('J'),   SEL_AUTONEXT },
 	/* Edit in EDITOR */
-	{ 'e',            SEL_EDIT },
+	{ 'y',            SEL_EDIT },
 	/* Run a plugin */
 	{ ';',            SEL_PLUGIN },
 	/* Show total size of listed selection */


================================================
FILE: patches/gitstatus/mainline.diff
================================================
# Description: Add git status column to detail mode. Provides additional
#              command line flag -G which will render the git status
#              column also in normal mode. Vim plugin users may consider
#              adding the -G flag to their command override.
#
# Authors: Luuk van Baal

diff --git a/src/nnn.c b/src/nnn.c
index 936e9c02..22032dcd 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -286,6 +286,25 @@
 #define VFS_USED  1
 #define VFS_SIZE  2

+/* Git icons */
+#ifdef NERD
+#define GIT_ADD ""
+#define GIT_DEL ""
+#define GIT_IGN ""
+#define GIT_MOD ""
+#define GIT_NEW ""
+#define GIT_NON "-"
+#define GIT_UPD "󰚰"
+#else
+#define GIT_ADD "A"
+#define GIT_DEL "D"
+#define GIT_IGN "!"
+#define GIT_MOD "M"
+#define GIT_NEW "?"
+#define GIT_NON "-"
+#define GIT_UPD "U"
+#endif
+
 /* TYPE DEFINITIONS */
 typedef unsigned int uint_t;
 typedef unsigned char uchar_t;
@@ -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 */
@@ -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) */
@@ -418,7 +439,17 @@ typedef struct {
 } session_header_t;
 #endif

+typedef struct {
+	char status[2];
+	char path[PATH_MAX];
+} git_status_t;
+
 /* GLOBALS */
+struct {
+	bool show;
+	size_t len;
+	git_status_t *statuses;
+} git_statuses;

 /* Configuration, contexts */
 static settings cfg = {
@@ -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";
+	FILE *fp = popen(gst, "r");
+	char status[PATH_MAX];
+	size_t pathindex, i = -1;
+	git_statuses.show = FALSE;
+
+	while (fgets(status, PATH_MAX, fp)) {
+		pathindex = (status[3] == '"') ? 4 : 3;
+		if (!cfg.showhidden && status[pathindex] == '.')
+			continue;
+		status[xstrlen(status) - pathindex + 2] = '\0';
+		git_statuses.statuses = xrealloc(git_statuses.statuses, sizeof(git_status_t) * (++i + 1));
+		git_statuses.statuses[i].status[0] = status[0];
+		git_statuses.statuses[i].status[1] = status[1];
+		mkpath(path, status + pathindex, git_statuses.statuses[i].path);
+	}
+
+	pclose(fp);
+	return (i + 1);
+}
+
+static void set_git_status(char status[][5], uint_t nr)
+{
+	for (int j = 0; j < 2; j++) {
+		if (status[j][0] == '-')
+			switch (git_statuses.statuses[nr].status[j]) {
+				case ' ': xstrsncpy(status[j], GIT_NON, 4); break;
+				case 'M': xstrsncpy(status[j], GIT_MOD, 4); break;
+				case 'A': xstrsncpy(status[j], GIT_ADD, 4); break;
+				case '?': xstrsncpy(status[j], GIT_NEW, 4); break;
+				case '!': xstrsncpy(status[j], GIT_IGN, 4); break;
+				case 'D': xstrsncpy(status[j], GIT_DEL, 4); break;
+				case 'U': xstrsncpy(status[j], GIT_UPD, 4); break;
+			}
+	}
+	if (git_statuses.statuses[nr].status[1] != '!')
+		git_statuses.show = TRUE;
+}
+
 static void resetdircolor(int flags)
 {
 	/* Directories are always shown on top, clear the color when moving to first file */
@@ -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)
@@ -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))
+			printwarn(NULL);
+
 #if _POSIX_C_SOURCE >= 200112L
 	posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
 #endif
@@ -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);
+			dentp->git_status[0][0] = dentp->git_status[1][0] = '-';
+			dentp->git_status[0][1] = dentp->git_status[1][1] = '\0';
+
+			if (dentp->flags & DIR_OR_DIRLNK) {
+				char prefix[PATH_MAX];
+				memccpy(prefix, dentpath, '\0', PATH_MAX);
+				prefix[pathlen - 1] = '/';
+
+				for (size_t i = 0; i < git_statuses.len; ++i)
+					if (is_prefix(git_statuses.statuses[i].path, prefix, pathlen))
+						set_git_status(dentp->git_status, i);
+			} else {
+				for (size_t i = 0; i < git_statuses.len; ++i)
+					if (!xstrcmp(git_statuses.statuses[i].path, dentpath)) {
+						set_git_status(dentp->git_status, i);
+						break;
+					}
+			}
+		}
+
 		++ndents;
 	} while ((dp = readdir(dirp)));

@@ -6569,11 +6673,12 @@ static int adjust_cols(int n)
 #endif
 	if (cfg.showdetail) {
 		/* Fallback to light mode if less than 35 columns */
-		if (n < 36)
+		if (n < 38)
 			cfg.showdetail ^= 1;
 		else /* 2 more accounted for below */
-			n -= 32;
-	}
+			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);
@@ -8401,6 +8506,7 @@ static void usage(void)
 		" -F val  fifo mode [0:preview 1:explore]\n"
 #endif
 		" -g      regex filters\n"
+		" -G      always show git status\n"
 		" -H      show hidden files\n"
 		" -i      show current file info\n"
 		" -J      no auto-advance on selection\n"
@@ -8544,6 +8650,7 @@ static void cleanup(void)
 		fflush(stdout);
 	}
 #endif
+	free(git_statuses.statuses);
 	free(selpath);
 	free(plgpath);
 	free(cfgpath);
@@ -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:uUVxz0h"))) != -1) {
+		       : getopt(argc, argv, "aAb:BcCdDeEfF:gGHiJKl:nNop:P:QrRs:St:T:uUVxz0h"))) != -1) {
 		switch (opt) {
 #ifndef NOFIFO
 		case 'a':
@@ -8643,6 +8750,9 @@ int main(int argc, char *argv[])
 			cfg.regex = 1;
 			filterfn = &visible_re;
 			break;
+		case 'G':
+			cfg.normalgit = 1;
+			break;
 		case 'H':
 			cfg.showhidden = 1;
 			break;


================================================
FILE: patches/gitstatus/namefirst.diff
================================================
# Description: Add git status column to detail mode. Provides additional
#              command line flag -G which will render the git status
#              column also in normal mode. Vim plugin users may consider
#              adding the -G flag to their command override.
#              Compatibility patch for the namefirst patch.
#
# Authors: Luuk van Baal
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -298,6 +298,25 @@
 #define VFS_USED  1
 #define VFS_SIZE  2
 
+/* Git icons */
+#ifdef NERD
+#define GIT_ADD ""
+#define GIT_DEL ""
+#define GIT_IGN ""
+#define GIT_MOD ""
+#define GIT_NEW ""
+#define GIT_NON "-"
+#define GIT_UPD "󰚰"
+#else
+#define GIT_ADD "A"
+#define GIT_DEL "D"
+#define GIT_IGN "!"
+#define GIT_MOD "M"
+#define GIT_NEW "?"
+#define GIT_NON "-"
+#define GIT_UPD "U"
+#endif
+
 /* TYPE DEFINITIONS */
 typedef unsigned int uint_t;
 typedef unsigned char uchar_t;
@@ -322,6 +341,7 @@
 	uid_t uid; /* 4 bytes */
 	gid_t gid; /* 4 bytes */
 #endif
+	char git_status[2][5];
 } *pEntry;
 
 /* Selection marker */
@@ -378,6 +398,7 @@
 	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) */
@@ -434,7 +455,17 @@
 	ushort_t maxnameln, maxsizeln, maxuidln, maxgidln, maxentln, uidln, gidln, printguid;
 } dtls;
 
+typedef struct {
+	char status[2];
+	char path[PATH_MAX];
+} git_status_t;
+
 /* GLOBALS */
+struct {
+	bool show;
+	size_t len;
+	git_status_t *statuses;
+} git_statuses;
 
 /* Configuration, contexts */
 static settings cfg = {
@@ -4341,6 +4372,47 @@
 	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";
+	FILE *fp = popen(gst, "r");
+	char status[PATH_MAX];
+	size_t pathindex, i = -1;
+	git_statuses.show = FALSE;
+
+	while (fgets(status, PATH_MAX, fp)) {
+		pathindex = (status[3] == '"') ? 4 : 3;
+		if (!cfg.showhidden && status[pathindex] == '.')
+			continue;
+		status[xstrlen(status) - pathindex + 2] = '\0';
+		git_statuses.statuses = xrealloc(git_statuses.statuses, sizeof(git_status_t) * (++i + 1));
+		git_statuses.statuses[i].status[0] = status[0];
+		git_statuses.statuses[i].status[1] = status[1];
+		mkpath(path, status + pathindex, git_statuses.statuses[i].path);
+	}
+
+	pclose(fp);
+	return (i + 1);
+}
+
+static void set_git_status(char status[][5], uint_t nr)
+{
+	for (int j = 0; j < 2; j++) {
+		if (status[j][0] == '-')
+			switch (git_statuses.statuses[nr].status[j]) {
+				case ' ': xstrsncpy(status[j], GIT_NON, 4); break;
+				case 'M': xstrsncpy(status[j], GIT_MOD, 4); break;
+				case 'A': xstrsncpy(status[j], GIT_ADD, 4); break;
+				case '?': xstrsncpy(status[j], GIT_NEW, 4); break;
+				case '!': xstrsncpy(status[j], GIT_IGN, 4); break;
+				case 'D': xstrsncpy(status[j], GIT_DEL, 4); break;
+				case 'U': xstrsncpy(status[j], GIT_UPD, 4); break;
+			}
+	}
+	if (git_statuses.statuses[nr].status[1] != '!')
+		git_statuses.show = TRUE;
+}
+
 static void resetdircolor(int flags)
 {
 	/* Directories are always shown on top, clear the color when moving to first file */
@@ -4765,6 +4837,10 @@
 
 	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)
@@ -6917,6 +6993,11 @@
 		attron(COLOR_PAIR(cfg.curctx + 1));
 	}
 
+	char linkpath[PATH_MAX];
+	if ((git_statuses.len = get_git_statuses(path)))
+		if (!realpath(path, linkpath))
+			printwarn(NULL);
+
 #if _POSIX_C_SOURCE >= 200112L
 	posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
 #endif
@@ -7141,6 +7222,29 @@
 #endif
 		}
 
+		if (git_statuses.len) {
+			char dentpath[PATH_MAX];
+			size_t pathlen = mkpath(linkpath, dentp->name, dentpath);
+			dentp->git_status[0][0] = dentp->git_status[1][0] = '-';
+			dentp->git_status[0][1] = dentp->git_status[1][1] = '\0';
+
+			if (dentp->flags & DIR_OR_DIRLNK) {
+				char prefix[PATH_MAX];
+				memccpy(prefix, dentpath, '\0', PATH_MAX);
+				prefix[pathlen - 1] = '/';
+
+				for (size_t i = 0; i < git_statuses.len; ++i)
+					if (is_prefix(git_statuses.statuses[i].path, prefix, pathlen))
+						set_git_status(dentp->git_status, i);
+			} else {
+				for (size_t i = 0; i < git_statuses.len; ++i)
+					if (!xstrcmp(git_statuses.statuses[i].path, dentpath)) {
+						set_git_status(dentp->git_status, i);
+						break;
+					}
+			}
+		}
+
 		++ndents;
 	} while ((dp = readdir(dirp)));
 
@@ -7715,7 +7819,8 @@
 			cfg.showdetail ^= 1;
 		else /* 2 more accounted for below */
 			n -= (dtls.maxentln - 2 - dtls.maxnameln);
-	}
+	} else if (cfg.normalgit && git_statuses.show)
+		n -= 3;
 
 	/* 2 columns for preceding space and indicator */
 	return (n - 2);
@@ -9576,6 +9681,7 @@
 		" -F val  fifo mode [0:preview 1:explore]\n"
 #endif
 		" -g      regex filters\n"
+		" -G      always show git status\n"
 		" -H      show hidden files\n"
 		" -i      show current file info\n"
 		" -J      no auto-advance on selection\n"
@@ -9720,6 +9826,7 @@
 		fflush(stdout);
 	}
 #endif
+	free(git_statuses.statuses);
 	free(selpath);
 	free(plgpath);
 	free(cfgpath);
@@ -9765,7 +9872,7 @@
 
 	while ((opt = (env_opts_id > 0
 		       ? env_opts[--env_opts_id]
-		       : getopt(argc, argv, "aAb:BcCdDeEfF:gHiJKl:nNop:P:QrRs:St:T:uUVxz0h"))) != -1) {
+		       : getopt(argc, argv, "aAb:BcCdDeEfF:gGHiJKl:nNop:P:QrRs:St:T:uUVxz0h"))) != -1) {
 		switch (opt) {
 #ifndef NOFIFO
 		case 'a':
@@ -9819,6 +9926,9 @@
 			cfg.regex = 1;
 			filterfn = &visible_re;
 			break;
+		case 'G':
+			cfg.normalgit = 1;
+			break;
 		case 'H':
 			cfg.showhidden = 1;
 			break;


================================================
FILE: patches/namefirst/mainline.diff
================================================
# Description: Prints filenames first in the detail view.  Prints user/group
#              columns when a directory contains different users/groups.
#
# Author: Luuk van Baal

diff --git a/src/nnn.c b/src/nnn.c
index 19ebc2cf..42a0a6b0 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -430,6 +430,10 @@ typedef struct {
 } session_header_t;
 #endif

+static struct {
+	ushort_t maxnameln, maxsizeln, maxuidln, maxgidln, maxentln, uidln, gidln, printguid;
+} dtls;
+
 /* GLOBALS */

 /* Configuration, contexts */
@@ -1175,10 +1179,13 @@ static char *getpwname(uid_t uid)
 	static char *namecache;

 	if (uidcache != uid) {
+		if (dtls.maxuidln && !dtls.printguid)
+			dtls.printguid = 1;
 		struct passwd *pw = getpwuid(uid);

 		uidcache = uid;
 		namecache = pw ? pw->pw_name : NULL;
+		dtls.uidln = xstrlen(namecache ? namecache : xitoa(uid));
 	}

 	return namecache ? namecache : xitoa(uid);
@@ -1190,10 +1197,13 @@ static char *getgrname(gid_t gid)
 	static char *grpcache;

 	if (gidcache != gid) {
+		if (dtls.maxgidln && !dtls.printguid)
+			dtls.printguid = 1;
 		struct group *gr = getgrgid(gid);

 		gidcache = gid;
 		grpcache = gr ? gr->gr_name : NULL;
+		dtls.gidln = xstrlen(grpcache ? grpcache : xitoa(gid));
 	}

 	return grpcache ? grpcache : xitoa(gid);
@@ -4346,14 +4356,13 @@ static void resetdircolor(int flags)
  * Max supported str length: NAME_MAX;
  */
 #ifdef NOLC
-static char *unescape(const char *str, uint_t maxcols)
+static size_t unescape(const char *str, uint_t maxcols)
 {
 	char * const wbuf = g_buf;
 	char *buf = wbuf;
-
-	xstrsncpy(wbuf, str, maxcols);
+	size_t len = xstrsncpy(wbuf, str, maxcols);
 #else
-static wchar_t *unescape(const char *str, uint_t maxcols)
+static size_t unescape(const char *str, uint_t maxcols)
 {
 	wchar_t * const wbuf = (wchar_t *)g_buf;
 	wchar_t *buf = wbuf;
@@ -4378,7 +4387,7 @@ static wchar_t *unescape(const char *str, uint_t maxcols)
 		++buf;
 	}

-	return wbuf;
+	return len;
 }

 static off_t get_size(off_t size, off_t *pval, int comp)
@@ -4627,9 +4636,10 @@ static uchar_t get_color_pair_name_ind(const struct entry *ent, char *pind, int
 }

 #ifdef DIM_FILTERED
-static void printent_name(const struct entry *ent, uint_t namecols)
+static size_t printent_name(const struct entry *ent, uint_t namecols)
 {
 	char * const fltr = g_ctx[cfg.curctx].c_fltr;
+	size_t namelen;

 	/* If there's a filter string, dim matching characters */
 	if (fltr[1]) {
@@ -4644,15 +4654,18 @@ static void printent_name(const struct entry *ent, uint_t namecols)
 		if (cfg.regex) {
 			/* For regex, we don't dim - just print normally */
 #ifndef NOLC
-			addwstr(unescape(ent->name, namecols));
+			namelen = unescape(ent->name, namecols);
+			addwstr((wchar_t *)g_buf);
 #else
-			addstr(unescape(ent->name, MIN(namecols, ent->nlen) + 1));
+			namelen = unescape(ent->name, MIN(namecols, ent->nlen) + 1);
+			addstr((char *)g_buf);
 #endif
 		} else if (cfg.fuzzy) {
 			/* Get fuzzy match positions */
 			fuzzy_match_positions(fltr + 1, ent->name, matched);
 #ifndef NOLC
-			wchar_t * const wbuf = unescape(ent->name, namecols);
+			namelen = unescape(ent->name, namecols);
+			wchar_t * const wbuf = (wchar_t *)g_buf;
 			uint_t col = 0;
 			for (wchar_t *p = wbuf; *p && col < namecols; ++p, ++col) {
 				if (matched[col]) {
@@ -4665,7 +4678,8 @@ static void printent_name(const struct entry *ent, uint_t namecols)
 			}
 #else
 			/* Non-wide character version for fuzzy dimming */
-			const char *name = unescape(ent->name, MIN(namecols, ent->nlen) + 1);
+			namelen = unescape(ent->name, MIN(namecols, ent->nlen) + 1);
+			const char *name = (char *)g_buf;
 			for (uint_t i = 0; (i < namecols) && name[i]; ++i) {
 				if (matched[i]) {
 					attron(match_attrs);
@@ -4680,7 +4694,8 @@ static void printent_name(const struct entry *ent, uint_t namecols)
 			/* String match - dim the substring */
 			string_match_positions(fltr + 1, ent->name, matched);
 #ifndef NOLC
-			wchar_t * const wbuf = unescape(ent->name, namecols);
+			namelen = unescape(ent->name, namecols);
+			wchar_t * const wbuf = (wchar_t *)g_buf;
 			uint_t col = 0;
 			for (wchar_t *p = wbuf; *p && col < namecols; ++p, ++col) {
 				if (matched[col]) {
@@ -4693,7 +4708,8 @@ static void printent_name(const struct entry *ent, uint_t namecols)
 			}
 #else
 			/* Non-wide character version for string dimming */
-			const char *name = unescape(ent->name, MIN(namecols, ent->nlen) + 1);
+			namelen = unescape(ent->name, MIN(namecols, ent->nlen) + 1);
+			const char *name = (char *)g_buf;
 			for (uint_t i = 0; (i < namecols) && name[i]; ++i) {
 				if (matched[i]) {
 					attron(match_attrs);
@@ -4708,22 +4724,30 @@ static void printent_name(const struct entry *ent, uint_t namecols)
 	} else {
 		/* No filter or filter not active - print normally */
 #ifndef NOLC
-		addwstr(unescape(ent->name, namecols));
+		namelen = unescape(ent->name, namecols);
+		addwstr((wchar_t *)g_buf);
 #else
-		addstr(unescape(ent->name, MIN(namecols, ent->nlen) + 1));
+		namelen = unescape(ent->name, MIN(namecols, ent->nlen) + 1);
+		addstr((char *)g_buf);
 #endif
 	}
+
+	return namelen;
 }
 #else
 /* Without dimming support, just print the name normally */
-static inline void printent_name(const struct entry *ent, uint_t namecols)
+static inline size_t printent_name(const struct entry *ent, uint_t namecols)
 {
 	(void)sel; /* Suppress unused parameter warning */
 #ifndef NOLC
-	addwstr(unescape(ent->name, namecols));
+	size_t namelen = unescape(ent->name, namecols);
+	addwstr((wchar_t *)g_buf);
 #else
-	addstr(unescape(ent->name, MIN(namecols, ent->nlen) + 1));
+	size_t namelen = unescape(ent->name, MIN(namecols, ent->nlen) + 1);
+	addstr((char *)g_buf);
 #endif
+
+	return namelen;
 }
 #endif

@@ -4731,38 +4755,14 @@ static void printent(int pdents_index, uint_t namecols)
 {
 	const struct entry *ent = &pdents[pdents_index];
 	char ind = '\0';
-	int attrs;
-
-	if (cfg.showdetail) {
-		int type = ent->mode & S_IFMT;
-		char perms[6] = {' ', ' ', (char)('0' + ((ent->mode >> 6) & 7)),
-				(char)('0' + ((ent->mode >> 3) & 7)),
-				(char)('0' + (ent->mode & 7)), '\0'};
-
-		addch(' ');
-		attrs = g_state.oldcolor ? (resetdircolor(ent->flags), A_DIM)
-					 : (fcolors[C_MIS] ? COLOR_PAIR(C_MIS) : 0);
-		if (attrs)
-			attron(attrs);
-
-		/* Print details */
-		print_time(&ent->sec, ent->flags);
-
-		printw("%s%9s ", perms, (type == S_IFREG || type == S_IFDIR)
-			? coolsize(cfg.blkorder ? (blkcnt_t)ent->blocks << blk_shift : ent->size)
-			: (type = (uchar_t)get_detail_ind(ent->mode), (char *)&type));
-
-		if (attrs)
-			attroff(attrs);
-	}
+	int attrs = 0;
+	size_t namelen;

 	if (g_state.showlines) {
 		ptrdiff_t rel_num = pdents_index - cur;
 		printw(rel_num == 0 ? "%4td" : "%+4td", rel_num);
 	}

-	attrs = 0;
-
 	uchar_t color_pair = get_color_pair_name_ind(ent, &ind, &attrs);

 	addch((ent->flags & FILE_SELECTED) ? '+' | A_REVERSE | A_BOLD : ' ');
@@ -4786,12 +4786,44 @@ static void printent(int pdents_index, uint_t namecols)
 	if (!ind)
 		++namecols;

-	printent_name(ent, namecols);
+	namelen = printent_name(ent, namecols);

-	if (attrs)
+	if (!sel && attrs)
 		attroff(attrs);
 	if (ind)
 		addch(ind);
+	if (cfg.showdetail) {
+		int type = ent->mode & S_IFMT;
+		char perms[6] = {(char)('0' + ((ent->mode >> 6) & 7)),
+				(char)('0' + ((ent->mode >> 3) & 7)),
+				(char)('0' + (ent->mode & 7)), ' ', ' ', '\0'}, *size = NULL;
+
+		if (attrs)
+			attron(attrs);
+		if (!g_state.oldcolor && (type == S_IFDIR || (type == S_IFLNK && ent->flags & DIR_OR_DIRLNK)))
+			attroff(A_BOLD);
+		int sizelen;
+		if (type == S_IFREG || type == S_IFDIR) {
+			size = coolsize(cfg.blkorder ? ent->blocks << blk_shift : ent->size);
+			sizelen = xstrlen(size);
+		} else
+			sizelen = 1;
+		printw("%*c%*s%s%s",
+			1 + MIN(namecols, dtls.maxnameln + (uint_t)(ind ? 0 : 1)) - (int)namelen, ' ',
+			dtls.maxsizeln - sizelen, "", size ? size
+			: (type = (uchar_t)get_detail_ind(ent->mode), (char *)&type), "  ");
+#ifndef NOUG
+		if (g_state.uidgid && dtls.printguid) {
+			addstr(getpwname(ent->uid));
+			printw("%*c%s", dtls.maxuidln + 1 - dtls.uidln, ' ', getgrname(ent->gid));
+			printw("%*c", dtls.maxgidln + 2 - dtls.gidln, ' ');
+		}
+#endif
+		addstr(perms);
+		print_time(&ent->sec, ent->flags);
+	}
+	if (attrs)
+		attroff(attrs);
 }

 /**
@@ -7670,26 +7702,19 @@ static void statusbar(char *path)
 	tocursor();
 }

-static inline void markhovered(void)
-{
-	if (cfg.showdetail && ndents) { /* Bold forward arrowhead */
-		tocursor();
-		addch('>' | A_BOLD);
-	}
-}
-
 static int adjust_cols(int n)
 {
 	/* Calculate the number of cols available to print entry name */
 #ifdef ICONS_ENABLED
 	n -= (g_state.oldcolor ? 0 : ICON_SIZE + ICON_PADDING_LEFT_LEN + ICON_PADDING_RIGHT_LEN);
 #endif
+
 	if (cfg.showdetail) {
 		/* Fallback to light mode if less than 35 columns */
-		if (n < 36)
+		if (n < (dtls.maxentln + 1 - dtls.maxnameln))
 			cfg.showdetail ^= 1;
 		else /* 2 more accounted for below */
-			n -= 32;
+			n -= (dtls.maxentln - 2 - dtls.maxnameln);
 	}

 	/* 2 columns for preceding space and indicator */
@@ -7728,8 +7753,6 @@ static void draw_line(int ncols)
 	/* Must reset e.g. no files in dir */
 	if (dir)
 		attroff(COLOR_PAIR(cfg.curctx + 1) | A_BOLD);
-
-	markhovered();
 }

 static void redraw(char *path)
@@ -7837,6 +7860,26 @@ static void redraw(char *path)
 	int onscreen = MIN(ONSCREEN + curscroll, ndents);
 	int len = scanselforpath(path, FALSE);

+	if (cfg.showdetail) {
+		ushort_t lenbuf = dtls.maxnameln = dtls.maxsizeln = dtls.maxuidln = dtls.maxgidln = dtls.printguid = 0;
+		for (i = curscroll; i < onscreen; ++i) {
+			if ((lenbuf = pdents[i].nlen - 1) > dtls.maxnameln)
+				dtls.maxnameln = lenbuf;
+			if ((lenbuf = xstrlen(coolsize(cfg.blkorder ? pdents[i].blocks << blk_shift : pdents[i].size))) > dtls.maxsizeln)
+				dtls.maxsizeln = lenbuf;
+#ifndef NOUG
+			if (g_state.uidgid) {
+				if ((getpwname(pdents[i].uid), dtls.uidln) > dtls.maxuidln)
+					dtls.maxuidln = dtls.uidln;
+				if ((getgrname(pdents[i].gid), dtls.gidln) > dtls.maxgidln)
+					dtls.maxgidln = dtls.gidln;
+			}
+#endif
+		}
+		dtls.maxentln = dtls.maxnameln + dtls.maxsizeln
+			+ (dtls.printguid ? (dtls.maxuidln + dtls.maxgidln + 29) : 26);
+	}
+
 	ncols = adjust_cols(ncols);

 	/* Print listing */
@@ -7865,7 +7908,7 @@ static void redraw(char *path)
 #endif
 	}

-	markhovered();
+	statusbar(path);
 }

 static bool cdprep(char *lastdir, char *lastname, char *path, char *newpath)


================================================
FILE: patches/restorepreview/mainline.diff
================================================
# Description: Adds preview pipe to enable closing and re-opening the preview
#              pane when running an undetached editor. If you are using vim
#              you might experience incorrectly resized window. Consider adding
#              the following to your vimrc:
#              autocmd VimEnter * :silent exec "!kill -s WINCH $PPID"
#
# Authors: Luuk van Baal

diff --git a/src/nnn.c b/src/nnn.c
index 9a78fb55..ca4ac0f7 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -396,7 +396,8 @@ typedef struct {
 	uint_t usebsdtar  : 1;  /* Use bsdtar as default archive utility */
 	uint_t xprompt    : 1;  /* Use native prompt instead of readline prompt */
 	uint_t showlines  : 1;  /* Show line numbers */
-	uint_t reserved   : 5;  /* Adjust when adding/removing a field */
+	uint_t previewer  : 1;  /* Run state of previewer */
+	uint_t reserved   : 4;  /* Adjust when adding/removing a field */
 } runstate;
 
 /* Contexts or workspaces */
@@ -527,6 +528,9 @@ alignas(max_align_t) static char g_tmpfpath[TMP_LEN_MAX];
 /* Buffer to store plugins control pipe location */
 alignas(max_align_t) static char g_pipepath[TMP_LEN_MAX];
 
+/* Buffer to store preview plugins control pipe location */
+static char g_ppipepath[TMP_LEN_MAX] __attribute__ ((aligned));
+
 /* Non-persistent runtime states */
 static runstate g_state;
 
@@ -705,12 +709,13 @@ static const char * const messages[] = {
 #define NNN_FCOLORS 5
 #define NNNLVL      6
 #define NNN_PIPE    7
-#define NNN_MCLICK  8
-#define NNN_SEL     9
-#define NNN_ARCHIVE 10
-#define NNN_ORDER   11
-#define NNN_HELP    12
-#define NNN_TRASH   13
+#define NNN_PPIPE   8
+#define NNN_MCLICK  9
+#define NNN_SEL     10
+#define NNN_ARCHIVE 11
+#define NNN_ORDER   12
+#define NNN_HELP    13
+#define NNN_TRASH   14
 
 static const char * const env_cfg[] = {
 	"NNN_OPTS",
@@ -721,6 +726,7 @@ static const char * const env_cfg[] = {
 	"NNN_FCOLORS",
 	"NNNLVL",
 	"NNN_PIPE",
+	"NNN_PPIPE",
 	"NNN_MCLICK",
 	"NNN_SEL",
 	"NNN_ARCHIVE",
@@ -859,7 +865,7 @@ static int set_sort_flags(int r);
 static void statusbar(char *path);
 static bool get_output(char *file, char *arg1, char *arg2, int fdout, bool page);
 #ifndef NOFIFO
-static void notify_fifo(bool force);
+static void notify_fifo(bool force, bool closepreview);
 #endif
 
 /* Functions */
@@ -3166,7 +3172,7 @@ try_quit:
 			} else {
 #ifndef NOFIFO
 				if (!g_state.fifomode)
-					notify_fifo(TRUE); /* Send hovered path to NNN_FIFO */
+					notify_fifo(TRUE, FALSE); /* Send hovered path to NNN_FIFO */
 #endif
 				escaped = TRUE;
 				settimeout();
@@ -5372,15 +5378,20 @@ static void run_cmd_as_plugin(const char *file, uchar_t flags)
 
 static bool plctrl_init(void)
 {
-	size_t len;
+	size_t len, lenbuf;
+	pid_t pid = getpid();
 
 	/* g_tmpfpath is used to generate tmp file names */
 	g_tmpfpath[tmpfplen - 1] = '\0';
-	len = xstrsncpy(g_pipepath, g_tmpfpath, TMP_LEN_MAX);
+	len = lenbuf = xstrsncpy(g_pipepath, g_tmpfpath, TMP_LEN_MAX);
 	g_pipepath[len - 1] = '/';
-	len = xstrsncpy(g_pipepath + len, "nnn-pipe.", TMP_LEN_MAX - len) + len;
-	xstrsncpy(g_pipepath + len - 1, xitoa(getpid()), TMP_LEN_MAX - len);
+	xstrsncpy(g_ppipepath, g_pipepath, TMP_LEN_MAX);
+	len += xstrsncpy(g_pipepath + len, "nnn-pipe.", TMP_LEN_MAX - len);
+	xstrsncpy(g_pipepath + len - 1, xitoa(pid), TMP_LEN_MAX - len);
+	len = xstrsncpy(g_ppipepath + lenbuf, "nnn-ppipe.", TMP_LEN_MAX - lenbuf) + lenbuf;
+	xstrsncpy(g_ppipepath + len - 1, xitoa(pid), TMP_LEN_MAX - len);
 	setenv(env_cfg[NNN_PIPE], g_pipepath, TRUE);
+	setenv(env_cfg[NNN_PPIPE], g_ppipepath, TRUE);
 
 	return EXIT_SUCCESS;
 }
@@ -5409,6 +5420,21 @@ static ssize_t read_nointr(int fd, void *buf, size_t count)
 	return len;
 }
 
+void *previewpipe(void *arg __attribute__ ((unused)))
+{
+	int fd, buf;
+
+	mkfifo(g_ppipepath, 0600);
+	fd = open(g_ppipepath, O_RDONLY);
+
+	if (read(fd, &buf, 1) == 1)
+		g_state.previewer = buf;
+
+	close(fd);
+	unlink(g_ppipepath);
+	return NULL;
+}
+
 static char *readpipe(int fd, char *ctxnum, char **path)
 {
 	char ctx, *nextpath = NULL;
@@ -6097,7 +6123,7 @@ static void populate(char *path, char *lastname)
 }
 
 #ifndef NOFIFO
-static void notify_fifo(bool force)
+static void notify_fifo(bool force, bool closepreview)
 {
 	if (!fifopath)
 		return;
@@ -6113,6 +6139,12 @@ static void notify_fifo(bool force)
 		}
 	}
 
+	if (closepreview) {
+		if (write(fifofd, "close\n", 6) != 6)
+			xerror();
+		return;
+	}
+
 	static struct entry lastentry;
 
 	if (!force && !memcmp(&lastentry, &pdents[cur], sizeof(struct entry))) // NOLINT
@@ -6145,7 +6177,7 @@ static void send_to_explorer(int *presel)
 		if (fd > 1)
 			close(fd);
 	} else
-		notify_fifo(TRUE); /* Send opened path to NNN_FIFO */
+		notify_fifo(TRUE, FALSE); /* Send opened path to NNN_FIFO */
 }
 #endif
 
@@ -6178,7 +6210,7 @@ static void move_cursor(int target, int ignore_scrolloff)
 
 #ifndef NOFIFO
 	if (!g_state.fifomode)
-		notify_fifo(FALSE); /* Send hovered path to NNN_FIFO */
+		notify_fifo(FALSE, FALSE); /* Send hovered path to NNN_FIFO */
 #endif
 }
 
@@ -6851,7 +6883,7 @@ static bool browse(char *ipath, int pkey)
 	pEntry pen
Download .txt
gitextract__6m8rskv/

├── .circleci/
│   └── config.yml
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── config.yml
│   └── workflows/
│       ├── ci.yml
│       ├── codeql.yml
│       └── lock.yml
├── .gitignore
├── CHANGELOG
├── LICENSE
├── Makefile
├── README.md
├── misc/
│   ├── CONTRIBUTING.md
│   ├── auto-completion/
│   │   ├── bash/
│   │   │   └── nnn-completion.bash
│   │   ├── fish/
│   │   │   └── nnn.fish
│   │   └── zsh/
│   │       └── _nnn
│   ├── desktop/
│   │   └── nnn.desktop
│   ├── haiku/
│   │   ├── Makefile
│   │   ├── haiku_interop.h
│   │   ├── nm.cpp
│   │   ├── nnn-master.recipe
│   │   └── nnn.rdef
│   ├── macos-legacy/
│   │   ├── mach_gettime.c
│   │   └── mach_gettime.h
│   ├── musl/
│   │   └── musl-static-ubuntu.sh
│   ├── natool/
│   │   └── natool
│   ├── packagecore/
│   │   └── packagecore.yaml
│   ├── quitcd/
│   │   ├── quitcd.bash_sh_zsh
│   │   ├── quitcd.csh
│   │   ├── quitcd.elv
│   │   ├── quitcd.fish
│   │   ├── quitcd.nu
│   │   └── quitcd.rc
│   └── test/
│       ├── benchmark.sh
│       ├── genfiles.sh
│       ├── mktest.sh
│       ├── plot-bench.py
│       └── verify-du.sh
├── nnn.1
├── patches/
│   ├── README.md
│   ├── check-patches.sh
│   ├── colemak/
│   │   └── mainline.diff
│   ├── gitstatus/
│   │   ├── mainline.diff
│   │   └── namefirst.diff
│   ├── namefirst/
│   │   └── mainline.diff
│   └── restorepreview/
│       └── mainline.diff
├── plugins/
│   ├── .cbcp
│   ├── .iconlookup
│   ├── .nmv
│   ├── .nnn-plugin-helper
│   ├── .ntfy
│   ├── README.md
│   ├── autojump
│   ├── boom
│   ├── bulknew
│   ├── cbcopy-mac
│   ├── cbpaste-mac
│   ├── cdpath
│   ├── chksum
│   ├── cmusq
│   ├── diffs
│   ├── dragdrop
│   ├── dups
│   ├── finder
│   ├── fixname
│   ├── fzcd
│   ├── fzhist
│   ├── fzopen
│   ├── fzplug
│   ├── getplugs
│   ├── gitroot
│   ├── gpgd
│   ├── gpge
│   ├── gpgs
│   ├── gpgv
│   ├── gsconnect
│   ├── gutenread
│   ├── imgresize
│   ├── imgur
│   ├── imgview
│   ├── ipinfo
│   ├── kdeconnect
│   ├── launch
│   ├── mimelist
│   ├── moclyrics
│   ├── mocq
│   ├── mp3conv
│   ├── mtpmount
│   ├── nbak
│   ├── nmount
│   ├── nuke
│   ├── oldbigfile
│   ├── openall
│   ├── organize
│   ├── pdfread
│   ├── preview-tabbed
│   ├── preview-tui
│   ├── pskill
│   ├── renamer
│   ├── ringtone
│   ├── rsynccp
│   ├── splitjoin
│   ├── suedit
│   ├── togglex
│   ├── umounttree
│   ├── upload
│   ├── wallpaper
│   ├── x2sel
│   └── xdgdefault
└── src/
    ├── .clang-tidy
    ├── dbg.h
    ├── icons-hash.c
    ├── icons-in-terminal.h
    ├── icons.h
    ├── nnn.c
    ├── nnn.h
    └── qsort.h
Download .txt
SYMBOL INDEX (242 symbols across 10 files)

FILE: misc/haiku/haiku_interop.h
  type haiku_nm_t (line 5) | struct haiku_nm_t

FILE: misc/haiku/nm.cpp
  function filter_result (line 8) | filter_result dir_mon_flt(BMessage *message, BHandler **hnd, BMessageFil...
  class DirectoryListener (line 27) | class DirectoryListener : public BLooper {
    method recv_reset (line 29) | bool recv_reset() {
    method MessageReceived (line 38) | void MessageReceived(BMessage * message) override {
  type haiku_nm_t (line 48) | struct haiku_nm_t {
    method haiku_nm_t (line 49) | haiku_nm_t() {
  function haiku_nm_h (line 61) | haiku_nm_h haiku_init_nm() {
  function haiku_close_nm (line 65) | void haiku_close_nm(haiku_nm_h hnd) {
  function haiku_watch_dir (line 71) | int haiku_watch_dir(haiku_nm_h hnd, const char *path) {
  function haiku_stop_watch (line 77) | int haiku_stop_watch(haiku_nm_h hnd) {
  function haiku_is_update_needed (line 81) | int haiku_is_update_needed(haiku_nm_h hnd) {

FILE: misc/macos-legacy/mach_gettime.c
  function clock_gettime (line 11) | int clock_gettime(clockid_t clk_id, struct timespec *tp)

FILE: misc/macos-legacy/mach_gettime.h
  type clockid_t (line 18) | typedef int clockid_t;
  type timespec (line 24) | struct timespec

FILE: misc/test/plot-bench.py
  function bench_file_to_lists (line 9) | def bench_file_to_lists(infile):
  function plot_data (line 12) | def plot_data(data):

FILE: src/dbg.h
  function xprintf (line 36) | static int xprintf(int fd, const char *fmt, ...)
  function enabledbg (line 50) | static int enabledbg(void)
  function disabledbg (line 74) | static void disabledbg(void)

FILE: src/icons-hash.c
  type icon_pair (line 53) | struct icon_pair
  function rh_insert (line 64) | static void
  function pcg (line 108) | static uint32_t
  function main (line 118) | int
  function icon_ext_hash (line 268) | static uint32_t

FILE: src/icons.h
  type icon_pair (line 173) | struct icon_pair { const char *match; const char *icon; unsigned char co...
  type icon (line 176) | struct icon { const char *icon; unsigned char color; }
  type icon (line 178) | struct icon
  type icon (line 179) | struct icon
  type icon (line 180) | struct icon
  type icon_pair (line 182) | struct icon_pair
  type icon_pair (line 209) | struct icon_pair

FILE: src/nnn.c
  type uint_t (line 302) | typedef unsigned int uint_t;
  type uchar_t (line 303) | typedef unsigned char uchar_t;
  type ushort_t (line 304) | typedef unsigned short ushort_t;
  type ullong_t (line 305) | typedef unsigned long long ullong_t;
  type entry (line 310) | struct entry {
  type selmark (line 328) | typedef struct {
  type kv (line 334) | typedef struct {
  type fltrexp_t (line 339) | typedef struct {
  type settings (line 351) | typedef struct {
  type runstate (line 384) | typedef struct {
  type context (line 414) | typedef struct {
  type session_header_t (line 424) | typedef struct {
  type entry (line 485) | struct entry
  type du_group (line 524) | typedef struct {
  type du_task (line 533) | typedef struct {
  type thread_data (line 544) | typedef struct {
  type sigaction (line 555) | struct sigaction
  type sigaction (line 556) | struct sigaction
  type sigaction (line 557) | struct sigaction
  type kevent (line 859) | struct kevent
  type timespec (line 862) | struct timespec
  function sigint_handler (line 916) | static void sigint_handler(int sig)
  function clean_exit_sighandler (line 922) | static void clean_exit_sighandler(int sig)
  function uchar_t (line 963) | static uchar_t xchartohex(uchar_t c)
  function test_set_bit (line 981) | static inline bool test_set_bit(uint_t nr)
  function test_set_bit_dir (line 1004) | static bool test_set_bit_dir(dev_t dev, ino_t ino)
  function max_openfds (line 1018) | static void max_openfds(void)
  function xstrsncpy (line 1051) | static size_t xstrsncpy(char *restrict dst, const char *restrict src, si...
  function is_suffix (line 1071) | static bool is_suffix(const char *restrict str, const char *restrict suf...
  function is_prefix (line 1085) | static inline bool is_prefix(const char *restrict str, const char *restr...
  function is_bad_len_or_dir (line 1090) | static inline bool is_bad_len_or_dir(const char *restrict path)
  type passwd (line 1178) | struct passwd
  type group (line 1193) | struct group
  function getutil (line 1203) | static inline bool getutil(char *util)
  function tilde_is_home (line 1208) | static inline bool tilde_is_home(const char *s)
  function tilde_is_home_strict (line 1213) | static inline bool tilde_is_home_strict(const char *s)
  function mkpath (line 1224) | static size_t mkpath(const char *dir, const char *name, char *out)
  function shell_escape (line 1393) | static ssize_t shell_escape(char *output, size_t outlen, const char *s)
  function set_tilde_in_path (line 1430) | static bool set_tilde_in_path(char *path)
  function reset_tilde_in_path (line 1441) | static void reset_tilde_in_path(char *path)
  function xterm_cfg (line 1448) | static void xterm_cfg(char *path)
  function convert_tilde (line 1466) | static bool convert_tilde(const char *path, char *buf)
  function create_tmp_file (line 1479) | static int create_tmp_file(void)
  function msg (line 1492) | static void msg(const char *message)
  function handle_key_resize (line 1498) | static void handle_key_resize(void)
  function clearoldprompt (line 1505) | static void clearoldprompt(void)
  function printmsg_nc (line 1514) | static inline void printmsg_nc(const char *msg)
  function printmsg (line 1521) | static void printmsg(const char *msg)
  function printwait (line 1528) | static void printwait(const char *msg, int *presel)
  function printerr (line 1539) | static void printerr(int linenum)
  function xconfirm (line 1549) | static inline bool xconfirm(int c)
  function get_input (line 1554) | static int get_input(const char *prompt)
  function isselfileempty (line 1579) | static bool isselfileempty(void)
  function get_cur_or_sel (line 1586) | static int get_cur_or_sel(void)
  function xdelay (line 1612) | static void xdelay(useconds_t delay)
  function uint_t (line 1618) | static uint_t entries_in_file(int fd, char *buf, size_t buflen, const ch...
  function confirm_force (line 1631) | static char confirm_force(bool selection, bool use_trash)
  function writesel (line 1675) | static void writesel(const char *buf, const size_t buflen)
  function appendfpath (line 1690) | static void appendfpath(const char *path, const size_t len)
  function selbufrealloc (line 1702) | static void selbufrealloc(const size_t alloclen)
  function seltofile (line 1713) | static size_t seltofile(int fd, uint_t *pcount, const char *separator)
  function listselfile (line 1764) | static bool listselfile(void)
  function resetselind (line 1776) | static void resetselind(void)
  function startselection (line 1783) | static void startselection(void)
  function clearselection (line 1797) | static void clearselection(void)
  function markcmp (line 1829) | static int markcmp(const void *va, const void *vb)
  function findmarkentry (line 1838) | static inline void findmarkentry(size_t len, struct entry *dentp)
  function invertselbuf (line 1851) | static void invertselbuf(const int pathlen)
  function addtoselbuf (line 1966) | static void addtoselbuf(const int pathlen, int startid, int endid)
  function rmfromselbuf (line 2009) | static void rmfromselbuf(size_t len)
  function scanselforpath (line 2021) | static int scanselforpath(const char *path, bool getsize)
  function endselection (line 2044) | static void endselection(bool endselmode)
  function editselection (line 2110) | static int editselection(bool allowemptysel)
  function selsafe (line 2233) | static bool selsafe(void)
  function export_file_list (line 2250) | static void export_file_list(void)
  function init_fcolors (line 2284) | static bool init_fcolors(void)
  function initcurses (line 2306) | static bool initcurses(void *oldmask)
  function enable_signals (line 2463) | static void enable_signals(void)
  function pid_t (line 2474) | static pid_t xfork(uchar_t flag)
  function join (line 2513) | static int join(pid_t p, uchar_t flag)
  function spawn (line 2540) | static int spawn(char *command, char *arg1, char *arg2, char *arg3, usho...
  function xdiraccess (line 2616) | static bool xdiraccess(const char *path)
  function plugscript (line 2629) | static bool plugscript(const char *plugin, uchar_t flags)
  function opstr (line 2640) | static void opstr(char *buf, char *op)
  function rmmulstr (line 2645) | static bool rmmulstr(char *buf, bool use_trash)
  function xrm (line 2662) | static bool xrm(char * const fpath, bool use_trash)
  function xrmfromsel (line 2679) | static void xrmfromsel(char *path, char *fpath)
  function cpmv_rename (line 2700) | static bool cpmv_rename(int choice, const char *path)
  function cpmvrm_selection (line 2752) | static bool cpmvrm_selection(enum action sel, char *path)
  function batch_rename (line 2807) | static bool batch_rename(void)
  function archive_selection (line 2898) | static void archive_selection(const char *cmd, const char *archive)
  function write_lastdir (line 2914) | static void write_lastdir(const char *curpath, const char *outfile)
  function xstricmp (line 2943) | static int xstricmp(const char * const s1, const char * const s2)
  function xstrverscasecmp (line 2993) | static int xstrverscasecmp(const char * const s1, const char * const s2)
  function setfilter (line 3070) | static int setfilter(pcre2_code **pcre2x, const char *filter)
  function setfilter (line 3079) | static int setfilter(regex_t *regex, const char *filter)
  function wchar_t (line 3086) | static inline wchar_t normalize_char(wchar_t c)
  function fuzzy_match (line 3098) | static int fuzzy_match(const char *filter, const char *fname)
  function visible_re (line 3140) | static int visible_re(const fltrexp_t *fltrexp, const char *fname)
  function visible_str (line 3157) | static int visible_str(const fltrexp_t *fltrexp, const char *fname)
  function fuzzy_match_positions (line 3167) | static void fuzzy_match_positions(const char *filter, const char *fname,...
  function string_match_positions (line 3217) | static void string_match_positions(const char *filter, const char *fname...
  function visible_fuzzy (line 3261) | static int visible_fuzzy(const fltrexp_t *fltrexp, const char *fname)
  function clearfilter (line 3268) | static void clearfilter(void)
  function entrycmp (line 3278) | static int entrycmp(const void *va, const void *vb)
  function reventrycmp (line 3331) | static int reventrycmp(const void *va, const void *vb)
  function handle_alt_key (line 3346) | static int handle_alt_key(wint_t *wch)
  function handle_event (line 3359) | static inline int handle_event(void)
  function nextsel (line 3371) | static int nextsel(int presel)
  function getorderstr (line 3475) | static int getorderstr(char *sort)
  function showfilterinfo (line 3501) | static void showfilterinfo(void)
  function showfilter (line 3519) | static void showfilter(char *str)
  function swap_ent (line 3527) | static inline void swap_ent(int id1, int id2)
  function fill (line 3539) | static int fill(const char *fltr, regex_t *re)
  function matches (line 3561) | static int matches(const char *fltr)
  function dentfind (line 3596) | static int dentfind(const char *fname, int n)
  function filterentries (line 3605) | static int filterentries(char *path, char *lastname)
  function addcmdtohist (line 3860) | static void addcmdtohist(char *cmd)
  function xread_history (line 3890) | static void xread_history(const char *histpath)
  function xwrite_history (line 3912) | static void xwrite_history(const char *histpath)
  function xlink (line 4192) | static int xlink(char *prefix, char *path, char *curfname, char *buf, in...
  function parsekvpair (line 4246) | static bool parsekvpair(kv **arr, char **envcpy, const uchar_t id, uchar...
  function get_kv_key (line 4326) | static int get_kv_key(kv *kvarr, char *val, uchar_t max, uchar_t id)
  function resetdircolor (line 4342) | static void resetdircolor(int flags)
  function wchar_t (line 4364) | static wchar_t *unescape(const char *str, uint_t maxcols)
  function off_t (line 4392) | static off_t get_size(off_t size, off_t *pval, int comp)
  function get_icon (line 4510) | static struct icon get_icon(const struct entry *ent)
  function print_icon (line 4536) | static void print_icon(const struct entry *ent, const int attrs)
  function print_time (line 4553) | static void print_time(const time_t *timep, const uchar_t flags)
  function get_detail_ind (line 4569) | static char get_detail_ind(const mode_t mode)
  function uchar_t (line 4584) | static uchar_t get_color_pair_name_ind(const struct entry *ent, char *pi...
  function printent_name (line 4638) | static void printent_name(const struct entry *ent, uint_t namecols)
  function printent_name (line 4723) | static inline void printent_name(const struct entry *ent, uint_t namecols)
  function printent (line 4733) | static void printent(int pdents_index, uint_t namecols, bool sel)
  function setcfg (line 4804) | static void setcfg(settings newcfg)
  function savecurctx (line 4813) | static void savecurctx(char *path, char *curname, int nextctx)
  function save_session (line 4848) | static void save_session(const char *sname, int *presel)
  function load_session (line 4905) | static bool load_session(const char *sname, char **path, char **lastdir,...
  function uchar_t (line 4987) | static uchar_t get_free_ctx(void)
  function set_smart_ctx (line 4999) | static void set_smart_ctx(int ctx, char *nextpath, char **path, char *fi...
  function handle_cur_move (line 5020) | static bool handle_cur_move(enum action sel)
  function get_output (line 5046) | static bool get_output(char *command, char *arg1, char *arg2, int fdout,...
  function buffer_command_output (line 5158) | static bool buffer_command_output(char * const cmds[], char *arg1, char ...
  function show_content_in_floating_window (line 5253) | static bool show_content_in_floating_window(char *content, size_t conten...
  function show_stats (line 5458) | static bool show_stats(char *pathbuf, char *dir)
  function xchmod (line 5500) | static bool xchmod(char *pathbuf, char *dir)
  function get_fs_info (line 5536) | static size_t get_fs_info(const char *path, uchar_t type)
  function xmktree (line 5553) | static bool xmktree(char *path, bool dir)
  function handle_archive (line 5620) | static bool handle_archive(char *fpath /* in-out param */, char op)
  function valid_parent (line 5711) | static void valid_parent(char *path, char *lastname)
  function archive_mount (line 5724) | static bool archive_mount(char *newpath)
  function remote_mount (line 5771) | static bool remote_mount(char *newpath)
  type stat (line 5855) | struct stat
  function lock_terminal (line 5927) | static void lock_terminal(void)
  function printkv (line 5932) | static void printkv(kv *kvarr, FILE *f, uchar_t max, uchar_t id)
  function printkeys (line 5940) | static void printkeys(kv *kvarr, char *buf, uchar_t max)
  function handle_bookmark (line 5952) | static size_t handle_bookmark(const char *bmark, char *newpath)
  function add_bookmark (line 5989) | static void add_bookmark(char *path, char *newpath, int *presel)
  function show_help (line 6014) | static void show_help(const char *path)
  function setexports (line 6139) | static void setexports(const char *path)
  function run_cmd_as_plugin (line 6166) | static void run_cmd_as_plugin(const char *file, ushort_t flags, enum act...
  function plctrl_init (line 6193) | static bool plctrl_init(void)
  function rmlistpath (line 6208) | static void rmlistpath(void)
  function read_nointr (line 6221) | static ssize_t read_nointr(int fd, void *buf, size_t count)
  function run_plugin (line 6289) | static bool run_plugin(char **path, const char *file, char *runfile, cha...
  function launch_app (line 6392) | static bool launch_app(char *newpath)
  function prompt_run (line 6411) | static bool prompt_run(void)
  function handle_cmd (line 6483) | static bool handle_cmd(enum action sel, char *path, char *newpath)
  function dentfree (line 6505) | static void dentfree(void)
  function du_queue_task (line 6533) | static bool du_queue_task(const char *path, du_group *group, bool count_...
  function add_blocks (line 6591) | static inline void add_blocks(blkcnt_t *tblocks, const struct stat *sb)
  function du_walk_dir (line 6599) | static void du_walk_dir(const char *root, du_group *group, bool count_ro...
  function dirwalk (line 6749) | static void dirwalk(char *path, int entnum, bool mountpoint, bool no_agg...
  function prep_threads (line 6775) | static bool prep_threads(void)
  function selforparent (line 6838) | static inline bool selforparent(const char *path)
  function dentfill (line 6843) | static int dentfill(char *path, struct entry **ppdents)
  function populate (line 7141) | static void populate(char *path, char *lastname)
  function notify_fifo (line 7171) | static void notify_fifo(bool force)
  function send_to_explorer (line 7206) | static void send_to_explorer(int *presel)
  function move_cursor (line 7223) | static void move_cursor(int target, int ignore_scrolloff)
  function handle_screen_move (line 7254) | static void handle_screen_move(enum action sel)
  function handle_openwith (line 7349) | static void handle_openwith(const char *path, const char *name, char *ne...
  function copynextname (line 7362) | static void copynextname(char *lastname)
  function handle_context_switch (line 7371) | static int handle_context_switch(enum action sel)
  function set_sort_flags (line 7411) | static int set_sort_flags(int r)
  function set_time_type (line 7537) | static bool set_time_type(int *presel)
  function statusbar (line 7566) | static void statusbar(char *path)
  function markhovered (line 7678) | static inline void markhovered(void)
  function adjust_cols (line 7686) | static int adjust_cols(int n)
  function draw_line (line 7704) | static void draw_line(int ncols)
  function redraw (line 7740) | static void redraw(char *path)
  function cdprep (line 7876) | static bool cdprep(char *lastdir, char *lastname, char *path, char *newp...
  function showselsize (line 7892) | static void showselsize(const char *path)
  type action (line 7912) | enum action
  type stat (line 7913) | struct stat
  type timespec (line 7921) | struct timespec
  type entry (line 7971) | struct entry
  type action (line 9092) | enum action
  type stat (line 9285) | struct stat
  function check_key_collision (line 9503) | static void check_key_collision(void)
  function usage (line 9518) | static void usage(void)
  function setup_config (line 9578) | static bool setup_config(void)
  function set_tmp_path (line 9662) | static bool set_tmp_path(void)
  function cleanup (line 9679) | static void cleanup(void)
  type stat (line 10021) | struct stat
  type sigaction (line 10101) | struct sigaction
  type sigaction (line 10136) | struct sigaction

FILE: src/nnn.h
  type action (line 47) | enum action {
  type key (line 127) | struct key {
  type key (line 132) | struct key
Condensed preview — 117 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (885K chars).
[
  {
    "path": ".circleci/config.yml",
    "chars": 4364,
    "preview": "version: 2\n\njobs:\n  compile:\n    docker:\n      - image: ubuntu:24.04\n        working_directory: ~/nnn\n        environmen"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 61,
    "preview": "# These are supported funding model platforms\n\ngithub: jarun\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 1695,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n---\n\n`nnn` comes with"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 227,
    "preview": "contact_links:\n  - name: Idea, Enhancement, Question, Support\n    url: https://github.com/jarun/nnn/discussions\n    abou"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1640,
    "preview": "name: GitHubCI\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n\njobs:\n  macOS-gcc:\n    runs-o"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "chars": 918,
    "preview": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n  schedule:\n    - cron"
  },
  {
    "path": ".github/workflows/lock.yml",
    "chars": 472,
    "preview": "name: 'Lock threads'\n\non:\n  schedule:\n    - cron: '0 0 * * *'\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  pull-"
  },
  {
    "path": ".gitignore",
    "chars": 57,
    "preview": "*.o\n*.dSYM\nnnn\nsrc/icons-generated*.h\nsrc/icons-hash-gen\n"
  },
  {
    "path": "CHANGELOG",
    "chars": 53780,
    "preview": "nnn v5.2 Blue Hawaii\n2026-02-14\n\n- enable 8 contexts (saved sessions may no longer be usable, users need to re-create th"
  },
  {
    "path": "LICENSE",
    "chars": 1472,
    "preview": "BSD 2-Clause License\n\nCopyright (c) 2014-2016, Lazaros Koromilas <lostd@2f30.org>\nCopyright (c) 2014-2016, Dimitris Papa"
  },
  {
    "path": "Makefile",
    "chars": 13243,
    "preview": "VERSION = $(shell grep -m1 VERSION $(SRC) | cut -f 2 -d'\"')\n\nPREFIX ?= /usr/local\nMANPREFIX ?= $(PREFIX)/share/man\nDESKT"
  },
  {
    "path": "README.md",
    "chars": 10436,
    "preview": "<h3 align=\"center\"><img src=\"misc/logo/logo-128x128.png\" alt=\"nnn\"><br>nnn - <i>Supercharge your productivity!</i></h3>\n"
  },
  {
    "path": "misc/CONTRIBUTING.md",
    "chars": 1336,
    "preview": "# Contributing\nContributions to nnn are welcome! There's always an open issue with the current ToDo list, which contains"
  },
  {
    "path": "misc/auto-completion/bash/nnn-completion.bash",
    "chars": 1643,
    "preview": "#\n# Rudimentary Bash completion definition for nnn.\n#\n# Author:\n#   Arun Prakash Jana <engineerarun@gmail.com>\n#\n\n_nnn ("
  },
  {
    "path": "misc/auto-completion/fish/nnn.fish",
    "chars": 2405,
    "preview": "#\n# Fish completion definition for nnn.\n#\n# Author:\n#   Arun Prakash Jana <engineerarun@gmail.com>\n#\n\nif test -n \"$XDG_C"
  },
  {
    "path": "misc/auto-completion/zsh/_nnn",
    "chars": 1801,
    "preview": "#compdef nnn\n#\n# Completion definition for nnn.\n#\n# Author:\n#   Arun Prakash Jana <engineerarun@gmail.com>\n#\n\nsetopt loc"
  },
  {
    "path": "misc/desktop/nnn.desktop",
    "chars": 235,
    "preview": "[Desktop Entry]\nType=Application\nName=nnn\nComment=Terminal file manager\nExec=nnn %f\nTerminal=true\nIcon=nnn\nMimeType=inod"
  },
  {
    "path": "misc/haiku/Makefile",
    "chars": 6289,
    "preview": "VERSION = $(shell grep -m1 VERSION $(SRC) | cut -f 2 -d'\"')\n\nPREFIX ?= /boot/system/non-packaged\nMANPREFIX ?= $(PREFIX)/"
  },
  {
    "path": "misc/haiku/haiku_interop.h",
    "chars": 310,
    "preview": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct haiku_nm_t *haiku_nm_h;\nhaiku_nm_h haiku_init_nm();\nvoid haiku_cl"
  },
  {
    "path": "misc/haiku/nm.cpp",
    "chars": 1640,
    "preview": "#include <Directory.h>\n#include <Looper.h>\n#include <NodeMonitor.h>\n#include <MessageFilter.h>\n\n#include \"haiku_interop."
  },
  {
    "path": "misc/haiku/nnn-master.recipe",
    "chars": 1624,
    "preview": "SUMMARY=\"A blazing-fast lightweight terminal file manager\"\nDESCRIPTION=\"nnn is a full-featured terminal file manager. It"
  },
  {
    "path": "misc/haiku/nnn.rdef",
    "chars": 8380,
    "preview": "\n// How to apply this resource definition file manually (Haiku only):\n// First, make sure that nnn is compiled.\n// Next,"
  },
  {
    "path": "misc/macos-legacy/mach_gettime.c",
    "chars": 1192,
    "preview": "#include \"mach_gettime.h\"\n#include <mach/mach_time.h>\n\n#define MT_NANO (+1.0E-9)\n#define MT_GIGA UINT64_C(1000000000)\n\n/"
  },
  {
    "path": "misc/macos-legacy/mach_gettime.h",
    "chars": 822,
    "preview": "#ifndef mach_time_h\n#define mach_time_h\n\n#include <sys/types.h>\n#include <sys/_types/_timespec.h>\n#include <mach/mach.h>"
  },
  {
    "path": "misc/musl/musl-static-ubuntu.sh",
    "chars": 2524,
    "preview": "#!/usr/bin/env sh\n\n# Statically compile nnn with netbsd-curses, musl-fts and musl libc on Ubuntu\n#\n# netbsd-curses: http"
  },
  {
    "path": "misc/natool/natool",
    "chars": 1395,
    "preview": "#!/usr/bin/env python3\n\n# #############################################################################\n# natool: a wrap"
  },
  {
    "path": "misc/packagecore/packagecore.yaml",
    "chars": 2542,
    "preview": "name: nnn\nmaintainer: Arun Prakash Jana <engineerarun@gmail.com>\nlicense: BSD 2-Clause\nsummary: The unorthodox terminal "
  },
  {
    "path": "misc/quitcd/quitcd.bash_sh_zsh",
    "chars": 993,
    "preview": "n ()\n{\n    # Block nesting of nnn in subshells\n    [ \"${NNNLVL:-0}\" -eq 0 ] || {\n        echo \"nnn is already running\"\n "
  },
  {
    "path": "misc/quitcd/quitcd.csh",
    "chars": 671,
    "preview": "# NOTE: set NNN_TMPFILE correctly if you use 'XDG_CONFIG_HOME'\n\n# The behaviour is set to cd on quit (nnn checks if NNN_"
  },
  {
    "path": "misc/quitcd/quitcd.elv",
    "chars": 922,
    "preview": "# Append this file to ~/.elvish/rc.elv (Elvish > 0.17.0)\n\nuse path\n\nfn n {|@a|\n\t# Block nesting of nnn in subshells\n\tif "
  },
  {
    "path": "misc/quitcd/quitcd.fish",
    "chars": 1189,
    "preview": "# Rename this file to match the name of the function\n# e.g. ~/.config/fish/functions/n.fish\n# or, add the lines to the '"
  },
  {
    "path": "misc/quitcd/quitcd.nu",
    "chars": 1288,
    "preview": "# Run nnn with dynamic changing directory to the environment.\n#\n# $env.XDG_CONFIG_HOME sets the home folder for `nnn` fo"
  },
  {
    "path": "misc/quitcd/quitcd.rc",
    "chars": 385,
    "preview": "# The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)\n# If NNN_TMPFILE is set to a custom path, it mus"
  },
  {
    "path": "misc/test/benchmark.sh",
    "chars": 667,
    "preview": "#!/bin/sh\n#\n# Usage: ./misc/test/benchmark.sh ./nnn /tmp/testdir1 ./testdir2 ...\n#\n# Don't forget to build nnn in benchm"
  },
  {
    "path": "misc/test/genfiles.sh",
    "chars": 162,
    "preview": "#!/bin/sh\n\n# Generates 100000 files in the current directory\n\ni=1; while [ $i -le 100000 ]; do\n    mktemp -p . -t 'XXXXX"
  },
  {
    "path": "misc/test/mktest.sh",
    "chars": 2919,
    "preview": "#!/bin/sh\n\n# Create test files and directories\n\ntest -e outdir && {\n    echo \"Remove 'outdir' and try again\"\n    exit 1\n"
  },
  {
    "path": "misc/test/plot-bench.py",
    "chars": 481,
    "preview": "#!/usr/bin/env python3\n#\n# Usage: ./plot-bench.py datafile\n# (where datafile is the output of benchmark.sh)\n\nimport matp"
  },
  {
    "path": "misc/test/verify-du.sh",
    "chars": 2628,
    "preview": "#!/bin/sh\n# Verify disk usage: run du from a path and print in GB for comparison with nnn.\n# Usage: ./verify-du.sh [path"
  },
  {
    "path": "nnn.1",
    "chars": 23298,
    "preview": ".Dd Feb 14, 2026\n.Dt NNN 1\n.Os\n.Sh NAME\n.Nm nnn\n.Nd The unorthodox terminal file manager.\n.Sh SYNOPSIS\n.Nm\n.Op Ar -aAcCd"
  },
  {
    "path": "patches/README.md",
    "chars": 2118,
    "preview": "<h1 align=\"center\">User Patch Framework</h1>\n\nThis directory contains sizable user submitted patches that were rejected "
  },
  {
    "path": "patches/check-patches.sh",
    "chars": 743,
    "preview": "#!/bin/bash\n#\n# Usage: ./misc/test/check-patches.sh\n#\n# Bash script that checks for any of the patches failing to apply."
  },
  {
    "path": "patches/colemak/mainline.diff",
    "chars": 4873,
    "preview": "diff --git a/src/nnn.c b/src/nnn.c\nindex d7c53166..bb7ff3e8 100644\n--- a/src/nnn.c\n+++ b/src/nnn.c\n@@ -5149,12 +5149,12 "
  },
  {
    "path": "patches/gitstatus/mainline.diff",
    "chars": 6525,
    "preview": "# Description: Add git status column to detail mode. Provides additional\n#              command line flag -G which will "
  },
  {
    "path": "patches/gitstatus/namefirst.diff",
    "chars": 6023,
    "preview": "# Description: Add git status column to detail mode. Provides additional\n#              command line flag -G which will "
  },
  {
    "path": "patches/namefirst/mainline.diff",
    "chars": 10480,
    "preview": "# Description: Prints filenames first in the detail view.  Prints user/group\n#              columns when a directory con"
  },
  {
    "path": "patches/restorepreview/mainline.diff",
    "chars": 7853,
    "preview": "# Description: Adds preview pipe to enable closing and re-opening the preview\n#              pane when running an undeta"
  },
  {
    "path": "plugins/.cbcp",
    "chars": 1479,
    "preview": "#!/usr/bin/env sh\n\n# Description: Copy selection to system clipboard as newline-separated entries\n# Dependencies:\n# - tr"
  },
  {
    "path": "plugins/.iconlookup",
    "chars": 21867,
    "preview": "#!/usr/bin/env sh\n\n# Description: Print icons in front of list of directories/files\n\n# Dependencies: awk\n\n# Usage\n#    1"
  },
  {
    "path": "plugins/.nmv",
    "chars": 3828,
    "preview": "#!/usr/bin/env bash\n\n# Description: An almost fully POSIX compliant batch file renamer\n#\n# Note: nnn auto-detects and in"
  },
  {
    "path": "plugins/.nnn-plugin-helper",
    "chars": 1256,
    "preview": "#!/usr/bin/env sh\n\n# Description: Helper script for plugins\n#\n# Shell: POSIX compliant\n# Author: Anna Arad\n\nselection=${"
  },
  {
    "path": "plugins/.ntfy",
    "chars": 624,
    "preview": "#!/usr/bin/env sh\n\n# Description: Show a notification\n#\n# Details: nnn invokes this plugin to show notification when a c"
  },
  {
    "path": "plugins/README.md",
    "chars": 18085,
    "preview": "<h1 align=\"center\">nnn plugins</h1>\n\n<p align=\"center\"><img src=\"https://i.imgur.com/SpT0L2W.png\" /></p>\n<p align=\"cente"
  },
  {
    "path": "plugins/autojump",
    "chars": 2724,
    "preview": "#!/usr/bin/env sh\n\n# Description: Navigate to directory using jump/autojump/zoxide/z\n#\n# Dependencies:\n#   - jump - http"
  },
  {
    "path": "plugins/boom",
    "chars": 1464,
    "preview": "#!/usr/bin/env sh\n\n# Description: Play random music (MP3, FLAC, M4A, WEBM, WMA) from current dir.\n#\n# Dependencies: mocp"
  },
  {
    "path": "plugins/bulknew",
    "chars": 739,
    "preview": "#!/usr/bin/env sh\n\n# Description: Allows for creation of multiple files/dirs simultaneously\n#              Creates a tmp"
  },
  {
    "path": "plugins/cbcopy-mac",
    "chars": 336,
    "preview": "#!/usr/bin/osascript\n\n# Description: Copy the hovered file to MacOS clipboard.\n#\n# Note: Supports only MacOS\n#\n# Shell: "
  },
  {
    "path": "plugins/cbpaste-mac",
    "chars": 725,
    "preview": "#!/usr/bin/env sh\n# shellcheck disable=all\n\n# Description: Paste the clipboard files into the current directory.\n#      "
  },
  {
    "path": "plugins/cdpath",
    "chars": 1901,
    "preview": "#!/usr/bin/env sh\n\n# Description: 'cd' to the directory from CDPATH\n#\n# Details: If the CDPATH environment variable is n"
  },
  {
    "path": "plugins/chksum",
    "chars": 2376,
    "preview": "#!/usr/bin/env sh\n\n# Description: Create and verify checksums\n#\n# Note:  On macOS, install the relevant checksum package"
  },
  {
    "path": "plugins/cmusq",
    "chars": 2284,
    "preview": "#!/usr/bin/env sh\n\n# Description: Add selection or hovered file/directory to cmus queue\n#\n# Dependencies: cmus, pgrep, x"
  },
  {
    "path": "plugins/diffs",
    "chars": 1829,
    "preview": "#!/usr/bin/env sh\n\n# Description: Show diff of 2 directories or multiple files in vimdiff\n#\n# Notes:\n#   1. vim may show"
  },
  {
    "path": "plugins/dragdrop",
    "chars": 2473,
    "preview": "#!/usr/bin/env sh\n\n# Description: Open a Drag and drop window, to drop files onto other programs.\n#              Also pr"
  },
  {
    "path": "plugins/dups",
    "chars": 2023,
    "preview": "#!/usr/bin/env sh\n\n# Description: List non-empty duplicates in the current dir (based on size followed by MD5)\n#\n# Sourc"
  },
  {
    "path": "plugins/finder",
    "chars": 2642,
    "preview": "#!/usr/bin/env bash\n\n# Description: Run custom search and list results in smart context\n#\n# Note: This plugin retains se"
  },
  {
    "path": "plugins/fixname",
    "chars": 1964,
    "preview": "#!/usr/bin/env bash\n\n# Description: Clean filename or dirname (either hovered or selections)\n#              to be more s"
  },
  {
    "path": "plugins/fzcd",
    "chars": 2697,
    "preview": "#!/usr/bin/env sh\n\n# Description: Fuzzy search multiple locations read-in from a path-list file\n#              (or $PWD)"
  },
  {
    "path": "plugins/fzhist",
    "chars": 1250,
    "preview": "#!/usr/bin/env sh\n\n# Description: Fuzzy find a command from history,\n#              edit in $EDITOR and run as a command"
  },
  {
    "path": "plugins/fzopen",
    "chars": 2263,
    "preview": "#!/usr/bin/env sh\n\n# Description: Regular mode:\n#                Fuzzy find a file in directory subtree.\n#              "
  },
  {
    "path": "plugins/fzplug",
    "chars": 2163,
    "preview": "#!/usr/bin/env sh\n\n# Description: Fuzzy find and execute nnn plugins (and optionally,\n#              custom scripts loca"
  },
  {
    "path": "plugins/getplugs",
    "chars": 1636,
    "preview": "#!/usr/bin/env sh\n\n# Description: Update nnn plugins to installed nnn version\n#\n# Shell: POSIX compliant\n# Authors: Arun"
  },
  {
    "path": "plugins/gitroot",
    "chars": 365,
    "preview": "#!/usr/bin/env sh\n\n# Description: cd to the top level of the current git repository in the current context\n# Dependencie"
  },
  {
    "path": "plugins/gpgd",
    "chars": 730,
    "preview": "#!/usr/bin/env sh\n\n# Description: Decrypts selected files using gpg. The contents of the\n#              decrypted file a"
  },
  {
    "path": "plugins/gpge",
    "chars": 1330,
    "preview": "#!/usr/bin/env sh\n\n# Description: Encrypts selected files using gpg. Can encrypt\n#              asymmetrically (key) or "
  },
  {
    "path": "plugins/gpgs",
    "chars": 1158,
    "preview": "#!/usr/bin/env sh\n\n# Description: signs selected files using gpg.\n#              includes options for clearsigning and\n#"
  },
  {
    "path": "plugins/gpgv",
    "chars": 674,
    "preview": "#!/usr/bin/env sh\n\n# Description: verifies signed files using gpg.\n#              includes options for detached signing\n"
  },
  {
    "path": "plugins/gsconnect",
    "chars": 676,
    "preview": "#!/usr/bin/env sh\n\n#set -x\n# Description: Send the selected (or hovered) files to your Android device using gsconnect da"
  },
  {
    "path": "plugins/gutenread",
    "chars": 1627,
    "preview": "#!/usr/bin/env sh\n\n# Description: Browse Project Gutenberg catalogue by popularity, then download\n#              and rea"
  },
  {
    "path": "plugins/imgresize",
    "chars": 790,
    "preview": "#!/usr/bin/env sh\n\n# Description: Resize images in a directory to screen resolution with imgp\n#\n# Dependencipes: imgp - "
  },
  {
    "path": "plugins/imgur",
    "chars": 20842,
    "preview": "#!/usr/bin/env bash\n\n##########################################################################\n# The MIT License\n#\n# Co"
  },
  {
    "path": "plugins/imgview",
    "chars": 4024,
    "preview": "#!/usr/bin/env sh\n\n# Description: Open hovered or current directory in image viewer.\n#              Generates media thum"
  },
  {
    "path": "plugins/ipinfo",
    "chars": 250,
    "preview": "#!/usr/bin/env sh\n\n# Description: Shows the external IP address and whois information. Useful over VPNs.\n#\n# Shell: POSI"
  },
  {
    "path": "plugins/kdeconnect",
    "chars": 1638,
    "preview": "#!/usr/bin/env sh\n\n# Description: Send files or folders to your Android device using kdeconnect-cli.\n#              kdec"
  },
  {
    "path": "plugins/launch",
    "chars": 1057,
    "preview": "#!/usr/bin/env sh\n\n# Description: Independent POSIX-compliant GUI application launcher.\n#              Fuzzy find execut"
  },
  {
    "path": "plugins/mimelist",
    "chars": 617,
    "preview": "#!/usr/bin/env sh\n\n# Description: Find and list files by mime type in smart context\n#\n# Dependencies:\n#   - file\n#   - m"
  },
  {
    "path": "plugins/moclyrics",
    "chars": 1064,
    "preview": "#!/usr/bin/env sh\n\n# Description: Fetches the lyrics of the track currently playing in MOC\n#\n# Dependencies: ddgr (https"
  },
  {
    "path": "plugins/mocq",
    "chars": 2063,
    "preview": "#!/usr/bin/env sh\n\n# Description: Appends and optionally plays music in MOC\n#\n# Notes:\n#   - if selection is available, "
  },
  {
    "path": "plugins/mp3conv",
    "chars": 949,
    "preview": "#!/usr/bin/env sh\n\n# Description: Extract audio from multimedia files and convert to mp3\n#\n# Dependencies: ffmpeg compil"
  },
  {
    "path": "plugins/mtpmount",
    "chars": 2033,
    "preview": "#!/usr/bin/env sh\n\n# Description: Toggle mount of MTP device (eg. Android device)\n#              'l' to list mountable d"
  },
  {
    "path": "plugins/nbak",
    "chars": 1582,
    "preview": "#!/usr/bin/env sh\n\n# Description: Backup nnn configuration\n#              - config dir content\n#              - environm"
  },
  {
    "path": "plugins/nmount",
    "chars": 3619,
    "preview": "#!/usr/bin/env sh\n\n# Description: Toggle mount status of a device using pmount\n#              If the device is not mount"
  },
  {
    "path": "plugins/nuke",
    "chars": 18869,
    "preview": "#!/usr/bin/env sh\n\n# Description: Sample script to play files in apps by file type or mime\n#\n# Shell: POSIX compliant\n# "
  },
  {
    "path": "plugins/oldbigfile",
    "chars": 322,
    "preview": "#!/usr/bin/env sh\n\n# Description: List files bigger than input size by ascending access date.\n#\n# Dependencies: find sor"
  },
  {
    "path": "plugins/openall",
    "chars": 1429,
    "preview": "#!/usr/bin/env bash\n\n# Description: Open selected files in nuke one by one or in oneshot\n#\n# Notes: 1. Opens the hovered"
  },
  {
    "path": "plugins/organize",
    "chars": 1685,
    "preview": "#!/usr/bin/env sh\n\n# Description: Organize files in directories by category\n#\n# Note: This plugin clears the selection a"
  },
  {
    "path": "plugins/pdfread",
    "chars": 737,
    "preview": "#!/usr/bin/env sh\n\n# Description: Read a text or PDF file in British English\n#\n# Shell: POSIX compliant\n# Author: Arun P"
  },
  {
    "path": "plugins/preview-tabbed",
    "chars": 6884,
    "preview": "#!/usr/bin/env bash\n\n# Description: tabbed/xembed based file previewer\n#\n# Dependencies:\n#   - tabbed (https://tools.suc"
  },
  {
    "path": "plugins/preview-tui",
    "chars": 23173,
    "preview": "#!/usr/bin/env bash\n\n# Description: Terminal based file previewer\n#\n# Note: This plugin needs a \"NNN_FIFO\" to work. See "
  },
  {
    "path": "plugins/pskill",
    "chars": 741,
    "preview": "#!/usr/bin/env sh\n\n# Description: Fuzzy list and kill a (zombie) process by name\n#\n# Dependencies: fzf, ps\n#\n# Note: To "
  },
  {
    "path": "plugins/renamer",
    "chars": 1202,
    "preview": "#!/usr/bin/env sh\n\n# Description: Batch rename selection or current directory with qmv or vidir\n#\n# Notes:\n#   - Try to "
  },
  {
    "path": "plugins/ringtone",
    "chars": 946,
    "preview": "#!/usr/bin/env sh\n\n# Description: Create an mp3 ringtone out of an audio file in any format\n#              Needs user to"
  },
  {
    "path": "plugins/rsynccp",
    "chars": 610,
    "preview": "#!/usr/bin/env sh\n\n# Description: Simple script to give copy-paste a progress percentage\n#              by utilizing rsy"
  },
  {
    "path": "plugins/splitjoin",
    "chars": 1419,
    "preview": "#!/usr/bin/env sh\n\n# Description: Splits the file passed as argument or joins selection\n#\n# Note: Adds numeric suffix to"
  },
  {
    "path": "plugins/suedit",
    "chars": 315,
    "preview": "#!/usr/bin/env sh\n\n# Description: Edit file as superuser\n#\n# Shell: POSIX compliant\n# Author: Anna Arad\n\nEDITOR=\"${EDITO"
  },
  {
    "path": "plugins/togglex",
    "chars": 540,
    "preview": "#!/usr/bin/env sh\n\n# Description: Toggles executable mode for selection\n#\n# Dependencies: chmod\n#\n# Note: Works _only_ w"
  },
  {
    "path": "plugins/umounttree",
    "chars": 1856,
    "preview": "#!/usr/bin/env sh\n\n# Description: Autodetects a nnn remote mountpoint (mounted with `c`)\n#              from any of its "
  },
  {
    "path": "plugins/upload",
    "chars": 1296,
    "preview": "#!/usr/bin/env sh\n\n# Description: Selections are archived into a tar file (uncompressed) and uploaded to file.io\n#      "
  },
  {
    "path": "plugins/wallpaper",
    "chars": 1355,
    "preview": "#!/usr/bin/env sh\n\n# Description: Set the selected image as wallpaper.\n# Uses nitrogen or pywal on X11, swww on wayland."
  },
  {
    "path": "plugins/x2sel",
    "chars": 1546,
    "preview": "#!/usr/bin/env sh\n\n# Description: Copy system clipboard newline-separated file list to selection\n#\n# Dependencies:\n#   -"
  },
  {
    "path": "plugins/xdgdefault",
    "chars": 1526,
    "preview": "#!/usr/bin/env sh\n\n# Description: Sets the xdg-open's default application for the current entry's file\n#              ty"
  },
  {
    "path": "src/.clang-tidy",
    "chars": 1760,
    "preview": "---\nChecks: >\n    clang-diagnostic-*,\n    clang-analyzer-*,\n    readability-*,\n    modernize-*,\n    bugprone-*,\n    misc"
  },
  {
    "path": "src/dbg.h",
    "chars": 2717,
    "preview": "/*\n * BSD 2-Clause License\n *\n * Copyright (C) 2014-2016, Lazaros Koromilas <lostd@2f30.org>\n * Copyright (C) 2014-2016,"
  },
  {
    "path": "src/icons-hash.c",
    "chars": 8826,
    "preview": "/*\n * simple program which outputs a hash-table of `icons_ext` with low collusion.\n * the hash function is case-insensit"
  },
  {
    "path": "src/icons-in-terminal.h",
    "chars": 132419,
    "preview": "#ifndef ICONS_IN_TERMINAL\n#define ICONS_IN_TERMINAL\n\n# define POWERLINE_BRANCH \"\\ue0a0\"\n# define POWERLINE_LINE_NUMBER \""
  },
  {
    "path": "src/icons.h",
    "chars": 18206,
    "preview": "#ifndef INCLUDE_ICONS_H\n#define INCLUDE_ICONS_H\n\n#if defined(ICONS_GENERATE) || defined(ICONS_ENABLED)\n\n/*\n * 1st arg = "
  },
  {
    "path": "src/nnn.c",
    "chars": 240748,
    "preview": "/*\n * BSD 2-Clause License\n *\n * Copyright (C) 2014-2016, Lazaros Koromilas <lostd@2f30.org>\n * Copyright (C) 2014-2016,"
  },
  {
    "path": "src/nnn.h",
    "chars": 7457,
    "preview": "/*\n * BSD 2-Clause License\n *\n * Copyright (C) 2014-2016, Lazaros Koromilas <lostd@2f30.org>\n * Copyright (C) 2014-2016,"
  },
  {
    "path": "src/qsort.h",
    "chars": 7430,
    "preview": "/*\n * Copyright (c) 2013, 2017 Alexey Tourbin\n *\n * Permission is hereby granted, free of charge, to any person obtainin"
  }
]

About this extraction

This page contains the full source code of the jarun/nnn GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 117 files (791.5 KB), approximately 260.3k tokens, and a symbol index with 242 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!