]> Sergey Matveev's repositories - nnn.git/commitdiff
nlay - a highly customizable file handler
authorArun Prakash Jana <engineerarun@gmail.com>
Sun, 23 Apr 2017 17:42:54 +0000 (23:12 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Sun, 23 Apr 2017 18:01:08 +0000 (23:31 +0530)
Makefile
Makefile.generic
README.md
config.def.h
nlay [new file with mode: 0755]
nnn.1
nnn.c

index bb450f910234a2ca3b19a9df21b6b604ae03d506..457da0c604980141a09fa7878acc4acb7b6f057c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,17 +6,18 @@ MANPREFIX = $(PREFIX)/share/man
 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 $@
@@ -30,11 +31,13 @@ $(BIN): $(SRC)
 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:
index 075ba0ceabdf2e5ebf6fb597617426d2f343b39f..c4e8fdd0416d34810676fff73d196d7d2faac81b 100644 (file)
@@ -6,17 +6,18 @@ MANPREFIX = $(PREFIX)/share/man
 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 $@
@@ -30,11 +31,13 @@ $(BIN): $(SRC)
 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:
index ba253e5203d20e32355cb8c480d515e7ac1f9d2e..93cbb90e3c0d5c89fd6c67a923628f591a67a446 100644 (file)
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ Noice is Not Noice, a noicer fork...
 - [Introduction](#introduction)
 - [Features](#features)
 - [Performance](#performance)
+- [nlay](#nlay)
 - [Installation](#installation)
 - [Usage](#usage)
   - [Cmdline options](#cmdline-options)
@@ -55,6 +56,7 @@ Have fun with it! PRs are welcome. Check out [#1](https://github.com/jarun/nnn/i
 - 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
@@ -88,6 +90,10 @@ nnn vs. mc vs. ranger memory usage while viewing a directory with 10,178 files,
 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.
@@ -180,22 +186,29 @@ The following abbreviations are used in the detail view:
 | `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
@@ -246,7 +259,11 @@ Start nnn and use `^K` to copy the absolute path (from `/`) of the file under th
 
 #### 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?
 
index 689aab5b7dfdfa749a66797d3a8bd1e6e7f3f667..28771bf879777677adbd44d3ccb8066cebd0fc17 100644 (file)
@@ -11,18 +11,15 @@ static int showhidden  = 0; /* Set to 1 to show hidden files by default */
 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,    "",     "" },
diff --git a/nlay b/nlay
new file mode 100755 (executable)
index 0000000..fd06307
--- /dev/null
+++ b/nlay
@@ -0,0 +1,119 @@
+#!/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
diff --git a/nnn.1 b/nnn.1
index 8b74150a07fae358b26c745933f066bbee772a5f..4fefe86b4e79761d73f7fa95cb84b3f7a977ca0a 100644 (file)
--- a/nnn.1
+++ b/nnn.1
@@ -106,9 +106,22 @@ supports the following options:
         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
@@ -154,22 +167,6 @@ type. Custom associations are listed in the EXAMPLES section below.
         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
diff --git a/nnn.c b/nnn.c
index 8c9029eaf301d6350a01981a1217401f9da62101..37a1938cb680421b0ea4901447db6f902f8a16df 100644 (file)
--- a/nnn.c
+++ b/nnn.c
@@ -68,7 +68,7 @@ xprintf(int fd, const char *fmt, ...)
 
 struct assoc {
        char *regex; /* Regex to match on filename */
-       char *bin;   /* Program */
+       char *mime; /* File type */
 };
 
 /* Supported actions */
@@ -134,7 +134,7 @@ static struct entry *dents;
 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;
@@ -384,23 +384,20 @@ strstrip(char *s)
 }
 
 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(&regex, assocs[i].regex,
                            REG_NOSUB | REG_EXTENDED | REG_ICASE) != 0)
                        continue;
-               if (regexec(&regex, file, 0, NULL, 0) == 0) {
-                       bin = assocs[i].bin;
-                       break;
-               }
+               if (regexec(&regex, file, 0, NULL, 0) == 0)
+                       return assocs[i].mime;
        }
-       DPRINTF_S(bin);
-       return bin;
+       return NULL;
 }
 
 static int
@@ -540,6 +537,7 @@ nextsel(char **run, char **env)
 {
        int c;
        unsigned int i;
+       static unsigned int len = LEN(bindings);
 
        c = getch();
        if (c == -1)
@@ -547,7 +545,7 @@ nextsel(char **run, char **env)
        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;
@@ -1248,7 +1246,7 @@ browse(char *ipath, char *ifilter)
        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;
@@ -1352,9 +1350,8 @@ nochange:
                        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",
@@ -1363,42 +1360,38 @@ nochange:
                                        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");
@@ -1788,7 +1781,7 @@ main(int argc, char *argv[])
        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");