We use our own implementation of xdg-open that replace the hardcoded script used in sxmo_files. We add and will maintain some desktop entries to offer a suckless experience by default. Signed-off-by: Reed Wade <reedwade@misterbanal.net> Signed-off-by: Anjandev Momi <anjan@momi.ca>master
parent
a90f565c12
commit
08b95c6182
5 changed files with 344 additions and 14 deletions
@ -0,0 +1,6 @@ |
||||
[Desktop Entry] |
||||
Name=mpv Music Player |
||||
Exec=mpv -ao=alsa --vid=no -v |
||||
Terminal=true |
||||
Type=Application |
||||
MimeType=audio/wav;audio/opus;audio/m4a;audio/flac;audio/mp3 |
@ -0,0 +1,6 @@ |
||||
[Desktop Entry] |
||||
Name=sxiv Image Viewer |
||||
Exec=sxiv |
||||
Terminal=false |
||||
Type=Application |
||||
MimeType=image/jpeg;image/png;image/gif |
@ -0,0 +1,6 @@ |
||||
[Desktop Entry] |
||||
Name=Zathura |
||||
Exec=zathura |
||||
Terminal=false |
||||
Type=Application |
||||
MimeType=application/pdf;application/x-rar;application/epub+zip |
@ -0,0 +1,324 @@ |
||||
#!/usr/bin/env sh |
||||
|
||||
MIMEAPPS="${XDG_CONFIG_HOME:-$HOME/.config}/mimeapps.list" |
||||
DESKTOPS_CACHED_MIMEAPPS="${XDG_CONFIG_HOME:-$HOME/.config}/desktops.mimeapps.list" |
||||
DESKTOP_DIRS="/usr/share/sxmo/applications/|/usr/share/applications/|/usr/local/share/applications/|${XDG_DATA_HOME:-$HOME/.local/share}/applications/" |
||||
attached= |
||||
debug= |
||||
TERMCMD="${TERMCMD:-st -e}" |
||||
|
||||
# This will convert a mimeapps.list to a parsable mapping |
||||
# Lines with multiple mimetype will be splitted |
||||
# The mapping format is something as |
||||
# added;image/jpeg;bar.desktop |
||||
# added;image/jpeg;baz.desktop |
||||
# added;video/H264;bar.desktop |
||||
# default;image/jpeg;foo.desktop |
||||
# removed;video/H264;baz.desktop |
||||
mimeapps_to_desktop_mapping() { |
||||
[ ! -f "$1" ] && return |
||||
awk ' |
||||
/^\[Default Applications\]$/ { kind = "default" } |
||||
/^\[Added Associations\]$/ { kind = "added" } |
||||
/^\[Removed Associations\]$/ { kind = "removed" } |
||||
/=/ { |
||||
split($0, mime_desktops, "=") |
||||
split(mime_desktops[2], desktops, ";") |
||||
|
||||
for ( key in desktops ) { |
||||
print kind ";" mime_desktops[1] ";" desktops[key] |
||||
} |
||||
} |
||||
' "$1" |
||||
} |
||||
|
||||
# This will generate the added mapping from all destkop entries in a dir |
||||
get_mimeapps_entries_from_desktop_dir() { |
||||
for desktop_path in "$1"/*.desktop; do |
||||
grep --include "*.desktop" '^MimeType=' "$desktop_path" \ |
||||
| tr ';' '\n' \ |
||||
| cut -d= -f2 \ |
||||
| xargs -i{} printf "%s=%s\n" "{}" "$(basename "$desktop_path")" |
||||
done |
||||
} |
||||
|
||||
# Build and save the desktop mimeapps mapping if necessary |
||||
prepare_desktop_mimeapps_mapping_cache() { |
||||
last_desktop_modif_date="$(printf %s "$DESKTOP_DIRS" | tr '|' '\n' | while read -r desktop_dir; do |
||||
for desktop_file in "$desktop_dir"/*.desktop; do |
||||
stat -c %Y "$desktop_file" |
||||
done |
||||
done | sort -r | head -n1)" |
||||
|
||||
if [ -r "$DESKTOPS_CACHED_MIMEAPPS" ]; then |
||||
desktop_cache_modif_date="$(stat -c %Y "$DESKTOPS_CACHED_MIMEAPPS")" |
||||
if [ "$last_desktop_modif_date" -gt "$desktop_cache_modif_date" ]; then |
||||
rm "$DESKTOPS_CACHED_MIMEAPPS" |
||||
fi |
||||
fi |
||||
|
||||
if [ ! -r "$DESKTOPS_CACHED_MIMEAPPS" ]; then |
||||
IFS='|' |
||||
echo "[Added Associations]" > "$DESKTOPS_CACHED_MIMEAPPS" |
||||
for desktop_dir in $DESKTOP_DIRS; do |
||||
get_mimeapps_entries_from_desktop_dir "$desktop_dir" |
||||
done >> "$DESKTOPS_CACHED_MIMEAPPS" |
||||
fi |
||||
} |
||||
|
||||
find_desktop_path() { |
||||
desktop_name="$1" |
||||
|
||||
IFS='|' |
||||
for desktop_dir in $DESKTOP_DIRS; do |
||||
if [ -r "$desktop_dir/$desktop_name" ]; then |
||||
realpath "$desktop_dir/$desktop_name" |
||||
return |
||||
fi |
||||
done |
||||
} |
||||
|
||||
# This will take the full maping and simplify it which means |
||||
# * strip added entries with removed ones |
||||
# * put default entries first |
||||
# * remove duplicates lines |
||||
# following this format |
||||
# image/jpeg;foo.desktop |
||||
# image/jpeg;bar.desktop |
||||
# image/jpeg;baz.desktop |
||||
simplify_mapping() { |
||||
awk ' |
||||
function contains(array, value) { |
||||
for (key in array) { |
||||
if (array[key] == value) |
||||
return 1 |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
/^$/ {next} |
||||
|
||||
/^default;/ { kind = "default" } |
||||
/^added;/ { kind = "added" } |
||||
/^removed;/ { kind = "removed" } |
||||
|
||||
{ gsub(kind ";", "", $0) } |
||||
|
||||
kind == "default" { default_entries[NR]=$0 } |
||||
kind == "added" { added_entries[NR]=$0 } |
||||
kind == "removed" { removed_entries[NR]=$0 } |
||||
|
||||
END { |
||||
for (key in default_entries) { |
||||
print default_entries[key] |
||||
} |
||||
for (key in added_entries) { |
||||
entry = added_entries[key] |
||||
if (contains(removed_entries, entry)) { continue } |
||||
if (contains(default_entries, entry)) { continue } |
||||
print entry |
||||
} |
||||
} |
||||
' /dev/stdin |
||||
} |
||||
|
||||
get_mimeapps_mapping() { |
||||
prepare_desktop_mimeapps_mapping_cache |
||||
|
||||
printf '%s\n%s' \ |
||||
"$(mimeapps_to_desktop_mapping "$MIMEAPPS")" \ |
||||
"$(mimeapps_to_desktop_mapping "$DESKTOPS_CACHED_MIMEAPPS")" \ |
||||
| simplify_mapping |
||||
} |
||||
|
||||
filter_matching_desktops() { |
||||
mime_type="$1" |
||||
|
||||
grep "^$mime_type;" /dev/stdin \ |
||||
| cut -d";" -f2 |
||||
} |
||||
|
||||
curl_mime_type() { |
||||
curl --head -fsw '%{content_type}' "$1" | tail -n1 | sed 's|;.*||' |
||||
} |
||||
|
||||
extension_mime_type() { |
||||
[ ! -r "/etc/mime.types" ] && return # require mailcap |
||||
|
||||
ext="${1##*.}" |
||||
grep "\t.*$ext" /etc/mime.types | awk '{print $1}' |
||||
} |
||||
|
||||
get_mime_type() { |
||||
# Seems like an x-scheme |
||||
if echo "$1" | grep -q '^.\+:'; then |
||||
if echo "$1" | grep -q '^https\?:'; then |
||||
mime_type="$(curl_mime_type "$1")" |
||||
fi |
||||
|
||||
[ -z "$mime_type" ] && mime_type="x-scheme-handler/$(echo "$1" | grep -o '^\w\+')" |
||||
else |
||||
# is readable |
||||
if [ -r "$1" ]; then |
||||
mime_type="$(file -b --mime-type "$1")" |
||||
else |
||||
echo "This file does not exists?" > /dev/stderr |
||||
exit 1 |
||||
fi |
||||
fi |
||||
|
||||
# we try to be more precise then |
||||
if [ "application/octet-stream" = "$mime_type" ]; then |
||||
new_mime_type="$(extension_mime_type "$1")" |
||||
[ -n "$new_mime_type" ] && mime_type="$new_mime_type" |
||||
elif [ "inode/symlink" = "$mime_type" ]; then |
||||
real_path="$(realpath "$1")" |
||||
mime_type="$(get_mime_type "$real_path")" |
||||
fi |
||||
|
||||
echo "$mime_type" |
||||
} |
||||
|
||||
execute() { |
||||
if [ -n "$debug" ]; then |
||||
echo "The final command to execute is:" > /dev/stderr |
||||
echo "$@" > /dev/stderr |
||||
exit 0 |
||||
fi |
||||
|
||||
eval "$@" |
||||
} |
||||
|
||||
fetch_file() { |
||||
if [ -n "$debug" ]; then |
||||
echo "The file would be downloaded with '$*'" > /dev/stderr |
||||
return |
||||
fi |
||||
|
||||
eval "$@" |
||||
} |
||||
|
||||
build_command() { |
||||
exec="$1" |
||||
shift |
||||
|
||||
IFS=" |
||||
" |
||||
file_paths="$*" |
||||
unset IFS |
||||
|
||||
if echo "$exec" | grep -q '%f\|%F'; then # We must retrieve distant files |
||||
file_paths="$( |
||||
echo "$file_paths" | while read -r file_path; do |
||||
local_file_path="$(mktemp --suffix=".$(basename "$file_path")")" |
||||
if echo "$file_path" | grep -q '^https\?://'; then |
||||
fetch_file curl -so "$local_file_path" "$file_path" |
||||
else |
||||
echo "$file_path" |
||||
continue |
||||
fi |
||||
echo "$local_file_path" |
||||
done |
||||
)" |
||||
exec="$(echo "$exec" | sed -e 's|%f|%u|' -e 's|%F|%U|')" |
||||
fi |
||||
|
||||
file_paths="$(echo "$file_paths" | awk '{print "\"" $0 "\""}')" |
||||
|
||||
command= |
||||
if echo "$exec" | grep -q '%u'; then # handle url file one by one |
||||
exec="$(echo "$exec" | sed 's|%u|"%s"|')" |
||||
if [ "true" = "$terminal" ]; then |
||||
command="$(echo "$file_paths" | xargs printf "$TERMCMD $exec & " | sed 's| $||')" |
||||
else |
||||
command="$(echo "$file_paths" | xargs printf "$exec & " | sed -e 's|^ ||' -e 's| $||')" |
||||
fi |
||||
elif echo "$exec" | grep -q '%U'; then # handle url file grouped |
||||
exec_before="$(echo "$exec" | awk -F' %U' '{print $1}')" |
||||
exec_after="$(echo "$exec" | awk -F'%U ' '{$1=""; print $0}')" |
||||
command="$exec_before $(echo "$file_paths" | xargs printf '"%s" ')${exec_after:+ $exec_after }&" |
||||
if [ "true" = "$terminal" ]; then |
||||
command="$TERMCMD $command" |
||||
fi |
||||
else |
||||
command="$exec $(echo "$file_paths" | xargs printf '"%s" ')&" |
||||
if [ "true" = "$terminal" ]; then |
||||
command="$TERMCMD $command" |
||||
fi |
||||
fi |
||||
|
||||
echo "$command" |
||||
} |
||||
|
||||
run_desktop() { |
||||
desktop="$1" |
||||
shift |
||||
|
||||
desktop_path="$(find_desktop_path "$desktop")" |
||||
if [ -z "$desktop_path" ]; then |
||||
echo "We can't find the desktop file \"$desktop\"" > /dev/stderr |
||||
return |
||||
fi |
||||
|
||||
desktop_content="$(cat "$desktop_path")" |
||||
exec="$(echo "$desktop_content" | grep '^Exec=' | sed 's|^Exec=||' | head -n1)" |
||||
terminal="$(echo "$desktop_content" | grep '^Terminal=' | cut -d= -f2)" |
||||
[ -z "$terminal" ] && terminal="false" |
||||
|
||||
command="$(build_command "$exec" "$@")" |
||||
|
||||
if [ -n "$attached" ]; then |
||||
command="$(echo "$command" | sed 's| &|;|g')" |
||||
fi |
||||
|
||||
if [ -n "$debug" ]; then |
||||
echo "Exec is \"$exec\"" > /dev/stderr |
||||
echo "Terminal is \"$terminal\"" > /dev/stderr |
||||
echo "Command is \"$command\"" > /dev/stderr |
||||
exit 0 |
||||
fi |
||||
|
||||
eval "$command" |
||||
|
||||
exit 0 |
||||
} |
||||
|
||||
run() { |
||||
mime_type="$(get_mime_type "$1")" |
||||
|
||||
if [ -z "$mime_type" ]; then |
||||
echo "We failed to find the mime_type for \"$1\"" > /dev/stderr |
||||
exit 1 |
||||
fi |
||||
|
||||
desktops="$(get_mimeapps_mapping | filter_matching_desktops "$mime_type")" |
||||
|
||||
if [ -n "$debug" ]; then |
||||
echo "The mime type is \"$mime_type\"" > /dev/stderr |
||||
echo "The matching desktops are:" > /dev/stderr |
||||
echo "$desktops" > /dev/stderr |
||||
fi |
||||
|
||||
if [ -z "$desktops" ]; then |
||||
echo "There is no matching desktop to open \"$mime_type\"" > /dev/stderr |
||||
exit 1 |
||||
fi |
||||
|
||||
echo "$desktops" | while read -r desktop; do |
||||
run_desktop "$desktop" "$@" |
||||
done |
||||
} |
||||
|
||||
if [ "-d" = "$1" ]; then |
||||
debug="1" |
||||
shift |
||||
fi |
||||
|
||||
if [ "-a" = "$1" ]; then |
||||
attached="1" |
||||
shift |
||||
fi |
||||
|
||||
if [ $# -gt 0 ]; then |
||||
run "$@" |
||||
fi |
Loading…
Reference in new issue