Add and integrate sdn-open
Originally I thought that not supporting %cd would be an issue, making this kind of utility unclean. It turns out the desire to launch xdg-open quickly is stronger.
This commit is contained in:
@@ -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})
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -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
NEWS
5
NEWS
@@ -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)
|
||||
|
||||
|
||||
52
sdn-open
Executable file
52
sdn-open
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/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)
|
||||
|
||||
case "$kind" in
|
||||
cd)
|
||||
# These mostly enter virtual filesystems, which we do not understand.
|
||||
xdg-open "$MC_EXT_FILENAME"
|
||||
;;
|
||||
'')
|
||||
if [ -n "$command" ]
|
||||
then eval "$command"
|
||||
else xdg-open "$MC_EXT_FILENAME"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported: $kind" >&2
|
||||
exit 1
|
||||
esac
|
||||
23
sdn-open.1
Normal file
23
sdn-open.1
Normal file
@@ -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.
|
||||
20
sdn.cpp
20
sdn.cpp
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user