Added local flake for xdg-terminal-exec; let's see if it works
This commit is contained in:
parent
c4408bba73
commit
d60f246610
|
|
@ -103,11 +103,15 @@
|
|||
# List packages installed in system profile. To search, run:
|
||||
# $ nix search wget
|
||||
environment.systemPackages = with pkgs; [
|
||||
xdg-terminal-exec.defaultPackage
|
||||
neovim
|
||||
git
|
||||
gay # very important, do not remove
|
||||
];
|
||||
|
||||
# Enable dconf; necessary for some programs
|
||||
programs.dconf.enable = true;
|
||||
|
||||
# Some programs need SUID wrappers, can be configured further or are
|
||||
# started in user sessions.
|
||||
# programs.mtr.enable = true;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,12 @@
|
|||
description = "NixOS configuration with flakes";
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
# nixos-hardware.url = "github:NixOS/nixos-hardware/master" # Why does this exist on my macbook?
|
||||
|
||||
xdg-terminal-exec = {
|
||||
url = "path:./xdg-terminal-exec";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
|
@ -11,7 +15,7 @@
|
|||
|
||||
# nur.url = "github:nix-community/NUR";
|
||||
};
|
||||
outputs = { self, nixpkgs, home-manager }:
|
||||
outputs = { self, nixpkgs, home-manager, xdg-terminal-exec }:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
in
|
||||
|
|
@ -19,6 +23,7 @@
|
|||
nixosConfigurations = {
|
||||
oyvoLaptop = nixpkgs.lib.nixosSystem {
|
||||
inherit system;
|
||||
_module.args = { inherit xdg-terminal-exec; };
|
||||
modules = [
|
||||
./configuration.nix
|
||||
home-manager.nixosModules.home-manager
|
||||
|
|
|
|||
4
flakes/xdg-terminal-exec/builder.sh
Normal file
4
flakes/xdg-terminal-exec/builder.sh
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export PATH="$coreutils/bin"
|
||||
mkdir $out
|
||||
mkdir $out/bin
|
||||
cp $src $out/bin/xdg-terminal-exec
|
||||
25
flakes/xdg-terminal-exec/flake.lock
Normal file
25
flakes/xdg-terminal-exec/flake.lock
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1704161960,
|
||||
"narHash": "sha256-QGua89Pmq+FBAro8NriTuoO/wNaUtugt29/qqA8zeeM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "63143ac2c9186be6d9da6035fa22620018c85932",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
11
flakes/xdg-terminal-exec/flake.nix
Normal file
11
flakes/xdg-terminal-exec/flake.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
description = "A very basic flake";
|
||||
|
||||
outputs = { self, nixpkgs }: {
|
||||
|
||||
packages.x86_64-linux.xdg-terminal-exec = nixpkgs.legacyPackages.x86_64-linux.xdg-terminal-exec;
|
||||
|
||||
packages.x86_64-linux.default = self.packages.x86_64-linux.xdg-terminal-exec;
|
||||
|
||||
};
|
||||
}
|
||||
1
flakes/xdg-terminal-exec/result
Symbolic link
1
flakes/xdg-terminal-exec/result
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
/nix/store/gb9xw4vfrq50f63hpzwq1rxda25hjc2k-xdg-terminal-exec
|
||||
599
flakes/xdg-terminal-exec/xdg-terminal-exec
Executable file
599
flakes/xdg-terminal-exec/xdg-terminal-exec
Executable file
|
|
@ -0,0 +1,599 @@
|
|||
#!/bin/sh
|
||||
# Proposal for XDG terminal execution utility
|
||||
#
|
||||
# by Vladimir Kudrya
|
||||
# https://github.com/Vladimir-csp/
|
||||
#
|
||||
# This script is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version. See <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Contributors:
|
||||
# Roman Chistokhodov https://github.com/FreeSlave/
|
||||
# fluvf https://github.com/fluvf
|
||||
|
||||
# Treat non-zero exit status from simple commands as an error
|
||||
# Treat unset variables as errors when performing parameter expansion
|
||||
# Disable pathname expansion
|
||||
set -euf
|
||||
|
||||
# Store original IFS value, assumed to contain the default: <space><tab><newline>
|
||||
OIFS="$IFS"
|
||||
# Newline, utility variable used throughout the script
|
||||
N='
|
||||
'
|
||||
|
||||
# Utility function to print messages to stderr
|
||||
error() { printf '%s\n' "$@" >&2; }
|
||||
|
||||
check_bool() {
|
||||
case "$1" in
|
||||
true | True | TRUE | yes | Yes | YES | 1) return 0 ;;
|
||||
false | False | FALSE | no | No | NO | 0) return 1 ;;
|
||||
*)
|
||||
error "Assuming '$1' means no"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Utility function to print debug messages to stderr (or not)
|
||||
if check_bool "${DEBUG-0}"; then
|
||||
debug() { printf 'D: %s\n' "$@" >&2; }
|
||||
else
|
||||
debug() { :; }
|
||||
fi
|
||||
|
||||
# Populates global constants and lists for later use and iteration
|
||||
make_paths() {
|
||||
IFS=':'
|
||||
|
||||
# Populate list of config files to read, in descending order of preference
|
||||
for dir in ${XDG_CONFIG_HOME:-"${HOME}/.config"}${IFS}${XDG_CONFIG_DIRS:-/etc/xdg}; do
|
||||
# Normalise base path and append the data subdirectory with a trailing '/'
|
||||
for desktop in ${LOWERCASE_XDG_CURRENT_DESKTOP}; do
|
||||
CONFIGS=${CONFIGS:+${CONFIGS}${IFS}}${dir%/}/${desktop}-xdg-terminals.list
|
||||
done
|
||||
CONFIGS=${CONFIGS:+${CONFIGS}${IFS}}${dir%/}/xdg-terminals.list
|
||||
done
|
||||
|
||||
# Populate list of directories to search for entries in, in ascending order of preference
|
||||
for dir in ${XDG_DATA_HOME:-${HOME}/.local/share}${IFS}${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do
|
||||
# Normalise base path and append the data subdirectory with a trailing '/'
|
||||
APPLICATIONS_DIRS=${dir%/}/applications/${APPLICATIONS_DIRS:+${IFS}${APPLICATIONS_DIRS}}
|
||||
done
|
||||
|
||||
# cache
|
||||
XDG_CACHE_HOME=${XDG_CACHE_HOME:-"${HOME}/.cache"}
|
||||
CACHE_FILE="${XDG_CACHE_HOME}/xdg-terminal-exec"
|
||||
|
||||
debug "paths:" "CONFIGS=${CONFIGS}" "APPLICATIONS_DIRS=${APPLICATIONS_DIRS}"
|
||||
}
|
||||
# Mask IFS withing function to allow temporary changes
|
||||
alias make_paths='IFS= make_paths'
|
||||
|
||||
gen_hash() {
|
||||
# return md5 of XDG_CURRENT DESKTOP and ls -LRl output for config and data paths
|
||||
# md5 is 4x faster than sha*, and there is no need for cryptography here
|
||||
# shellcheck disable=SC2034
|
||||
read -r hash drop <<- EOH
|
||||
$(
|
||||
hash_paths="${CONFIGS}:${APPLICATIONS_DIRS}"
|
||||
{
|
||||
echo "${XDG_CURRENT_DESKTOP-}"
|
||||
IFS=':'
|
||||
# shellcheck disable=SC2086
|
||||
debug "> hashing '${XDG_CURRENT_DESKTOP-}' and listing of:" $hash_paths "^ end of hash listing"
|
||||
# shellcheck disable=SC2012,SC2086
|
||||
LANG=C ls -LRl ${hash_paths} 2> /dev/null
|
||||
} | md5sum 2> /dev/null
|
||||
)
|
||||
EOH
|
||||
case "$hash" in
|
||||
[0-9a-f]??????????????????????????????[0-9a-f])
|
||||
debug "got fresh hash '$hash'"
|
||||
echo "$hash"
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
debug "failed to get fresh hash, got '$hash'"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
read_cache() {
|
||||
# reads $cached_hash, $cached_exec, $cached_execarg, $cached_cmd from cache file,
|
||||
# checks if cache is actual and applies it, otherwise returns 1
|
||||
# tries to bail out as soon as possible if something does not fit
|
||||
if [ -f "${CACHE_FILE}" ]; then
|
||||
IFS=${N}
|
||||
line_num=0
|
||||
while read -r line; do
|
||||
line_num=$((line_num + 1))
|
||||
case "${line_num}_${line}" in
|
||||
1_[0-9a-f]??????????????????????????????[0-9a-f]) cached_hash=$line ;;
|
||||
2_*) cached_exec=$line ;;
|
||||
3_ | 3_*) cached_execarg=$line ;;
|
||||
4_*)
|
||||
# get cmd and break right away, line_num will be left at 4
|
||||
cached_cmd=$line
|
||||
break
|
||||
;;
|
||||
*)
|
||||
debug "cache line ${line_num} is invalid: ${line}"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done < "${CACHE_FILE}"
|
||||
if [ "$line_num" = "4" ]; then
|
||||
debug "got cache:" "${cached_hash}" "${cached_exec}" "${cached_execarg}" "${cached_cmd}"
|
||||
IFS=$OIFS
|
||||
HASH=$(gen_hash) || return 1
|
||||
if [ "$HASH" = "$cached_hash" ] && command -v "$cached_cmd" > /dev/null; then
|
||||
debug "cache is actual"
|
||||
EXEC=${cached_exec}
|
||||
EXECARG=${cached_execarg}
|
||||
return 0
|
||||
else
|
||||
debug "cache is out-of-date"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
debug "invalid cache data"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
debug "no cache data"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
# Mask IFS withing function to allow temporary changes
|
||||
alias read_cache='IFS= read_cache'
|
||||
|
||||
save_cache() {
|
||||
# saves $HASH, $EXEC, $EXECARG, $1 (executable) to cache file or removes it if CACHE_ENABLE is false
|
||||
if check_bool "$CACHE_ENABLED"; then
|
||||
[ ! -d "${XDG_CACHE_HOME}" ] && mkdir -p "${XDG_CACHE_HOME}"
|
||||
if [ -z "${HASH-}" ]; then
|
||||
HASH=$(gen_hash) || {
|
||||
echo "could not hash listing, removing '${CACHE_FILE}'" >&2
|
||||
rm -f "${CACHE_FILE}"
|
||||
return 0
|
||||
}
|
||||
fi
|
||||
UM=$(umask)
|
||||
umask 0077
|
||||
printf '%s\n' "${HASH}" "${EXEC}" "${EXECARG}" "${1}" > "${CACHE_FILE}"
|
||||
umask "$UM"
|
||||
debug "> saved cache:" "${HASH}" "${EXEC}" "${EXECARG}" "${1}" "^ end of saved cache"
|
||||
else
|
||||
debug "cache is disabled, removing '${CACHE_FILE}'"
|
||||
rm -f "${CACHE_FILE}"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Parse all config files and populate $ENTRY_IDS with read desktop entry IDs
|
||||
read_config_paths() {
|
||||
# All config files are read immediatelly, rather than on demand, even if it's more IO intensive
|
||||
# This way all IDs are already known, and in order of preference, before iterating over them
|
||||
IFS=':'
|
||||
for config_path in ${CONFIGS}; do
|
||||
debug "reading config '$config_path'"
|
||||
# Nonexistant file is not an error
|
||||
[ -f "$config_path" ] || continue
|
||||
# Let `read` trim leading/trailing whitespace from the line
|
||||
while IFS="$OIFS" read -r line; do
|
||||
#debug "read line '$line'"
|
||||
case $line in
|
||||
|
||||
# Catch directives first
|
||||
|
||||
# cache control
|
||||
/enable_cache)
|
||||
debug "found '$line' directive${XTE_CACHE_ENABLED+ (ignored)}"
|
||||
CACHE_ENABLED=${XTE_CACHE_ENABLED-true}
|
||||
;;
|
||||
/disable_cache)
|
||||
debug "found '$line' directive${XTE_CACHE_ENABLED+ (ignored)}"
|
||||
CACHE_ENABLED=${XTE_CACHE_ENABLED-false}
|
||||
;;
|
||||
|
||||
# `[The extensionless entry filename] should be a valid D-Bus well-known name.`
|
||||
# `a sequence of non-empty elements separated by dots (U+002E FULL STOP),
|
||||
# none of which starts with a digit, and each of which contains only characters from the set [a-zA-Z0-9-_]`
|
||||
# Stricter parts seem to be related only to reversed DNS notation but not common naming
|
||||
# i.e. there is `2048-qt.desktop`.
|
||||
# I do not know of any terminal that starts with a number, but it's valid.
|
||||
|
||||
# Catch and validate potential entry ID with action ID (be graceful about an empty one)
|
||||
[a-zA-Z0-9_]*)
|
||||
# consider only the first ':' as a delimiter
|
||||
IFS=':' read -r entry_id action_id <<- EOL
|
||||
$line
|
||||
EOL
|
||||
if validate_entry_id "${entry_id}" && validate_action_id "${action_id}"; then
|
||||
ENTRY_IDS=${ENTRY_IDS:+${ENTRY_IDS}${N}}$line
|
||||
debug "added entry ID with action ID '$line'"
|
||||
else
|
||||
error "Discarded possibly misspelled entry '$line'"
|
||||
fi
|
||||
;;
|
||||
|
||||
esac
|
||||
# By default empty lines and comments get ignored
|
||||
done < "$config_path"
|
||||
done
|
||||
}
|
||||
# Mask IFS withing function to allow temporary changes
|
||||
alias read_config_paths='IFS= read_config_paths'
|
||||
|
||||
replace() {
|
||||
# takes $1, finds $2, replaces with $3
|
||||
# does it in large chunks
|
||||
|
||||
# var to be modified
|
||||
string=${1}
|
||||
# right part of string
|
||||
r_string=${1}
|
||||
# left part of string
|
||||
l_string=''
|
||||
# previous right part of string
|
||||
prev_r_string=''
|
||||
while true; do
|
||||
# save previous r_string
|
||||
prev_r_string=${r_string}
|
||||
# cut the right part with search string from the left
|
||||
r_string=${r_string#*"${2}"}
|
||||
# cut the left part with search string and rigth part from the right
|
||||
l_string=${string%"${2}${r_string}"}
|
||||
case "$r_string" in
|
||||
# if the right part was not unmodified, there is nothing to replace
|
||||
"$prev_r_string") break ;;
|
||||
# if the right part was is modified, update string with:
|
||||
# the left part, replace string, the right part
|
||||
*) string=${l_string}${3}${r_string} ;;
|
||||
esac
|
||||
done
|
||||
echo "$string"
|
||||
}
|
||||
|
||||
# Find and map all desktop entry files from standardised paths into aliases
|
||||
find_entry_paths() {
|
||||
debug "registering entries"
|
||||
# Append application directory paths to be searched
|
||||
IFS=':'
|
||||
for directory in $APPLICATIONS_DIRS; do
|
||||
# Append '.' to delimit start of entry ID
|
||||
set -- "$@" "$directory".
|
||||
done
|
||||
|
||||
# Find all desktop entries with valid names
|
||||
set -- "$@" -type f -name '[a-zA-Z0-9_]*.desktop' ! -path '*[^a-zA-Z0-9_./-]*'
|
||||
|
||||
# Loop through found entry paths and IDs
|
||||
IFS=$N
|
||||
while read -r entry_path && read -r entry_id; do
|
||||
# Entries are checked in ascending order of preference, so use last found if duplicate
|
||||
# shellcheck disable=SC2139
|
||||
alias "$entry_id"="entry_path='$entry_path'"
|
||||
debug "registered '$entry_path' as entry '$entry_id'"
|
||||
# Add as a fallback ID regardles if it's a duplicate
|
||||
FALLBACK_ENTRY_IDS=${entry_id}${FALLBACK_ENTRY_IDS:+${N}${FALLBACK_ENTRY_IDS}}
|
||||
debug "added fallback ID '$entry_id'"
|
||||
done <<- EOE
|
||||
$(
|
||||
# Don't complain about nonexistent directories
|
||||
find -L "$@" 2> /dev/null |
|
||||
# Print entry path and convert it into an ID and print that too
|
||||
awk '{ print; sub(".*/[.]/", ""); gsub("/", "-"); print }'
|
||||
)
|
||||
EOE
|
||||
}
|
||||
# Mask IFS withing function to allow temporary changes
|
||||
alias find_entry_paths='IFS= find_entry_paths'
|
||||
|
||||
# Check validity of a given entry key - value pair
|
||||
# Modifies following global variables:
|
||||
# EXEC : Program to execute, possibly with arguments. See spec for details.
|
||||
# EXECARG : Execution argument for the terminal emulator.
|
||||
# TERMINAL : Set if application has been categorized as a terminal emulator
|
||||
check_entry_key() {
|
||||
key="$1"
|
||||
value="$2"
|
||||
action="$3"
|
||||
read_exec="$4"
|
||||
de_checks="$5"
|
||||
|
||||
# Order of checks is important
|
||||
case $key in
|
||||
'Categories'*=*)
|
||||
debug "checking for 'TerminalEmulator' in Categories '$value'"
|
||||
IFS=';'
|
||||
for category in $value; do
|
||||
[ "$category" = "TerminalEmulator" ] && {
|
||||
TERMINAL=true
|
||||
return 0
|
||||
}
|
||||
done
|
||||
# Default in this case is to fail
|
||||
return 1
|
||||
;;
|
||||
'Actions'*=*)
|
||||
# `It is not valid to have an action group for an action identifier not mentioned in the Actions key.
|
||||
# Such an action group must be ignored by implementors.`
|
||||
# ignore if no action requested
|
||||
[ -z "$action" ] && return 0
|
||||
debug "checking for '$action' in Actions '$value'"
|
||||
IFS=';'
|
||||
for check_action in $value; do
|
||||
[ "$check_action" = "$action" ] && return 0
|
||||
done
|
||||
# Default in this case is to fail
|
||||
return 1
|
||||
;;
|
||||
'OnlyShowIn'*=*)
|
||||
case "$de_checks" in
|
||||
true) debug "checking for intersecion between '${XDG_CURRENT_DESKTOP-}' and OnlyShowIn '$value'" ;;
|
||||
false)
|
||||
debug "skipping OnlyShowIn check"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
IFS=';'
|
||||
for target in $value; do
|
||||
IFS=':'
|
||||
for desktop in ${XDG_CURRENT_DESKTOP-}; do
|
||||
[ "$desktop" = "$target" ] && return 0
|
||||
done
|
||||
done
|
||||
# Default in this case is to fail
|
||||
return 1
|
||||
;;
|
||||
'NotShowIn'*=*)
|
||||
case "$de_checks" in
|
||||
true) debug "checking for intersecion between '${XDG_CURRENT_DESKTOP-}' and NotShowIn '$value'" ;;
|
||||
false)
|
||||
debug "skipping NotShowIn check"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
IFS=';'
|
||||
for target in $value; do
|
||||
IFS=':'
|
||||
for desktop in ${XDG_CURRENT_DESKTOP-}; do
|
||||
debug "checking NotShowIn match '$desktop'='$target'"
|
||||
[ "$desktop" = "$target" ] && return 1
|
||||
done
|
||||
done
|
||||
# Default in this case is to succeed
|
||||
return 0
|
||||
;;
|
||||
'X-ExecArg'*=* | 'ExecArg'*=*)
|
||||
# Set global variable
|
||||
EXECARG=$value
|
||||
debug "read ExecArg '$EXECARG'"
|
||||
;;
|
||||
'TryExec'*=*)
|
||||
debug "checking TryExec executable '$value'"
|
||||
command -v "$value" > /dev/null || return 1
|
||||
;;
|
||||
'Hidden'*=*)
|
||||
debug "checking boolean Hidden '$value'"
|
||||
[ "$value" = 'true' ] && return 1
|
||||
;;
|
||||
'Exec'*=*)
|
||||
case "$read_exec" in
|
||||
false)
|
||||
debug "ignored Exec from wrong section"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
debug "read Exec '$value'"
|
||||
# Set global variable
|
||||
EXEC=$value
|
||||
# Get first word from read Exec value
|
||||
IFS="$OIFS"
|
||||
eval "set -- $EXEC"
|
||||
debug "checking Exec[0] executable '$1'"
|
||||
command -v "$1" > /dev/null || return 1
|
||||
;;
|
||||
esac
|
||||
# By default unrecognised keys, empty lines and comments get ignored
|
||||
}
|
||||
# Mask IFS withing function to allow temporary changes
|
||||
alias check_entry='IFS= check_entry'
|
||||
|
||||
# Read entry from given path
|
||||
read_entry_path() {
|
||||
entry_path="$1"
|
||||
entry_action="$2"
|
||||
de_checks="$3"
|
||||
read_exec=false
|
||||
# shellcheck disable=SC2016
|
||||
debug "reading desktop entry '$entry_path'${entry_action:+ action '}$entry_action${entry_action:+'}"
|
||||
# Let `read` trim leading/trailing whitespace from the line
|
||||
while IFS="$OIFS" read -r line; do
|
||||
case $line in
|
||||
# `There should be nothing preceding [the Desktop Entry group] in the desktop entry file but [comments]`
|
||||
# if entry_action is not requested, allow reading Exec right away from the main group
|
||||
'[Desktop Entry]'*) [ -z "$entry_action" ] && read_exec=true ;;
|
||||
# A `Key=Value` pair
|
||||
[a-zA-Z0-9-]*)
|
||||
# Split value from pair
|
||||
value=${line#*=}
|
||||
# Remove all but leading spaces, and trim that from the value
|
||||
value=${value#"${value%%[! ]*}"}
|
||||
# Check the key
|
||||
check_entry_key "$line" "$value" "$entry_action" "$read_exec" "$de_checks" && continue
|
||||
# Reset values that might have been set
|
||||
unset EXEC
|
||||
unset EXECARG
|
||||
unset TERMINAL
|
||||
# shellcheck disable=SC2016
|
||||
debug "entry discarded"
|
||||
return 1
|
||||
;;
|
||||
# found requested action, allow reading Exec
|
||||
"[Desktop Action ${entry_action}]"*) read_exec=true ;;
|
||||
# Start of the next group header, stop if already read exec
|
||||
'['*) [ "$read_exec" = "true" ] && break ;;
|
||||
esac
|
||||
# By default empty lines and comments get ignored
|
||||
done < "$entry_path"
|
||||
}
|
||||
|
||||
validate_entry_id() {
|
||||
# validates entry ID ($1)
|
||||
|
||||
case "$1" in
|
||||
# invalid characters or degrees of emptiness
|
||||
*[!a-zA-Z0-9_.-]* | *[!a-zA-Z0-9_.-] | [!a-zA-Z0-9_.-]* | [!a-zA-Z0-9_.-] | '' | .desktop)
|
||||
debug "string not valid as Entry ID: '$1'"
|
||||
return 1
|
||||
;;
|
||||
# all that left with .desktop
|
||||
*.desktop) return 0 ;;
|
||||
# and without
|
||||
*)
|
||||
debug "string not valid as Entry ID '$1'"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_action_id() {
|
||||
# validates action ID ($1)
|
||||
|
||||
case "$1" in
|
||||
# empty is ok
|
||||
'') return 0 ;;
|
||||
# invalid characters
|
||||
*[!a-zA-Z0-9-]* | *[!a-zA-Z0-9-] | [!a-zA-Z0-9-]* | [!a-zA-Z0-9-])
|
||||
debug "string not valid as Action ID: '$1'"
|
||||
return 1
|
||||
;;
|
||||
# all that left
|
||||
*) return 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Loop through IDs and try to find a valid entry
|
||||
find_entry() {
|
||||
# for explicitly listed entries do not apply DE *ShowIn limits
|
||||
de_checks=false
|
||||
IFS="$N"
|
||||
for entry_id in ${ENTRY_IDS}${N}//fallback_start//${N}$FALLBACK_ENTRY_IDS; do
|
||||
case "$entry_id" in
|
||||
# entry has an action appended
|
||||
*:*)
|
||||
entry_action=${entry_id#*:}
|
||||
entry_id=${entry_id%:*}
|
||||
;;
|
||||
# skip empty line
|
||||
'') continue ;;
|
||||
# fallback entries ahead, enable *ShowIn checks
|
||||
'//fallback_start//')
|
||||
de_checks=true
|
||||
continue
|
||||
;;
|
||||
# nullify action
|
||||
*) entry_action='' ;;
|
||||
esac
|
||||
|
||||
debug "matching path for entry ID '$entry_id'"
|
||||
# Check if a matching path was found for ID
|
||||
alias "$entry_id" > /dev/null 2>&1 || continue
|
||||
# Evaluates the alias, it sets $entry_path
|
||||
eval "$entry_id"
|
||||
# Unset the alias, so duplicate entries are skipped
|
||||
unalias "$entry_id"
|
||||
read_entry_path "$entry_path" "$entry_action" "$de_checks" || continue
|
||||
# Check that the entry is actually executable
|
||||
[ -z "${EXEC-}" ] && continue
|
||||
# ensure entry is a Terminal Emulator
|
||||
[ -z "${TERMINAL-}" ] && continue
|
||||
# Set defaults
|
||||
: "${EXECARG="-e"}"
|
||||
# Entry is valid, stop
|
||||
return 0
|
||||
done
|
||||
# shellcheck disable=SC2086
|
||||
IFS=':' error "No valid terminal entry was found in:" ${APPLICATIONS_DIRS}
|
||||
return 1
|
||||
}
|
||||
# Mask IFS withing function to allow temporary changes
|
||||
alias find_entry='IFS= find_entry'
|
||||
|
||||
## globals
|
||||
LOWERCASE_XDG_CURRENT_DESKTOP=$(echo "${XDG_CURRENT_DESKTOP-}" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# this will receive proper value later
|
||||
APPLICATIONS_DIRS=''
|
||||
|
||||
# path iterators
|
||||
make_paths
|
||||
|
||||
# At this point we have no way of telling if cache is enabled or not, unless XTE_CACHE_ENABLED is set,
|
||||
# so just try reading it as if default is true, otherwise do the usual thing.
|
||||
# Editing config to disable cache should invalidate the cache.
|
||||
# The true default is false though:
|
||||
CACHE_ENABLED=${XTE_CACHE_ENABLED-false}
|
||||
|
||||
# HASH can be reused
|
||||
HASH=''
|
||||
|
||||
if check_bool "${XTE_CACHE_ENABLED-true}" && read_cache; then
|
||||
CACHE_USED=true
|
||||
else
|
||||
# continue with globals
|
||||
CACHE_USED=false
|
||||
|
||||
# All desktop entry ids in descending order of preference from *xdg-terminals.list configs,
|
||||
# with duplicates removed
|
||||
ENTRY_IDS=''
|
||||
# All desktop entry ids found in data dirs in descending order of preference,
|
||||
# with duplicates (including those in $ENTRY_IDS) removed
|
||||
FALLBACK_ENTRY_IDS=''
|
||||
|
||||
# Modifies $ENTRY_IDS
|
||||
read_config_paths
|
||||
# Modifies $ENTRY_IDS and sets global aliases
|
||||
find_entry_paths
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
IFS="$N" debug "> final entry ID list:" ${ENTRY_IDS} "^ end of final entry ID list"
|
||||
# shellcheck disable=SC2086
|
||||
IFS="$N" debug "> final fallback entry ID list:" ${FALLBACK_ENTRY_IDS} "^ end of final fallback entry ID list"
|
||||
|
||||
# walk ID lists and find first applicable
|
||||
find_entry || exit 1
|
||||
fi
|
||||
|
||||
# Store original argument list, before it's modified
|
||||
debug "> original args:" "$@" "^ end of original args" "EXEC=$EXEC" "EXECARG=$EXECARG"
|
||||
|
||||
# drop -e or custom ExecArg if given as the first arg
|
||||
case "${1-}" in
|
||||
'-e' | "$EXECARG")
|
||||
debug "dropping '$1' from received args"
|
||||
shift ;;
|
||||
esac
|
||||
|
||||
# `Implementations must undo quoting [in the Exec argument(s)][...]`
|
||||
if [ "$#" -gt 0 ]; then
|
||||
eval "set -- $EXEC ${EXECARG:+'"$EXECARG"'} \"\$@\""
|
||||
else
|
||||
eval "set -- $EXEC"
|
||||
fi
|
||||
|
||||
debug "> final args:" "$@" "^ end of final args"
|
||||
|
||||
if [ "$CACHE_USED" = "false" ]; then
|
||||
# saves or removes cache, forked out of the way
|
||||
save_cache "$1" &
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
11
flakes/xdg-terminal-exec/xdg-terminal-exec.nix
Normal file
11
flakes/xdg-terminal-exec/xdg-terminal-exec.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "xdg-terminal-exec";
|
||||
builder = "${pkgs.bash}/bin/bash";
|
||||
args = [ ./builder.sh ];
|
||||
coreutils = pkgs.coreutils;
|
||||
src = ./xdg-terminal-exec;
|
||||
system = builtins.currentSystem;
|
||||
}
|
||||
3
home.nix
3
home.nix
|
|
@ -49,6 +49,9 @@
|
|||
# configure fonts correctly
|
||||
fonts.fontconfig.enable = true;
|
||||
xdg.configFile."fontconfig/conf.d/20-default.fonts.conf".source = ./config/20-default-fonts.conf;
|
||||
|
||||
# fix nemo terminal integration
|
||||
dconf.settings."org/cinnamon/desktop/applications/terminal".exec = "kitty";
|
||||
|
||||
programs.kitty = {
|
||||
enable = true;
|
||||
|
|
|
|||
Loading…
Reference in a new issue