mirror of
https://github.com/m-housh/dotfiles.git
synced 2026-02-13 22:02:34 +00:00
305 lines
8.1 KiB
Bash
Executable File
305 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Adapted from https://github.com/basecamp/omarchy/tree/master?tab=readme-ov-file
|
|
|
|
THIS_FILE=${BASH_SOURCE[0]}
|
|
THIS=${THIS:-$(basename "$THIS_FILE")}
|
|
LOG_FILE=${LOG_FILE:-"$THIS.log"}
|
|
LOG_LABEL=$(basename "$THIS_FILE")
|
|
|
|
function usage() {
|
|
cat <<EOF
|
|
Generates a '.desktop' file for a web application, so that it can act as a stand alone application and
|
|
be launched from an application launcher.
|
|
|
|
USAGE: $THIS [OPTIONS]
|
|
|
|
OPTIONS:
|
|
-n | --name <name>: The name of the application.
|
|
|
|
-u | --url <url>: The url used to launch the application.
|
|
|
|
-i | --icon <icon>: The icon for the application.
|
|
|
|
-e | --exec <cmd>: Custom execution command (optional).
|
|
|
|
-m | --mime-types <types>: MIME-types for the application (optional).
|
|
|
|
-f | --file <file>: Install from a spec in a json file.
|
|
|
|
-l | --launch: Launches in a new terminal window in interactive mode.
|
|
|
|
--no-interactive: Don't proceed to interactive mode. If required properties aren't set,
|
|
then error. This is useful if using '--file' and there are parsing errors
|
|
or missing properties.
|
|
|
|
--dry-run: Run in dry-run mode, which doesn't generate files or download icons.
|
|
|
|
-h | --help: Show usage information.
|
|
|
|
EXAMPLES:
|
|
|
|
If no options or arguments are supplied, then it will start an interactive session that prompts for the
|
|
values.
|
|
|
|
$ $THIS
|
|
|
|
Calling the app with named arguments:
|
|
|
|
$ $THIS \\
|
|
--name "My Awesome App" \\
|
|
--url "https://awesome.com" \\
|
|
--icon "https://awesome.com/assets/icon.png"
|
|
|
|
Using a json file as input:
|
|
|
|
$ $THIS --file myapp.json
|
|
|
|
NOTES:
|
|
|
|
The icon option can either be a url where we will download a png from or a local file. Local files
|
|
can either be the full path to the file or a file name of an icon located in '~/.local/share/applications/icons/'.
|
|
|
|
Interactive sessions do not give the option to use a custom execution command or supply the
|
|
MIME types, which are less frequently used options.
|
|
|
|
If using a json spec file, all keys are the same as their option name, except for mime-types use 'mime_types' as the
|
|
key in the json object. Although the 'exec' and 'mime_types' are not required in the spec file. A common json spec
|
|
file example would look like:
|
|
|
|
{
|
|
"name": "My Awesome App",
|
|
"url": "https://awesome.com",
|
|
"icon: "https://awesome.com/assets/icon.png"
|
|
}
|
|
|
|
EOF
|
|
}
|
|
|
|
window_class="com.ghostty.install-webapp"
|
|
window_padding_x="2"
|
|
|
|
app_name=""
|
|
app_url=""
|
|
exec_cmd=""
|
|
dry_run="0"
|
|
file_mode_flag="0"
|
|
icon_ref=""
|
|
json_file=""
|
|
mime_types=""
|
|
launch_flag="0"
|
|
interactive_flag="0" # This is an internal flag, to not log some things when launch is used.
|
|
interactive_mode=false
|
|
no_interactive_flag="0"
|
|
SCRIPTS="${SCRIPTS:-$HOME/.local/scripts}"
|
|
XDG_DATA_HOME=${XDG_DATA_HOME}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
if [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then
|
|
usage && exit 0
|
|
elif [[ $1 == "-n" ]] || [[ $1 == "--name" ]]; then
|
|
shift
|
|
app_name=$1
|
|
elif [[ $1 == "-u" ]] || [[ $1 == "--url" ]]; then
|
|
shift
|
|
app_url=$1
|
|
elif [[ $1 == "-i" ]] || [[ $1 == "--icon" ]]; then
|
|
shift
|
|
icon_ref=$1
|
|
elif [[ $1 == "-e" ]] || [[ $1 == "--exec" ]]; then
|
|
shift
|
|
exec_cmd=$1
|
|
elif [[ $1 == "-m" ]] || [[ $1 == "--mime-types" ]]; then
|
|
shift
|
|
mime_types=$1
|
|
elif [[ $1 == "-f" ]] || [[ $1 == "--file" ]]; then
|
|
file_mode_flag="1"
|
|
shift
|
|
json_file=$1
|
|
elif [[ $1 == "-l" ]] || [[ $1 == "--launch" ]]; then
|
|
launch_flag="1"
|
|
elif [[ $1 == "--interactive" ]]; then
|
|
interactive_flag="1"
|
|
elif [[ $1 == "--no-interactive" ]]; then
|
|
no_interactive_flag="1"
|
|
elif [[ $1 =~ ^--dry ]]; then
|
|
dry_run="1"
|
|
fi
|
|
shift
|
|
done
|
|
|
|
log() {
|
|
logging log --source "$THIS_FILE" "$@"
|
|
}
|
|
|
|
launch() {
|
|
ghostty --class=$window_class --window-padding-x=$window_padding_x \
|
|
--keybind="ctrl+c=quit" \
|
|
-e "${BASH_SOURCE[0]}" --interactive
|
|
}
|
|
|
|
check_properties() {
|
|
if [[ -z $app_name ]] || [[ -z $app_url ]] || [[ -z $icon_ref ]]; then
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
load_from_file() {
|
|
if [[ ! -f $1 ]]; then
|
|
log --error "File '$1' is not found or readable." && exit 1
|
|
fi
|
|
file=$(cat $1)
|
|
app_name=$(echo $file | jq -r '.name // ""')
|
|
app_url=$(echo $file | jq -r '.url // ""')
|
|
icon_ref=$(echo $file | jq -r '.icon // ""')
|
|
exec_cmd=$(echo $file | jq -r '.exec // ""')
|
|
mime_types=$(echo $file | jq -r '.mime_types // ""')
|
|
}
|
|
|
|
print_properties() {
|
|
log "\e[33mAPP NAME:\e[0m $app_name"
|
|
log "\e[33mURL:\e[0m $app_url"
|
|
log "\e[33mICON:\e[0m $icon_ref"
|
|
log "\e[33mEXEC:\e[0m $exec_cmd"
|
|
log "\e[33mMIME:\e[0m $mime_types"
|
|
}
|
|
|
|
prompt_for_properties() {
|
|
log "\e[32mLet's create a new web app you can start with the app launcher.\n\e[0m"
|
|
|
|
if [[ -z $app_name ]]; then
|
|
app_name=$(gum input --prompt "Name> " --placeholder "My favorite web app")
|
|
fi
|
|
|
|
if [[ -z $app_url ]]; then
|
|
app_url=$(gum input --prompt "URL> " --placeholder "https://example.com")
|
|
fi
|
|
|
|
if [[ -z $icon_ref ]]; then
|
|
icon_ref=$(gum input --prompt "Icon URL> " --placeholder "See https://dashboardicons.com (must use PNG!)")
|
|
fi
|
|
}
|
|
|
|
set_icon_ref() {
|
|
# Refer to local icon or fetch remotely from URL
|
|
local icon_dir="$XDG_DATA_HOME/applications/icons"
|
|
local icon_path=""
|
|
|
|
# Ensure the icon directory exists (useful if it's the first run.)
|
|
[ ! -d $icon_dir ] && mkdir -p $icon_dir
|
|
|
|
if [[ $icon_ref == https://* ]]; then
|
|
icon_path="$icon_dir/$app_name.png"
|
|
log "Downloading icon: $icon_ref"
|
|
if [[ $dry_run == "0" ]]; then
|
|
if curl -sL -o "$icon_path" "$icon_ref"; then
|
|
icon_path="$icon_dir/$app_name.png"
|
|
else
|
|
log --error "Failed to download icon." && exit 1
|
|
fi
|
|
fi
|
|
else
|
|
# Check if the icon path is a file.
|
|
if [ -f $icon_ref ]; then
|
|
icon_path=$icon_ref
|
|
else
|
|
icon_path="$icon_dir/$icon_ref"
|
|
fi
|
|
fi
|
|
|
|
icon_ref=$icon_path
|
|
}
|
|
|
|
generate_file() {
|
|
|
|
cat >"$1" <<EOF
|
|
[Desktop Entry]
|
|
Version=1.0
|
|
Name=$app_name
|
|
Comment=$app_name
|
|
Exec=$exec_cmd
|
|
Terminal=false
|
|
Type=Application
|
|
Icon=$icon_ref
|
|
StartupNotify=true
|
|
EOF
|
|
|
|
# Add mime types if provided
|
|
if [[ -n $mime_types ]]; then
|
|
echo "MimeType=$mime_types" >>"$1"
|
|
fi
|
|
|
|
chmod +x "$1"
|
|
}
|
|
|
|
################################################################################
|
|
# MAIN
|
|
################################################################################
|
|
|
|
# Setup logging file and label
|
|
source "$SCRIPTS/hypr/logging"
|
|
setup-logging "$LOG_FILE" "$LOG_LABEL"
|
|
export LOG_ENABLE_DRY_RUN="$dry_run"
|
|
|
|
if [[ -z "$XDG_DATA_HOME" ]]; then
|
|
log "XDG_DATA_HOME not set"
|
|
log "using ~/.local/share"
|
|
XDG_DATA_HOME=$HOME/.local/share
|
|
fi
|
|
|
|
if [[ $launch_flag == "1" ]]; then
|
|
launch && exit 0
|
|
fi
|
|
|
|
if [[ $file_mode_flag == "1" ]]; then
|
|
load_from_file $json_file
|
|
fi
|
|
|
|
# Check that all properties are set, prompt for missing values if not.
|
|
check_properties
|
|
if [[ "$?" == "1" ]]; then
|
|
|
|
# Check if the '--no-interactive' flag was passed and exit with error.
|
|
[[ $no_interactive_flag == "1" ]] &&
|
|
log --error "Required properties not set and '--no-interactive' flag was passed." &&
|
|
exit 1
|
|
|
|
# Only log this if not in interactive mode.
|
|
[[ $interactive_mode == "0" ]] &&
|
|
log "All required properties not set, prompting for missing properties."
|
|
|
|
prompt_for_properties
|
|
|
|
# Check properties again after prompting in interactive mode.
|
|
check_properties
|
|
if [[ "$?" == "1" ]]; then
|
|
# Exit if they were not set during interactive mode.
|
|
log --error "You must set app name, app URL, and icon URL!" && exit 1
|
|
fi
|
|
|
|
# Set flag that we are in interactive mode.
|
|
interactive_mode=true
|
|
fi
|
|
|
|
desktop_file="$XDG_DATA_HOME/applications/$app_name.desktop"
|
|
|
|
# Parse the icon ref and download icon, if applicable.
|
|
set_icon_ref
|
|
|
|
# Check that an exec command is set, or default to the 'launch-webapp' script.
|
|
if [[ -z $exec_cmd ]]; then
|
|
exec_cmd="$SCRIPTS/hypr/webapp launch $app_url"
|
|
fi
|
|
|
|
log "\e[032mCreating web app:\e[0m $desktop_file"
|
|
print_properties
|
|
|
|
if [[ $dry_run == "0" ]]; then
|
|
generate_file "$desktop_file"
|
|
fi
|
|
|
|
if [[ $interactive_mode == true ]] && [[ $dry_run == "0" ]]; then
|
|
log "You can now find $app_name using the app launcher (SUPER + SPACE)\n"
|
|
fi
|