Compare commits

...

42 Commits
0.1 ... master

Author SHA1 Message Date
Jack L. Frost cd53817db7 let the handlers, well, handle this
Signed-off-by: fbt <fbt@fleshless.org>
2022-12-23 14:13:13 +00:00
Jack L. Frost 8f4b3af31c decode the URI always
Signed-off-by: fbt <fbt@fleshless.org>
2019-06-16 14:53:37 +03:00
Jack L. Frost 27801d670f I have no ide how that piece of code got mangled
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-02 12:52:56 +03:00
Jack L. Frost d706122511 kek
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-01 20:20:59 +03:00
Jack L. Frost bdfa690762 remove redundant parts
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-01 19:59:02 +03:00
Jack L. Frost 509f11cd87 Handle symlinks gracefully
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-01 19:23:59 +03:00
Jack L. Frost ada3aafd2c Tiny fix: make file follow symlinks
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-01 18:27:45 +03:00
Jack L. Frost beae2098fb duh
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-29 10:10:08 +03:00
Jack L. Frost 4d9c558264 bugfix
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 23:49:51 +03:00
Jack L. Frost ccad66749c what are the chances you actually need literal '%template' in cmd?
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 20:43:04 +03:00
Jack L. Frost 5675a08012 exit here
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 20:21:26 +03:00
Jack L. Frost 213c8e4ce2 Configuration is serious business
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 20:03:36 +03:00
Jack L. Frost 614b2bea94 a key to disable desktop notifications
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 18:34:22 +03:00
Jack L. Frost 240d35cba3 use notify-send if available
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 18:32:42 +03:00
Jack L. Frost 2b1353ac9c wut?
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 17:50:32 +03:00
Jack L. Frost 0b3468ed49 macro support
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 17:48:58 +03:00
Jack L. Frost a77e18d908 nify the handler functions
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 17:35:51 +03:00
Jack L. Frost f68c9e817b This is why I stopped doing a release every few commits
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 17:02:22 +03:00
Jack L. Frost 739c430e42 even smarter DSL
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 16:49:08 +03:00
Jack L. Frost c054744d48 Allow multiple regexes to be specified
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 16:28:13 +03:00
Jack L. Frost 8493a07fdc Read pairs, no need for a separator this way
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 08:05:14 +03:00
Jack L. Frost 7eef67695a cosmetics
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 07:47:43 +03:00
Jack L. Frost b10611f5ae code overhaul
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 06:32:29 +03:00
Jack L. Frost 6afb99d1ce filetype detection fix 2015-07-19 21:51:22 +03:00
Jack L. Frost 0deb0b449c printf 2015-03-10 01:29:49 +03:00
Jack L. Frost 597c801bdf Merge branch 'master' of builder:git/sx-open 2015-02-25 08:00:57 +03:00
Jack L. Frost 0347154d6b wut 2015-02-25 08:00:47 +03:00
Jack L. Frost 2470681dcb conflict 2015-02-19 14:03:49 +03:00
Jack L. Frost 6cb89f0cd6 Code cleanup, thx to http://www.shellcheck.net 2015-01-17 16:38:52 +03:00
Jack L. Frost 958ae3f264 associative arrays mess up sorting 2015-01-13 23:40:37 +03:00
Jack L. Frost 303bdf5d71 that is also redundant 2014-11-26 16:00:03 +03:00
Jack L. Frost d8b9b5dc01 ^file:// is redundant 2014-11-26 15:59:17 +03:00
Jack L. Frost 7696ea5ce8 ugh, making this work with mimes is annoying 2014-11-25 13:22:15 +03:00
Jack L. Frost 214ab03647 No no no, that was ugly as hell. Files need to be handled as uris if we want to do so by name 2014-11-21 14:14:01 +03:00
Jack L. Frost 97b1be6732 the hash table declarations don't need to be in the config. 2014-11-21 13:48:57 +03:00
Jack L. Frost 545447c9b0 Handling files by name. Takes precedence over mimes. 2014-11-21 13:48:09 +03:00
Jack L. Frost 93ec32f793 a usage function 2014-11-08 08:03:59 +03:00
Jack L. Frost 02c7e5cb1a no more grep! 2014-10-16 13:46:57 +04:00
Jack L. Frost b32491ea9c Fixing a typo in the readme 2014-09-28 01:49:58 +04:00
Jack L. Frost 31a48b9795 Hmm. The ISC licence looks better 2014-09-26 02:41:28 +04:00
Jack L. Frost 6eb58fa18a The year is wrong 2014-09-26 02:34:10 +04:00
Jack L. Frost 6fd20205c4 add a license 2014-09-26 02:29:28 +04:00
4 changed files with 305 additions and 52 deletions

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
Copyright (c) 2014, Jack L. Frost <fbt@fleshless.org>
Permission to use, copy, modify, and/or distribute this software for any purpose with or without
fee is hereby granted, provided that the above copyright notice and this permission notice appear
in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.

