CFLAGS += -O3 -march=native -Wall -Wextra -Wno-unused-parameter
LDLIBS = -lreadline
ifeq ($(shell uname), Darwin)
- LDLIBS += -lncurses
+ LDLIBS += -lncurses
else
- LDLIBS += -lncursesw
+ LDLIBS += -lncursesw
endif
-DISTFILES = nnn.c config.def.h nnn.1 Makefile README.md LICENSE
+DISTFILES = nlay nnn.c config.def.h nnn.1 Makefile README.md LICENSE
LOCALCONFIG = config.h
SRC = nnn.c
BIN = nnn
+PLAYER = nlay
-all: $(BIN)
+all: $(BIN) $(PLAYER)
$(LOCALCONFIG): config.def.h
cp config.def.h $@
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
+ cp -f $(PLAYER) $(DESTDIR)$(PREFIX)/bin
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
cp -f $(BIN).1 $(DESTDIR)$(MANPREFIX)/man1
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN)
+ rm -f $(DESTDIR)$(PREFIX)/bin/$(PLAYER)
rm -f $(DESTDIR)$(MANPREFIX)/man1/$(BIN).1
dist:
CFLAGS += -O2 -Wall -Wextra -Wno-unused-parameter
LDLIBS = -lreadline
ifeq ($(shell uname), Darwin)
- LDLIBS += -lncurses
+ LDLIBS += -lncurses
else
- LDLIBS += -lncursesw
+ LDLIBS += -lncursesw
endif
-DISTFILES = nnn.c config.def.h nnn.1 Makefile README.md LICENSE
+DISTFILES = nlay nnn.c config.def.h nnn.1 Makefile README.md LICENSE
LOCALCONFIG = config.h
SRC = nnn.c
BIN = nnn
+PLAYER = nlay
-all: $(BIN)
+all: $(BIN) $(PLAYER)
$(LOCALCONFIG): config.def.h
cp config.def.h $@
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
+ cp -f $(PLAYER) $(DESTDIR)$(PREFIX)/bin
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
cp -f $(BIN).1 $(DESTDIR)$(MANPREFIX)/man1
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN)
+ rm -f $(DESTDIR)$(PREFIX)/bin/$(PLAYER)
rm -f $(DESTDIR)$(MANPREFIX)/man1/$(BIN).1
dist:
- [Introduction](#introduction)
- [Features](#features)
- [Performance](#performance)
+- [nlay](#nlay)
- [Installation](#installation)
- [Usage](#usage)
- [Cmdline options](#cmdline-options)
- Super-easy navigation with roll-over at edges
- Jump HOME or back to the last visited directory (as you normally do!)
- Desktop opener integration to handle mime types
+- Customizable bash script nlay to handle known file types
- Disk usage analyzer mode
- Basic and detail views
- Show stat and file information
28863 vaio 20 0 19876 6436 2620 S 0.0 0.1 0:00.19 nnn -d
```
+### nlay
+
+nnn comes with an easily customizable bash shell script to handle files - nlay. To know more about it, visit [nlay on wiki](https://github.com/jarun/nnn/wiki/all-about-nlay).
+
### Installation
nnn needs libreadline, libncursesw (on Linux or ncurses on OS X) and standard libc.
| `c` | Character Device |
#### File handling
+
+nnn is designed to play files using multiple strategies (in order of decreasing priority):
- Set `NNN_OPENER` to let a desktop opener handle it all. E.g.:
export NNN_OPENER=xdg-open
export NNN_OPENER="gio open"
export NNN_OPENER=gvfs-open
- - Selective file associations (ignored if `NNN_OPENER` is set):
- - vi - plain text files (determined using file)
- - mpv - common audio and video mimes
- - [zathura](https://pwmt.org/projects/zathura/) - pdf files
- - to customize further see [how to change file associations](#change-file-associations)
- - Set `NNN_FALLBACK_OPENER` as the fallback opener:
- - if the executable in static file association is missing
- - if a file type was not handled in static file association
+ - If nnn recognizes the file extension, it invokes nlay (which invokes the players). Default players:
+ - mpv - audio and video
+ - viewnior - image
+ - [zathura](https://pwmt.org/projects/zathura/) - pdf
+ - vim - plain text
+ - to add, remove recognized extensions in nnn, see [how to change file associations](#change-file-associations)
+ - If a file without any extension is a plain text file, it is opened in vi
+ - Set `NNN_FALLBACK_OPENER` as the fallback opener. E.g.:
+
+ export NNN_FALLBACK_OPENER=xdg-open
+ export NNN_FALLBACK_OPENER="gio open"
+ export NNN_FALLBACK_OPENER=gvfs-open
- To enable the desktop file manager key, set `NNN_DE_FILE_MANAGER`. E.g.:
export NNN_DE_FILE_MANAGER=thunar
+ export NNN_DE_FILE_MANAGER=nautilus
- [mediainfo](https://mediaarea.net/en/MediaInfo) is required to view media information
#### Help
#### Change file associations
-If you want to set custom applications for certain mime types, or change the ones set already (e.g. vi, mpv, zathura), modify the `assocs` structure in [config.def.h](https://github.com/jarun/nnn/blob/master/config.def.h) (it's easy). Then re-compile and install.
+If `NNN_OPENER` is not set, nnn tries to recognize a file by the file extension and invokes nlay. To change the extensions recognized by nnn, modify the `assocs` structure in [config.def.h](https://github.com/jarun/nnn/blob/master/config.def.h) (it's easy). Then re-compile and install.
+
+If you want to add a file extension mainline, please raise a bug. Without it nnn will not invoke nlay.
+
+nlay has provisions (disabled by default) to handle a specific file extension too. However, the extension should be recognized by nnn first.
### Why fork?
static int showdetail = 0; /* Set to show additional file info */
static char *idlecmd = "rain"; /* The screensaver program */
-struct assoc assocs[] = {
- { "\\.(c|cpp|h|txt|log|sh)$", "vi" },
- { "\\.(avi|mp4|mkv|3gp|mov)$", "mpv" },
- { "\\.(wma|mp3|ogg|flac|m4a)$", "mpv" },
- { "\\.(png|jpg|gif)$", "viewnior" },
- //{ "\\.(html|svg)$", "firefox" },
- { "\\.pdf$", "zathura" },
- //{ "\\.sh$", "sh" },
- //{ ".", "less" },
+static struct assoc assocs[] = {
+ { "\\.(c|cpp|h|log|md|py|sh|txt)$", "text" },
+ { "\\.(3g2|3gp|asf|avi|divx|flv|m2v|m4v|mkv|mov|mp4|mp4v|mpeg|mpg|ogv|qt|rm|rmvb|vob|webm|wmv)$", "video" },
+ { "\\.(aac|ac3|amr|flac|m4a|m4b|m4p|mp3|mp4a|ogg|opus|ra|wav|wma)$", "audio" },
+ { "\\.(bmp|gif|jpeg|jpg|pbm|pgm|png|svg|tiff|webp)$", "image" },
+ { "\\.pdf$", "pdf" },
};
-struct key bindings[] = {
+static struct key bindings[] = {
/* Quit */
{ 'q', SEL_QUIT, "", "" },
{ 'Q', SEL_CDQUIT, "", "" },
--- /dev/null
+#!/bin/bash
+
+# #############################################################################
+# nlay: a customizable script to play files in different apps by file type
+#
+# usage: nlay file type
+#
+# MUST READ:
+#
+# 1. Feel free to change the default apps to your favourite ones.
+# If you change the app for a group you may also need to modify the bg
+# setting. If bg is set the app is detached and started in the background in
+# silent mode.
+#
+# The bg setting depends on personal preference and type of app, e.g.,
+# I would start vim (CLI) in the foreground but Sublime Text (GUI) in the
+# background.
+#
+# Check (and TOGGLE as you wish) the default bg settings.
+#
+# 2. Detached apps are not killed when nnn exits. Use kill(1) or killall(1) to
+# to stop console based background apps.
+#
+# 3. Assuming you don't to play multiple audio/video files simultaneously,
+# nlay kills any running instances of the audio/video player in bg mode.
+#
+# 4. Keep a personal backup (on GitHub Gist maybe?) of this file if you modify
+# it. nlay is OVERWRITTEN during nnn upgrade.
+#
+# Author: Arun Prakash Jana
+# Email: engineerarun@gmail.com
+# #############################################################################
+
+
+# Enable the lines below to handle file by extension
+# This is provided for using a custom player for specific files
+# $ext holds the extension
+<<ENABLE_FILE_TYPE_HANDLING
+fname=$(basename "$1")
+if [[ $fname != *"."* ]]; then
+ exit 1
+fi
+
+ext="${fname##*.}"
+if [ -z "$ext" ]; then
+ exit 1
+fi
+
+# bash 4.0 way to switch to lowercase
+ext="${ext,,}"
+
+# handle this extension and exit
+ENABLE_FILE_TYPE_HANDLING
+
+
+#------------------ AUDIO -------------------
+if [ "$2" == "audio" ]; then
+ app=mpv
+ # To start mpv in a window enable audio_opts
+ #audio_opts="--no-terminal --force-window"
+
+ #bg=">/dev/null 2>&1 &"
+
+ if [ -n "$bg" ]; then
+ killall -9 $app >/dev/null 2>&1
+ fi
+
+ eval $app $audio_opts "\"$1\"" $bg
+ exit 0
+fi
+
+#------------------ VIDEO -------------------
+if [ "$2" == "video" ]; then
+ app=mpv
+ # To start mpv in a window enable video_opts
+ #video_opts="--no-terminal --force-window"
+
+ #bg=">/dev/null 2>&1 &"
+
+ if [ -n "$bg" ]; then
+ killall -9 $app >/dev/null 2>&1
+ fi
+
+ eval $app $video_opts "\"$1\"" $bg
+ exit 0
+fi
+
+#------------------ IMAGE -------------------
+if [ "$2" == "image" ]; then
+ app=viewnior
+ #image_opts=
+
+ bg=">/dev/null 2>&1 &"
+
+ eval $app $image_opts "\"$1\"" $bg
+ exit 0
+fi
+
+#------------------- PDF --------------------
+if [ "$2" == "pdf" ]; then
+ app=zathura
+ #pdf_opts=
+
+ bg=">/dev/null 2>&1 &"
+
+ eval $app $pdf_opts "\"$1\"" $bg
+ exit 0
+fi
+
+#---------------- PLAINTEXT -----------------
+if [ "$2" == "text" ]; then
+ app=vim
+ #txt_opts=
+
+ #bg=">/dev/null 2>&1 &"
+
+ eval $app $txt_opts "\"$1\"" $bg
+ exit 0
+fi
show program help and exit
.Sh CONFIGURATION
.Nm
+invokes
+.Pa nlay
+to play a file if it recognizes a file by extension.
+.Pa nlay
+is a
+highly customizable bash shell script which invokes a player depending on the
+type of file. Read more on
+.Pa nlay
+at:
+.br
+.Em https://github.com/jarun/nnn/wiki/all-about-nlay
+.Pp
+.Nm
is configured by modifying
-.Pa config.h
-and recompiling the code.
+.Pa config.def.h
+and recompiling the code. config.h is generated as a backup of config.def.h.
.Pp
See the environment and examples sections below for more options and information.
.Pp
echo -n $1 | xsel --clipboard --input
-------------------------------------
.Ed
-.Sh EXAMPLES
-The following example shows one possible configuration for
-file associations which is also the default if environment
-variable NNN_OPENER is not set:
-.Bd -literal
- -----------------------------------------------
- struct assoc assocs[] = {
- { "\\.(c|cpp|h|txt|log|sh)$", "vi" },
- { "\\.(wma|mp3|ogg|flac)$", "mpv" },
- { "\\.pdf$", "zathura" },
- };
- -----------------------------------------------
-Plain text files are opened with vi.
-.br
-Any other file types are opened with the 'xdg-open' command.
-.Ed
.Sh KNOWN ISSUES
If you are using urxvt you might have to set backspacekey to DEC.
.Sh AUTHORS
struct assoc {
char *regex; /* Regex to match on filename */
- char *bin; /* Program */
+ char *mime; /* File type */
};
/* Supported actions */
static int ndents, cur, total_dents;
static int idle;
static char *opener;
-static char *fallback_opener;
+static char *fb_opener;
static char *copier;
static char *desktop_manager;
static off_t blk_size;
}
static char *
-openwith(char *file)
+getmime(char *file)
{
regex_t regex;
- char *bin = NULL;
unsigned int i;
+ static unsigned int len = LEN(assocs);
- for (i = 0; i < LEN(assocs); i++) {
+ for (i = 0; i < len; i++) {
if (regcomp(®ex, assocs[i].regex,
REG_NOSUB | REG_EXTENDED | REG_ICASE) != 0)
continue;
- if (regexec(®ex, file, 0, NULL, 0) == 0) {
- bin = assocs[i].bin;
- break;
- }
+ if (regexec(®ex, file, 0, NULL, 0) == 0)
+ return assocs[i].mime;
}
- DPRINTF_S(bin);
- return bin;
+ return NULL;
}
static int
{
int c;
unsigned int i;
+ static unsigned int len = LEN(bindings);
c = getch();
if (c == -1)
else
idle = 0;
- for (i = 0; i < LEN(bindings); i++)
+ for (i = 0; i < len; i++)
if (c == bindings[i].sym) {
*run = bindings[i].run;
*env = bindings[i].env;
static char path[PATH_MAX], oldpath[PATH_MAX], newpath[PATH_MAX];
static char lastdir[PATH_MAX];
static char fltr[LINE_MAX];
- char *bin, *dir, *tmp, *run, *env;
+ char *mime, *dir, *tmp, *run, *env;
struct stat sb;
regex_t re;
int r, fd;
case S_IFREG:
{
static char cmd[MAX_CMD_LEN];
- static char *runvi = "vi";
- /* If default mime opener is set, use it */
+ /* If NNN_OPENER is set, use it */
if (opener) {
snprintf(cmd, MAX_CMD_LEN,
"%s \"%s\" > /dev/null 2>&1",
continue;
}
- /* Try custom applications */
- bin = openwith(newpath);
+ /* Play with nlay if identified */
+ mime = getmime(dents[cur].name);
+ if (mime) {
+ snprintf(cmd, MAX_CMD_LEN, "nlay \"%s\" %s",
+ newpath, mime);
+ exitcurses();
+ r = system(cmd);
+ initcurses();
+ continue;
+ }
- /* If custom app doesn't exist try fallback */
- snprintf(cmd, MAX_CMD_LEN, "which \"%s\"", bin);
+ /* If nlay doesn't handle it, open plain text
+ files with vi, then try NNN_FALLBACK_OPENER */
+ snprintf(cmd, MAX_CMD_LEN,
+ "file \"%s\"", newpath);
if (get_output(cmd, MAX_CMD_LEN) == NULL)
- bin = NULL;
+ continue;
- if (bin == NULL) {
- /* If a custom handler application is
- not set, open plain text files with
- vi, then try fallback_opener */
- snprintf(cmd, MAX_CMD_LEN,
- "file \"%s\"", newpath);
- if (get_output(cmd, MAX_CMD_LEN) == NULL)
- goto nochange;
-
- if (strstr(cmd, "ASCII text") != NULL)
- bin = runvi;
- else if (fallback_opener) {
- snprintf(cmd, MAX_CMD_LEN,
- "%s \"%s\" > \
- /dev/null 2>&1",
- fallback_opener,
- newpath);
- r = system(cmd);
- continue;
- } else {
- printmsg("No association");
- goto nochange;
- }
+ if (strstr(cmd, "ASCII text") != NULL) {
+ exitcurses();
+ spawn("vi", newpath, NULL, 0);
+ initcurses();
+ continue;
+ } else if (fb_opener) {
+ snprintf(cmd, MAX_CMD_LEN, "%s \"%s\" > /dev/null 2>&1",
+ fb_opener, newpath);
+ r = system(cmd);
+ continue;
}
- exitcurses();
- spawn(bin, newpath, NULL, 0);
- initcurses();
- continue;
+
+ printmsg("No association");
+ goto nochange;
}
default:
printmsg("Unsupported file");
opener = getenv("NNN_OPENER");
/* Get the fallback desktop mime opener, if set */
- fallback_opener = getenv("NNN_FALLBACK_OPENER");
+ fb_opener = getenv("NNN_FALLBACK_OPENER");
/* Get the desktop file browser, if set */
desktop_manager = getenv("NNN_DE_FILE_MANAGER");