42 Commits
0.1 ... master

Author SHA1 Message Date
fbt
cd53817db7 let the handlers, well, handle this
Signed-off-by: fbt <fbt@fleshless.org>
2022-12-23 14:13:13 +00:00
fbt
8f4b3af31c decode the URI always
Signed-off-by: fbt <fbt@fleshless.org>
2019-06-16 14:53:37 +03:00
fbt
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
fbt
d706122511 kek
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-01 20:20:59 +03:00
fbt
bdfa690762 remove redundant parts
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-01 19:59:02 +03:00
fbt
509f11cd87 Handle symlinks gracefully
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-01 19:23:59 +03:00
fbt
ada3aafd2c Tiny fix: make file follow symlinks
Signed-off-by: fbt <fbt@fleshless.org>
2018-08-01 18:27:45 +03:00
fbt
beae2098fb duh
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-29 10:10:08 +03:00
fbt
4d9c558264 bugfix
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 23:49:51 +03:00
fbt
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
fbt
5675a08012 exit here
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 20:21:26 +03:00
fbt
213c8e4ce2 Configuration is serious business
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 20:03:36 +03:00
fbt
614b2bea94 a key to disable desktop notifications
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 18:34:22 +03:00
fbt
240d35cba3 use notify-send if available
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 18:32:42 +03:00
fbt
2b1353ac9c wut?
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 17:50:32 +03:00
fbt
0b3468ed49 macro support
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 17:48:58 +03:00
fbt
a77e18d908 nify the handler functions
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 17:35:51 +03:00
fbt
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
fbt
739c430e42 even smarter DSL
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 16:49:08 +03:00
fbt
c054744d48 Allow multiple regexes to be specified
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 16:28:13 +03:00
fbt
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
fbt
7eef67695a cosmetics
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 07:47:43 +03:00
fbt
b10611f5ae code overhaul
Signed-off-by: fbt <fbt@fleshless.org>
2018-07-27 06:32:29 +03:00
fbt
6afb99d1ce filetype detection fix 2015-07-19 21:51:22 +03:00
fbt
0deb0b449c printf 2015-03-10 01:29:49 +03:00
fbt
597c801bdf Merge branch 'master' of builder:git/sx-open 2015-02-25 08:00:57 +03:00
fbt
0347154d6b wut 2015-02-25 08:00:47 +03:00
fbt
2470681dcb conflict 2015-02-19 14:03:49 +03:00
fbt
6cb89f0cd6 Code cleanup, thx to http://www.shellcheck.net 2015-01-17 16:38:52 +03:00
fbt
958ae3f264 associative arrays mess up sorting 2015-01-13 23:40:37 +03:00
fbt
303bdf5d71 that is also redundant 2014-11-26 16:00:03 +03:00
fbt
d8b9b5dc01 ^file:// is redundant 2014-11-26 15:59:17 +03:00
fbt
7696ea5ce8 ugh, making this work with mimes is annoying 2014-11-25 13:22:15 +03:00
fbt
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
fbt
97b1be6732 the hash table declarations don't need to be in the config. 2014-11-21 13:48:57 +03:00
fbt
545447c9b0 Handling files by name. Takes precedence over mimes. 2014-11-21 13:48:09 +03:00
fbt
93ec32f793 a usage function 2014-11-08 08:03:59 +03:00
fbt
02c7e5cb1a no more grep! 2014-10-16 13:46:57 +04:00
fbt
b32491ea9c Fixing a typo in the readme 2014-09-28 01:49:58 +04:00
fbt
31a48b9795 Hmm. The ISC licence looks better 2014-09-26 02:41:28 +04:00
fbt
6eb58fa18a The year is wrong 2014-09-26 02:34:10 +04:00
fbt
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'