View File

@ -1,10 +1,22 @@
sx-open
=======
# sx-open
sx-open is an attemt to implement a saner alternative to xdg-open.
sx-open is an attempt to implement a saner alternative to xdg-open.
Installation
------------
## Installation
Clone the repo, drop sx-open.cfg into your $HOME/.config.
Clone the repo, drop sx-open.cfg into your $HOME/.config and set it up to do what you want. There are no built-in defaults, it's all in the config.
As this thing is meant to replace xdg-open, you will probably want to link sx-open into xdg-open somewhere in your $PATH as to override the default one.
## Usage
sx-open [-dhv] <uri/file>
Flags:
-d Dry run
-v Verbose
-h Help
### Exit codes
* 1 — action failed
* 2 — file not found
* 3 — no handlers found

283
sx-open
View File

@ -1,51 +1,262 @@
#!/usr/bin/env bash
# This is an attempt to replace xdg-open with something sane.
# Source the config file.
cfg_file="$HOME/.config/sx-open.cfg"
[[ -f "$cfg_file" ]] && { source "$cfg_file"; }
usage() { echo "usage function not implemented yet."; }
handle_uri() {
local target="$1"
for h in "${!uri_handlers[@]}"; do
grep -oE "${uri_handlers[${h}]}" &>/dev/null <<< "$target" && {
${h} "$target" &
return 0
}
done
return 1
usage() {
cat <<- EOF
sx-open [-dhv] <uri/file>
Flags:
-d Dry run
-v Verbose mode
-n Disable desktop notifications
-h Help
EOF
}
handle_fs_target() {
local target="${1##*file://}"
act() {
cfg verbose && printf 'CMD: %s\n' "$*" >&2
cfg dryrun || { "$@"; return $?; }
target_mimetype=$(file -ib "$target")
for m in "${!mime_handlers[@]}"; do
grep -oE "${mime_handlers[${m}]}" &>/dev/null <<< "$target_mimetype" && {
${m} "$target" &
return 0
}
done
return 1
return 0
}
main() {
target="$1"
[[ "$target" ]] || { usage; exit; }
urldecode() { : "${*//+/ }"; printf '%b\n' "${_//%/\\x}"; }
if [[ -e "$target" || "$target" == 'file://'* ]]; then
handle_fs_target "$target"
# cfg foo bool = [true|1]
# cfg foo [string] = 'bar'
# cfg foo
cfg() {
declare s_name=$1; shift
declare -n \
_s="cfg[$s_name]" \
_s_type="cfg[${s_name}_type]"
if (( $# )); then
while (( $# )); do
case $1 in
(bool|str) _s_type="$1";;
(true|false|0|1)
_s_type='bool'
_s="$1"
break
;;
(=)
[[ $_s_type ]] || _s_type='string'
[[ $_s_type == 'bool' ]] && {
case $2 in
(true|false|0|1) true;;
(*)
error "On line $LINENO, in $FUNCNAME: Invalid value for '$s_name' type 'bool': '$2'"
exit 111
;;
esac
}
_s="$2"
break
;;
(*)
error "On line $LINENO, in $FUNCNAME: Syntax error: “cfg $s_name $*”"
exit 115
;;
esac
shift
done
else
handle_uri "$target"
[[ -n $_s ]] || {
error "On line $LINENO, in $FUNCNAME: invalid option: '$s_name'"
exit 113
}
case $_s_type in
(bool)
case $_s in
(true|1) return 0;;
(false|0) return 1;;
esac
;;
(*)
printf '%s\n' "$_s"
return 0
;;
esac
fi
}
notify() {
cfg notify || return 7 # disabled
[[ $DISPLAY ]] || return 3
[[ $notifier ]] || return 5
"${notifier[@]}" 'sx-open' "$@"
}
error() {
printf '%s\n' "$*" >&2
notify "$*"
}
# handle_target <res> <uri>
# 1: cmd failed
# 3: no handler
handle_target() {
declare -n result=$1
declare h cmd regex target_is_file target target_left cmd_is_template
cmd_append_target=1
match=0
target=$2
target_left=$target
if [[ -e "$target" ]]; then
target_is_file=1
[[ "$target" =~ ^/.* ]] || { target="${PWD}/${target}"; } # Turn relative paths to absolute ones.
IFS=';' read target_mimetype _ <<< $( file -ib "$target" )
target_left=$target_mimetype
[[ $target_mimetype == 'inode/symlink' ]] && \
IFS=';' read target_mimetype_true _ <<< $( file -ibL "$target" )
set -- "${mime_handlers[@]}"
elif is_uri "$target"; then
set -- "${uri_handlers[@]}"
else
return 2
fi
[[ "$?" -gt 0 ]] && { echo "No handlers found for $target"; }
while (( $# )); do
cmd_str=$1 regex=$2
cmd=()
# Fix the regex
[[ $regex =~ \^?([^\$]+)\$? ]] && regex="^${BASH_REMATCH[1]}$"
if [[ $cmd_str == *'%target%'* ]]; then
cmd=( ${cmd_str//%target%/$target} )
else
cmd=( $cmd_str "$target" )
fi
if [[ $target_left =~ $regex ]]; then
match=1
elif [[ $target_mimetype_true ]]; then
[[ $target_mimetype_true =~ $regex ]] && match=1
fi
if (( match )); then
act "${cmd[@]}"; result=$?
(( result )) && return 1
return 0
fi
shift 2
done
return 3
}
# DSL
uri() {
declare r handler=$1; shift
for r in "$@"; do
uri_handlers+=( "$handler" "$r" )
done
}
mime() {
declare r handler=$1; shift
for r in "$@"; do
mime_handlers+=( "$handler" "$r" )
done
}
scheme() {
declare r handler=$1; shift
for s in "$@"; do
uri_handlers+=( "$handler" "$s:.+" )
done
}
is_uri() [[ $1 =~ ^[a-zA-Z][a-zA-Z0-9\+\.\-]+:.+ ]]
main() {
declare cmd_result target
declare -gA cfg
cfg verbose bool = false
cfg dryrun bool = false
cfg notify bool = true
# Source the config file.
cfg_file="$HOME/.config/sx-open.cfg"
[[ -f "$cfg_file" ]] && { source "$cfg_file"; }
while (( $# )); do
case $1 in
(-d)
cfg dryrun = true
cfg verbose = true
;;
(-v) cfg verbose = true;;
(-n) cfg notify = false;; # disable desktop notifications
(-h) usage; return 0;;
(--) shift; break;;
(*) break;;
esac
shift
done
target=$1; [[ "$target" ]] || { usage; exit; }
# target=$(urldecode "$target") # No idea why I thought this was necessary.
cfg dryrun && {
printf 'Dry run: not actually running the handler\n' >&2
cfg verbose true
}
# Treat file:// as local paths.
[[ "$target" =~ ^file:(//)?(/.+) ]] && target=${BASH_REMATCH[2]}
# Figure out if we're in X and set $notifier if we are.
if [[ $DISPLAY ]]; then
# Do we have notify-send?
notifier=$(type -P 'notify-send')
fi
handle_target cmd_result "$target"
case $? in
(1)
error "Action on “$target” failed with exit code: “$cmd_result”"
return 4
;;
(2)
error "No such file or directory: “$target”"
return 2
;;
(3)
error "No handlers found for “$target”"
return 3
;;
esac
return 0
}

View File

@ -1,16 +1,33 @@
#!syntax bash
# Configuration file for sx-open
# Note that as sx-open checks the regexes in order, they should be placed in order from specific to less so.
# Regexes imply '^$'
declare -A uri_handlers
declare -A mime_handlers
# Disable desktop notifications
#cfg notify false
uri_handlers=(
["steam"]='^steam://.+'
["browser"]='.+'
)
# Enable verbose mode
#cfg verbose true
mime_handlers=(
["sxiv"]='image/.+'
)
# Enable dry run mode (implies verbose)
#cfg dryrun true
# vim: syntax=sh
# <cmd> macros:
# %target% — The first argument to this script.
# If not found, target is appended to the end of <cmd>
# example:
#uri 'browser %target% --profile=work' 'https://.+\.?workdomain\.tld\..*'
# scheme <cmd> <scheme>[ <scheme> ...]
#scheme browser http https
#scheme steam steam
# Or you can specify a regex for the entire uri:
# uri <cmd> <regex>[ <regex> ...]
#uri steam 'steam:.+'
#uri browser '(https?|ftp):.+'
# Mime types for filesystem targets:
# mime <cmd> <regex>[ <regex> ...]
#mime sxiv 'image/.+'
#mime libreoffice 'application/msword'