feat: Moves local scripts directory. Handles systemd configurations.

This commit is contained in:
2025-09-28 10:04:15 -04:00
parent e5baef9bac
commit 28903f8078
50 changed files with 323 additions and 271 deletions

24
dev-env
View File

@@ -31,11 +31,13 @@ log() {
log "env: $DEV_ENV"
# Removes a destination directory and copies all files to the destination.
update_files() {
log "copying over files from: $1"
pushd $1 &>/dev/null
(
configs=$(find . -mindepth 1 -maxdepth 1 -type d)
# Copy everything except systemd folder, it needs treated differently.
configs=$(find . -mindepth 1 -maxdepth 1 -name "systemd" -prune -o -type d -print)
for c in $configs; do
directory=${2%/}/${c#./}
log " removing: rm -rf $directory"
@@ -54,6 +56,7 @@ update_files() {
popd &>/dev/null
}
# Removes a destination file and copies a single file to the destination.
copy() {
log "removing: $2"
if [[ $dry_run == "0" ]]; then
@@ -65,16 +68,27 @@ copy() {
fi
}
# Copy all files from a directory into another directory.
copy_files() {
for f in $(find $1 -mindepth 1 -maxdepth 1 -type f); do
copy $f "$2/$(basename $f)"
done
}
update_files $DEV_ENV/env/.config $XDG_CONFIG_HOME
update_files $DEV_ENV/env/.local $HOME/.local
#
# Systemd.
mkdir -p $XDG_CONFIG_HOME/systemd/user
copy_files $DEV_ENV/env/.config/systemd/user $XDG_CONFIG_HOME/systemd/user
# copy $DEV_ENV/tmux-sessionizer/tmux-sessionizer $HOME/.local/scripts/tmux-sessionizer
copy $DEV_ENV/env/.zshenv $HOME/.zshenv
copy $DEV_ENV/env/.tmux.conf $HOME/.tmux.conf
# GPG
mkdir $HOME/.gnupg
rm $HOME/.gnupg/gpg.conf >/dev/null 1>&2 && copy $DEV_ENV/env/.gnupg/gpg.conf $HOME/.gnupg/gpg.conf
rm $HOME/.gnupg/gpg-agent.conf >/dev/null 1>&2 && copy $DEV_ENV/env/.gnupg/gpg-agent.conf $HOME/.gnupg/gpg-agent.conf
rm $HOME/.gnupg/scdaemon.conf >/dev/null 1>&2 && copy $DEV_ENV/env/.gnupg/scdaemon.conf $HOME/.gnupg/scdaemon.conf
copy_files $DEV_ENV/env/.gnupg $HOME/.gnupg
systemctl --user daemon-reload
hyprctl reload

View File

@@ -4,5 +4,5 @@ After=graphical-session.target
[Service]
Type=oneshot
ExecStart=%h/.local/bin/battery-monitor
ExecStart=%h/.local/scripts/battery-monitor
Environment=DISPLAY=:0

View File

@@ -5,7 +5,7 @@ Before=exit.target
[Service]
Type=oneshot
ExecStart=%h/.local/bin/clear-clipboard-history
ExecStart=%h/.local/scripts/clear-clipboard-history
[Install]
WantedBy=exit.target

32
env/.local/scripts/battery-monitor vendored Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/zsh
# Used with the systemd battery monitor service and timer to alert
# when the battery has dropped below the threshold and is not currently
# charging.
THRESHOLD=20 # Notify when below 20%
NOTIFICATION_FLAG="/run/user/${UID}/user_battery_notified"
function get-battery-percentage() {
local battery=$(upower --battery | grep percentage)
echo "${battery//[^0-9]/}"
}
function send-battery-alert() {
notify-send -u critical \
"Recharge battery!" "Batttery is down to ${1}" \
-i battery-caution \
-t 30000
}
battery_percentage=$(get-battery-percentage)
battery_state=$(upower --battery | grep -E state | awk '{print $2}')
if [[ "$battery_state" == "discharging" && "$battery_percentage" -le "$THRESHOLD" ]]; then
if [ ! -f "$NOTIFICATION_FLAG" ]; then
send-battery-alert "$battery_percentage"
touch "$NOTIFICATION_FLAG"
fi
else
rm -f "$NOTIFICATION_FLAG"
fi

8
env/.local/scripts/clear-clipboard-history vendored Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
#wl-copy --clear >/dev/null 2>&1 && \
if [ -n "$WAYLAND_DISPLAY" ]; then
wl-copy --clear
fi
rm ~/.local/share/clipse/clipboard_history.json >/dev/null 2>&1

5
env/.local/scripts/close-all-windows vendored Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
hyprctl clients -j | \
jq '.[] | .address' | \
xargs -I{} hyprctl dispatch closewindow address:{}

151
env/.local/scripts/install-webapp vendored Executable file
View File

@@ -0,0 +1,151 @@
#!/bin/zsh
# Adapted from https://github.com/basecamp/omarchy/tree/master?tab=readme-ov-file
function usage() {
cat <<EOF
Generates a '.desktop' file for a web application, so that it
can act as a stand alone application and launched from an application
launcher.
USAGE: install-webapp [-n <name>] [-u <url>] [-i <icon>] [-e <exec-cmd>] [-m <mime-types>] [-h] [args...]
OPTIONS:
-n | --name: The name of the application.
-u | --url: The url used to launch the application.
-i | --icon: The icon for the application.
-e | --exec: Custom execution command (optional).
-m | --mime-types: MIME-types for the application (optional).
-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.
$ install-webapp
Calling the app with named arguments:
$ install-webapp \\
--name "My Awesome App" \\
--url "https://awesome.com" \\
--icon "https://awesome.com/assets/icon.png"
It is also possible to use only positional arguments with out their key. They can be passed in the order as
they're listed.
$ install-webapp "My Awesome App" \\
"https://awesome.com" \\
"https://awesome.com/assets/icon.png"
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.
EOF
}
declare -a app_name
declare -a app_url
declare -a icon_ref
declare -a custom_exec # Optional custom exec command
declare -a mime_types # Optional mime types
declare -a help_flag
declare INTERACTIVE_MODE=false
zparseopts -D -F -K -- \
{n,-name}:=app_name \
{u,-url}:=app_url \
{i,-icon}:=icon_ref \
{e,-exec}:=custom_exec \
{m,-mime-types}:=mime_types \
{h,-help}=help_flag
[ ${#help_flag[@]} -gt 0 ] && usage && exit 0
# If passed in as positional arguments, without flags.
[ -n "$1" ] && app_name+=("$1")
[ -n "$2" ] && app_url+=("$2")
[ -n "$3" ] && icon_ref+=("$3")
[ -n "$4" ] && custom_exec+=("$4")
[ -n "$5" ] && mime_types+=("$5")
# Check if proper arguments were passed in. Start interactive mode if not.
if [[ -z "$app_name[-1]" || -z "$app_url[-1]" || -z "$icon_ref[-1]" ]]; then
echo -e "\e[32mLet's create a new web app you can start with the app launcher.\n\e[0m"
app_name+=($(gum input --prompt "Name> " --placeholder "My favorite web app"))
app_url+=($(gum input --prompt "URL> " --placeholder "https://example.com"))
icon_ref+=($(gum input --prompt "Icon URL> " --placeholder "See https://dashboardicons.com (must use PNG!)"))
INTERACTIVE_MODE=true
else
INTERACTIVE_MODE=false
fi
# Ensure valid execution
if [[ -z "$app_name[-1]" || -z "$app_url[-1]" || -z "$icon_ref[-1]" ]]; then
echo "You must set app name, app URL, and icon URL!"
exit 1
fi
APP_NAME=$app_name[-1]
APP_URL=$app_url[-1]
ICON_REF=$icon_ref[-1]
CUSTOM_EXEC=$custom_exec[-1]
MIME_TYPES=$mime_types[-1]
# Refer to local icon or fetch remotely from URL
ICON_DIR="$HOME/.local/share/applications/icons"
if [[ $ICON_REF == https://* ]]; then
ICON_PATH="$ICON_DIR/$APP_NAME.png"
if curl -sL -o "$ICON_PATH" "$ICON_REF"; then
ICON_PATH="$ICON_DIR/$APP_NAME.png"
else
echo "Error: Failed to download icon."
exit 1
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
# Use custom exec if provided, otherwise default behavior
if [[ -n $CUSTOM_EXEC ]]; then
EXEC_COMMAND="$CUSTOM_EXEC"
else
EXEC_COMMAND="$HOME/.local/bin/launch-webapp $APP_URL"
fi
# Create application .desktop file
DESKTOP_FILE="$HOME/.local/share/applications/$APP_NAME.desktop"
cat >"$DESKTOP_FILE" <<EOF
[Desktop Entry]
Version=1.0
Name=$APP_NAME
Comment=$APP_NAME
Exec=$EXEC_COMMAND
Terminal=false
Type=Application
Icon=$ICON_PATH
StartupNotify=true
EOF
# Add mime types if provided
if [[ -n $MIME_TYPES ]]; then
echo "MimeType=$MIME_TYPES" >>"$DESKTOP_FILE"
fi
chmod +x "$DESKTOP_FILE"
if [[ $INTERACTIVE_MODE == true ]]; then
echo -e "You can now find $APP_NAME using the app launcher (SUPER + SPACE)\n"
fi

7
env/.local/scripts/launch-webapp vendored Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Adapted from https://github.com/basecamp/omarchy/tree/master?tab=readme-ov-file
#
browser="chromium.desktop"
exec setsid uwsm app -- $(sed -n 's/^Exec=\([^ ]*\).*/\1/p' {~/.local,~/.nix-profile,/usr}/share/applications/$browser 2>/dev/null | head -1) --app="$1" "${@:2}"

View File

@@ -0,0 +1,15 @@
#!/bin/bash
# Moves all workspaces to the passed in monitor id, which can be useful when
# connecting or disconnecting from a monitor.
MONITOR=$1
if [ ! $# = 1 ]; then
echo "Usage: mv-all-workspaces-to-monitor <monitor-id>"
exit 1
fi
hyprctl workspaces -j |
jq '.[] | select(.monitorID != "$MONITOR") | .id' |
xargs -I{} hyprctl dispatch moveworkspacetomonitor {} "$MONITOR" >/dev/null 2>&1

29
env/.local/scripts/toggle-desktop vendored Executable file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Workspace to hide everything in
HIDE_WS="special:hidden"
# File to store original workspace ID
STATE_FILE="/tmp/hypr_hide_state"
# Get current workspace ID
CUR_WS=$(hyprctl -j activeworkspace | jq -r '.id')
# Check if we're currently hidden
if [[ -f "$STATE_FILE" ]]; then
# Restore windows
ORIG_WS=$(cat "$STATE_FILE")
for win in $(hyprctl -j clients | jq -r ".[] | select(.workspace.name | contains(\"$HIDE_WS\")) | .address"); do
hyprctl dispatch movetoworkspace "$ORIG_WS,address:$win"
hyprctl dispatch workspace "$ORIG_WS"
done
rm "$STATE_FILE"
else
# Hide all windows (move to special hidden workspace)
for win in $(hyprctl -j clients | jq -r ".[] | select(.workspace.id == $CUR_WS) | .address"); do
hyprctl dispatch movetoworkspace "$HIDE_WS,address:$win"
hyprctl dispatch togglespecialworkspace "$HIDE_WS"
done
rm "$STATE_FILE"
echo "$CUR_WS" >"$STATE_FILE"
fi

12
env/.local/scripts/toggle-internal-monitor vendored Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/zsh
#
# Toggles the state of the internal laptop monitor, which is useful
# when I'm connected to an external monitor / docks.
monitor="eDP-1"
if hyprctl monitors | grep -q "$monitor"; then
hyprctl keyword monitor "$monitor,disable" 1>/dev/null
else
hyprctl keyword monitor "$monitor,enable" 1>/dev/null
fi

11
env/.local/scripts/toggle-waybar vendored Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
WAYBAR_PID=$(pgrep -x waybar)
if [ -n "$WAYBAR_PID" ]; then
# kill waybar process if it's running.
kill "$WAYBAR_PID"
else
# start waybar in the background.
waybar &
fi

4
env/.local/scripts/waybar-restart vendored Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/zsh
pkill -x waybar
setsid uwsm app -- waybar >/dev/null 2>&1 &

27
env/.local/scripts/window-toggle-floating vendored Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
#
# Float's a window, setting it's height and width and centering.
# The percentage of the screen size for the floating window.
WIDTH_PERCENT=80
HEIGHT_PERCENT=40
floating=$(hyprctl activewindow -j | jq '.floating')
if [ "$floating" = "true" ]; then
hyprctl dispatch togglefloating
else
monitor=$(hyprctl monitors -j | jq '.[] | select(.focused == true)')
mw=$(echo "$monitor" | jq '.width')
mh=$(echo "$monitor" | jq '.height')
ms=$(echo "$monitor" | jq '.scale')
echo "scale: $ms"
neww=$(echo "scale=6; (($mw / $ms) * $WIDTH_PERCENT / 100)" | bc)
newh=$(echo "scale=6; (($mh / $ms) * $HEIGHT_PERCENT / 100)" | bc)
hyprctl dispatch togglefloating &&
hyprctl dispatch resizeactive exact $neww $newh &&
hyprctl dispatch centerwindow
fi

2
env/.zshenv vendored
View File

@@ -47,7 +47,7 @@ export NAP_CONFIG="$HOME/.config/nap/config.yaml"
export PDFS="$HOME/Library/Mobile Documents/com~apple~Preview/Documents"
export PROPOSALS="$HOME/Library/Mobile Documents/com~apple~CloudDocs/Work/Proposals"
export SCREENSHOTS="$BUCKET/Pictures/Screenshots"
export SCRIPTS="$XDG_DATA_HOME/scripts"
export SCRIPTS="$$HOME/.local/scripts"
export SITES="$GHREPOS/sites"
export SKELETONDIR="$DOTFILES/skeleton"
export WORK="$HOME/Library/Mobile Documents/com~apple~CloudDocs/Work"

View File

@@ -1,20 +0,0 @@
#!/bin/bash
INTERNAL="eDP-1" # check with `hyprctl monitors`
# Check lid event handler with:
#
# grep -A5 -i lid /proc/bus/input/devices
#
# The event is contained in the H: Handlers=kbd event<N>
#
DEVICE="/dev/input/event0" # replace with your lid event device
evtest --grab "$DEVICE" |
while read -r line; do
if echo "$line" | grep -q "SW_LID.*value 1"; then
hyprctl keyword monitor "$INTERNAL,disable"
elif echo "$line" | grep -q "SW_LID.*value 0"; then
hyprctl keyword monitor "$INTERNAL,preferred,auto,auto"
fi
done

View File

@@ -1,12 +0,0 @@
#!/bin/sh
set -e
font_dir="$(brew --prefix)/share/figlet/fonts"
for font in "${font_dir}"/*.flf; do
clear
echo "FONT: $font"
figlet -f "${font}" hello
read -r line
done

View File

@@ -1,8 +0,0 @@
#!/bin/sh
set -e
message="${1:-m-housh}"
font="${2:-puffy}"
echo "${message}" | figlet -c -f "${font}"

View File

@@ -1,9 +0,0 @@
#!/bin/sh
if [ "$(uname -n)" = "Michaels-Mac-mini.local" ]; then
echo "Removing derived data folders"
rm -r /Volumes/Bucket/Library/Developer/Xcode/DerivedData
else
echo "Removing derived data folders"
rm -r ~/Library/Developer/Xcode/DerivedData/*
fi

View File

@@ -1,8 +0,0 @@
#!/bin/zsh
# adapted from...
# https://github.com/rwxrob/dot/blob/main/scripts/cmt
while IFS= read -r line; do
echo "${1:-#} $line"
done

View File

@@ -1,5 +0,0 @@
#!/bin/bash
url="https://lite.duckduckgo.com/lite?kd=1&kp=1&q=$(urlencode "$*")"
exec lynx -vikeys "$url"

View File

@@ -1,16 +0,0 @@
#!/bin/bash
# Create a new figlet (ascii art) from the input.
figl() {
font=${FIGL_FONT:-puffy}
declare -a buf
while IFS= read -r line; do
buf+=("$line")
done
for line in "${buf[@]}"; do
figlet -f "$font" -c "${line}" | head -6
done
}
figl "$*"

View File

@@ -1,58 +0,0 @@
#!/bin/sh
# Creates symlinks from external application directory
# to another directory so applications are seen in
# spotlight searches and launchpad.
set -e
app_dir=""
destination_dir=""
# Parses the input arguments. If 2 arguments are passed in, then
# the first is where we search for applications (source) and the second
# argument is the destination directory for the symlinks to be placed in
#
# If one argument is passed in, then it is used as the destination directory
# and we use the default source directory.
_parse_args() {
arg_count="$#"
app_dir="/Volumes/M1 Mac-Mini External Drive/Applications"
destination_dir="${HOME}/Application"
if test "$arg_count" -eq 1; then
destination_dir="$1"
elif test "$arg_count" -eq 2; then
app_dir="$1"
destination_dir="$2"
fi
}
# Checks if the `app_dir` exists.
_is_mounted() {
if ! test -d "$app_dir"; then
echo "Application directory does not exist or is not mounted" >&2
return 1
fi
}
# ---------------- main -------------------
main() {
_parse_args "$@"
test -d "${destination_dir}" || echo "Destination does not exist" >&2
if test _is_mounted; then
for app in "${app_dir}"/*.app; do
destination="${destination_dir}/$(basename "${app}")"
if test -e "${destination}"; then
echo "Destination already exists: ${destination}. Skipping!" >&2
continue
fi
# remove echo to do real work.
echo ln -sv "${app}" "${destination}" >&2
done
fi
}
main "$@"

View File

@@ -1,94 +0,0 @@
#!/usr/bin/env zsh
# Posts to facebook group and personal page.
#
# Typical usage would be to generate a link to the latest
# blog post and send to facebook:
#
# `$ mhlink --last | xargs -I {} post-to-facebook -m <optional-message> {}`
#
#
#################### Options ####################
declare -a message
zparseopts -D -F -K -- \
{a,-all}=locationOpt \
{m,-message}+:=message \
{o,-offline}=offline \
{p,-personal}=locationOpt \
{h,-help}=help
baseUrl="https://graph.facebook.com/v18.0"
link=$1
message="${message[-1]}"
token=$(cat < "$HOME/.config/facebook-bot/access-token.txt")
#################### Usage ####################
function usage() {
cat <<EOF
post-to-facebook: Create posts on facebook using. This accepts
a link as an argument and a message option. Either the message
or the link (or both) needs to be supplied.
Typical usage:
post-to-facebook --message "Some message" "https://mhouhs.com/<post>"
Usage: post-to-facebook [-a] [-m <message>] [-o] [-p] <link>
-a | --all: Send the post to the group and personal pages.
-m | --message: The optional message.
-o | --offline: Do not send the request(s), but print them.
-p | --personal: Send to personal page only.
-h | --help: Show the usage.
The -a or -p options are optional, if neither is supplied then it will
only be posted to the group.
EOF
}
#################### Helpers ####################
function post() {
local url=$1
if [ -n "$offline" ]; then
echo "Offline mode, request not being sent."
http --offline --ignore-stdin POST "$url" access_token=="$token" \
link="$link" \
message="$message"
else
http --ignore-stdin POST "$url" access_token=="$token" \
link="$link" \
message="$message"
fi
}
function post_to_group() {
group=$(cat < "$HOME/.config/facebook-bot/group.txt")
post "$baseUrl/$group/feed"
}
function post_to_personal() {
post "$baseUrl/me/feed"
}
#################### Main ####################
[ -n "$help" ] && usage && exit 0
[ -z "$link" ] && [ -z "$message" ] \
&& echo "Link or message is required." \
&& exit 1
[ "$locationOpt" = "-p" ] || [ "$locationOpt" = "--personal" ] \
&& post_to_personal \
&& exit 0
[ "$locationOpt" = "-a" ] || [ "$locationOpt" = "--all" ] \
&& post_to_personal
post_to_group

View File

@@ -1,8 +0,0 @@
#!/bin/bash
# adapted from...
# https://github.com/rwxrob/dot/blob/main/scripts/ucmt
while IFS= read -r line; do
echo "${line#* }"
done

View File

@@ -1 +0,0 @@
/home/michael/.config/systemd/user/espanso.service

View File

@@ -1,11 +0,0 @@
[Unit]
Description=espanso
[Service]
ExecStart=/usr/bin/espanso launcher
Restart=on-failure
RestartSec=3
[Install]
WantedBy=default.target

View File

@@ -1 +0,0 @@
/usr/lib/systemd/user/hypridle.service

View File

@@ -1 +0,0 @@
/usr/lib/systemd/user/hyprpaper.service

View File

@@ -1,11 +0,0 @@
[Unit]
Description=Hyprland lid handler using evdev
After=graphical.target
[Service]
ExecStart=%h/.local/bin/lid.sh
Restart=always
[Install]
WantedBy=default.target