diff options
| -rw-r--r-- | CMakeLists.txt | 4 | ||||
| -rw-r--r-- | LICENSE | 2 | ||||
| -rw-r--r-- | NEWS | 5 | ||||
| -rw-r--r-- | README.adoc | 18 | ||||
| -rwxr-xr-x | sdn-open | 72 | ||||
| -rw-r--r-- | sdn-open.1 | 23 | ||||
| -rw-r--r-- | sdn-view.1 | 5 | ||||
| -rw-r--r-- | sdn.1 | 7 | ||||
| -rw-r--r-- | sdn.cpp | 20 |
9 files changed, 135 insertions, 21 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d0a6042..7e62183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,9 +33,9 @@ include (GNUInstallDirs) # sdn-mc-ext should be in libexec, but we prefer it in PATH. install (TARGETS sdn sdn-mc-ext DESTINATION ${CMAKE_INSTALL_BINDIR}) -install (PROGRAMS sdn-install sdn-view +install (PROGRAMS sdn-install sdn-open sdn-view DESTINATION ${CMAKE_INSTALL_BINDIR}) -install (FILES sdn.1 sdn-install.1 sdn-view.1 +install (FILES sdn.1 sdn-install.1 sdn-open.1 sdn-view.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) @@ -1,4 +1,4 @@ -Copyright (c) 2017 - 2024, Přemysl Eric Janouch <p@janouch.name> +Copyright (c) 2017 - 2025, Přemysl Eric Janouch <p@janouch.name> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. @@ -5,7 +5,7 @@ Unreleased - + and - adjust the selection using shell globs; - t and T insert the selection into the external command line in relative or absolute form, respectively; - - Enter is like t but enters directories, and M-Enter is synonymous to t; + - Enter is like t but enters directories; - C-g or Escape clear the selection, similarly to the editor. * Added an sdn-view script that can process Midnight Commander mc.ext.ini files @@ -13,6 +13,9 @@ Unreleased while the original direct pager invocation has been moved to F13 (which also reflects Midnight Commander) + * Added an sdn-open script which does the same kind of processing as above + on top of xdg-open. This is what is now executed by M-Enter. + 1.0.0 (2024-12-21) diff --git a/README.adoc b/README.adoc index 8789821..b7aeecf 100644 --- a/README.adoc +++ b/README.adoc @@ -5,7 +5,8 @@ sdn 'sdn' is a simple directory navigator that you can invoke while editing shell commands. It enables you to: - * take a quick peek at directory contents without running `ls` + * take a quick peek at directory contents without running `ls`; + * select files to insert into the command line; * browse the filesystem without all the mess that Midnight Commander does: there's no need to create a subshell in a new pty. The current command line can be simply forwarded if it is to be edited. What's more, it will always @@ -75,6 +76,7 @@ that of git, only named colours aren't supported: .... cursor 231 202 +select 202 bold bar 16 255 ul cwd bold input @@ -91,15 +93,19 @@ To obtain more vifm-like controls, you may write the following to your .... normal h parent -normal l choose +normal l enter .... Helper programs ~~~~~~~~~~~~~~~ -The F3 and F4 keys are normally bound to actions 'view' and 'edit', similarly to -Norton Commander and other orthodox file managers. The helper programs used -here may be changed by setting the PAGER and VISUAL (or EDITOR) environment -variables. +The F3, F13 and F4 keys are normally bound to actions 'view', 'view-raw', +and 'edit', similarly to Norton Commander and other orthodox file managers. +The helper programs used here may be changed by setting the PAGER and VISUAL +(or EDITOR) environment variables. + +If 'view' finds Midnight Commander, it will make use of its configuration +to apply any matching filter, such as to produce archive listings, +or it will run the respective command. While it is mostly possible to get 'mcview' working using an invocation like `PAGER='mcview -u' sdn`, beware that this helper cannot read files from its diff --git a/sdn-open b/sdn-open new file mode 100755 index 0000000..5eb048f --- /dev/null +++ b/sdn-open @@ -0,0 +1,72 @@ +#!/bin/sh -e +# sdn-open: an opener for sdn that makes use of Midnight Commander configuration +# to make more kinds of files directly openable + +if [ "$#" -ne 1 ] +then + echo "Usage: $0 FILE" >&2 + exit 2 +fi + +# This handles both MC_DATADIR and odd installation locations. +datadir= +if command -v mc >/dev/null +then datadir=$(mc --datadir | sed 's/ (.*)$//') +fi + +config= +for dir in "$HOME"/.config/mc "$datadir" /etc/mc +do + if [ -n "$dir" -a -f "$dir/mc.ext.ini" ] + then + config=$dir/mc.ext.ini + break + fi +done + +# This is often used in %env{} expansion, so let's be on the same page. +export PAGER=${PAGER:-less} + +export MC_EXT_FILENAME=$(realpath "$1") +export MC_EXT_BASENAME=$(basename "$1") +export MC_EXT_CURRENTDIR=$(dirname "$MC_EXT_FILENAME") +output=$(sdn-mc-ext <"$config" "$(file -Lbz "$1")" \ + "$MC_EXT_FILENAME" "$MC_EXT_BASENAME" "$MC_EXT_CURRENTDIR" Open || :) +kind=$(echo "$output" | sed -n 1p) +command=$(echo "$output" | sed -n 2p) + +# We're trying to retain any explicit user preferences while navigating through: +# - Debian-based systems have /etc/alternatives/open as /usr/bin/open, +# pointing to either /usr/bin/xdg-open or /usr/bin/run-mailcap; +# - macOS has /usr/bin/open, and typically no xdg-open; +# - Windows Subsystem for Linux has explorer.exe in PATH, +# where launched applications may have problems with UNC paths, +# and possibly also xdg-open that may not be capable of opening much. +# +# Both macOS open and Windows explorer.exe are capable of opening files, +# directories, as well as URLs through native associations. +if [ -n "$MC_XDG_OPEN" ] +then : +elif command -v explorer.exe >/dev/null +then export MC_XDG_OPEN=explorer.exe +elif command -v open >/dev/null +then export MC_XDG_OPEN=open +elif command -v xdg-open >/dev/null +then export MC_XDG_OPEN=xdg-open +fi + +case "$kind" in +cd) + # These mostly enter virtual filesystems, which we do not understand. + "$MC_XDG_OPEN" "$MC_EXT_FILENAME" + ;; +'') + if [ -n "$command" ] + then eval "$command" + else "$MC_XDG_OPEN" "$MC_EXT_FILENAME" + fi + ;; +*) + echo "Unsupported: $kind" >&2 + exit 1 +esac diff --git a/sdn-open.1 b/sdn-open.1 new file mode 100644 index 0000000..b234329 --- /dev/null +++ b/sdn-open.1 @@ -0,0 +1,23 @@ +.Dd November 20, 2025 +.Dt SDN-OPEN 1 +.Os +.Sh NAME +.Nm sdn-open +.Nd run Midnight Commander open configuration externally +.Sh SYNOPSIS +.Nm sdn-open +.Ar path +.Sh DESCRIPTION +.Nm +invokes +.Xr xdg-open 1 +on the passed filename. +.Pp +If it succeeds in finding a +.Xr mc 1 +.Pa mc.ext.ini +file, it will first process it, and run any matching command instead. +.Sh REPORTING BUGS +Use +.Lk https://git.janouch.name/p/sdn +to report bugs, request features, or submit pull requests. @@ -1,4 +1,4 @@ -.Dd December 28, 2024 +.Dd December 30, 2024 .Dt SDN-VIEW 1 .Os .Sh NAME @@ -16,7 +16,8 @@ or a fallback pager on the passed filename. If it succeeds in finding a .Xr mc 1 .Pa mc.ext.ini -file, it will first process it, and apply any matching filter. +file, it will first process it, and apply any matching filter, +or run the respective command. .Sh REPORTING BUGS Use .Lk https://git.janouch.name/p/sdn @@ -1,5 +1,5 @@ \" https://mandoc.bsd.lv/man/roff.7.html#Sentence_Spacing -.Dd October 27, 2020 +.Dd December 30, 2024 .Dt SDN 1 .Os .Sh NAME @@ -95,7 +95,7 @@ names are used for special keys. To obtain more vifm-like controls and Windows-like quit abilities: .Bd -literal -offset indent normal h parent -normal l choose +normal l enter normal M-f4 quit .Ed .Pp @@ -107,7 +107,7 @@ For rxvt, that would be: define C-ppage ^[[5^ define C-npage ^[[6^ normal C-ppage parent -normal C-npage choose +normal C-npage enter .Ed .Pp Escape characters must be inserted verbatim, e.g., by pressing C-v ESC in vi, @@ -120,6 +120,7 @@ For a black-on-white terminal supporting 256 colours, a theme such as the following may work: .Bd -literal -offset indent cursor 231 202 +select 202 bold bar 16 255 ul cwd bold input @@ -1,7 +1,7 @@ // // sdn: simple directory navigator // -// Copyright (c) 2017 - 2024, Přemysl Eric Janouch <p@janouch.name> +// Copyright (c) 2017 - 2025, Přemysl Eric Janouch <p@janouch.name> // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted. @@ -430,8 +430,8 @@ enum { ALT = 1 << 24, SYM = 1 << 25 }; // Outside the range of Unicode #define CTRL(char) ((char) == '?' ? 0x7f : (char) & 0x1f) #define ACTIONS(XX) XX(NONE) XX(HELP) XX(QUIT) XX(QUIT_NO_CHDIR) \ - XX(ENTER) XX(CHOOSE) XX(CHOOSE_FULL) XX(VIEW_RAW) XX(VIEW) XX(EDIT) \ - XX(SORT_LEFT) XX(SORT_RIGHT) \ + XX(ENTER) XX(OPEN) XX(CHOOSE) XX(CHOOSE_FULL) \ + XX(VIEW_RAW) XX(VIEW) XX(EDIT) XX(SORT_LEFT) XX(SORT_RIGHT) \ XX(SELECT) XX(DESELECT) XX(SELECT_TOGGLE) XX(SELECT_ABORT) \ XX(UP) XX(DOWN) XX(TOP) XX(BOTTOM) XX(HIGH) XX(MIDDLE) XX(LOW) \ XX(PAGE_PREVIOUS) XX(PAGE_NEXT) XX(SCROLL_UP) XX(SCROLL_DOWN) XX(CENTER) \ @@ -453,7 +453,7 @@ static const char *g_action_names[] = {ACTIONS(XX)}; static map<wint_t, action> g_normal_actions { {'\r', ACTION_ENTER}, {KEY (ENTER), ACTION_ENTER}, - {ALT | '\r', ACTION_CHOOSE}, {ALT | KEY (ENTER), ACTION_CHOOSE}, + {ALT | '\r', ACTION_OPEN}, {ALT | KEY (ENTER), ACTION_OPEN}, {'t', ACTION_CHOOSE}, {'T', ACTION_CHOOSE_FULL}, {KEY (F (1)), ACTION_HELP}, {'h', ACTION_HELP}, {KEY (F (3)), ACTION_VIEW}, {KEY (F (13)), ACTION_VIEW_RAW}, @@ -1056,13 +1056,18 @@ fun run_program (initializer_list<const char *> list, const string &filename) { update (); } +fun sdn_open (const string &filename) { + run_program ({(const char *) getenv ("SDN_OPENER"), "sdn-open", "xdg-open"}, + filename); +} + fun view_raw (const string &filename) { // XXX: we cannot realistically detect that the pager hasn't made a pause // at the end of the file, so we can't ensure all contents have been seen run_program ({(const char *) getenv ("PAGER"), "less", "cat"}, filename); } -fun view (const string &filename) { +fun sdn_view (const string &filename) { run_program ({(const char *) getenv ("SDN_VIEWER"), "sdn-view", (const char *) getenv ("PAGER"), "less", "cat"}, filename); } @@ -1525,12 +1530,15 @@ fun handle (wint_t c) -> bool { case ACTION_ENTER: enter (current); break; + case ACTION_OPEN: + sdn_open (current.filename); + break; case ACTION_VIEW_RAW: // Mimic mc, it does not seem sensible to page directories (is_directory ? change_dir : view_raw) (current.filename); break; case ACTION_VIEW: - (is_directory ? change_dir : view) (current.filename); + (is_directory ? change_dir : sdn_view) (current.filename); break; case ACTION_EDIT: edit (current.filename); |
