feat(system): comprehensive branding, styling, and system feature update
- Relocate themes to assets/themes/ and update all references. - Implement custom SDDM theme and Plymouth theme enhancements. - Add themed templates for Alacritty, Hyprland, Waybar, and other apps. - Introduce Makima key remapper module and configuration. - Add Voxtype and Walker configurations. - Implement systemd power management and timeout optimizations. - Add Nautilus-python extensions for LocalSend. - Update branding assets and ASCII art integration.
This commit is contained in:
17
bin/utils/nomarchy-build-iso
Executable file
17
bin/utils/nomarchy-build-iso
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Build the Nnomarchy Installer ISO declaratively using the flake.
|
||||
|
||||
echo "Building Nnomarchy Installer ISO..."
|
||||
|
||||
# The output will be a symlink named 'result' in the current directory
|
||||
nix build .#nixosConfigurations.installerIso.config.system.build.isoImage
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
ISO_PATH=$(readlink -f result/iso/*.iso)
|
||||
echo "Success! ISO built at: $ISO_PATH"
|
||||
echo "You can now burn this to a USB drive using 'dd' or 'etcher'."
|
||||
else
|
||||
echo "Error: ISO build failed."
|
||||
exit 1
|
||||
fi
|
||||
66
bin/utils/nomarchy-cmd-audio-switch
Executable file
66
bin/utils/nomarchy-cmd-audio-switch
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Switch between audio outputs while preserving the mute status. By default mapped to Super + Mute.
|
||||
|
||||
focused_monitor="$(hyprctl monitors -j | jq -r '.[] | select(.focused == true).name')"
|
||||
|
||||
sinks=$(pactl -f json list sinks | jq '[.[] | select((.ports | length == 0) or ([.ports[]? | .availability != "not available"] | any))]')
|
||||
sinks_count=$(echo "$sinks" | jq '. | length')
|
||||
|
||||
if (( sinks_count == 0 )); then
|
||||
swayosd-client \
|
||||
--monitor "$focused_monitor" \
|
||||
--custom-message "No audio devices found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
current_sink_name=$(pactl get-default-sink)
|
||||
current_sink_index=$(echo "$sinks" | jq -r --arg name "$current_sink_name" 'map(.name) | index($name)')
|
||||
|
||||
if [[ $current_sink_index != "null" ]]; then
|
||||
next_sink_index=$(((current_sink_index + 1) % sinks_count))
|
||||
else
|
||||
next_sink_index=0
|
||||
fi
|
||||
|
||||
next_sink=$(echo "$sinks" | jq -r ".[$next_sink_index]")
|
||||
next_sink_name=$(echo "$next_sink" | jq -r '.name')
|
||||
|
||||
next_sink_description=$(echo "$next_sink" | jq -r '.description')
|
||||
if [[ $next_sink_description == "(null)" ]] || [[ $next_sink_description == "null" ]] || [[ -z $next_sink_description ]]; then
|
||||
# For Bluetooth devices, the friendly name is on the Device entry (device.id), not the Sink entry (object.id)
|
||||
device_id=$(echo "$next_sink" | jq -r '.properties."device.id"')
|
||||
if [[ $device_id != "null" ]] && [[ -n $device_id ]]; then
|
||||
next_sink_description=$(wpctl status | grep -E "^\s*│?\s+${device_id}\." | sed -E 's/^.*[0-9]+\.\s+//' | sed -E 's/\s+\[.*$//')
|
||||
fi
|
||||
# Fall back to object.id lookup if device.id didn't yield a result
|
||||
if [[ -z $next_sink_description ]]; then
|
||||
sink_id=$(echo "$next_sink" | jq -r '.properties."object.id"')
|
||||
next_sink_description=$(wpctl status | grep -E "\s+\*?\s+${sink_id}\." | sed -E 's/^.*[0-9]+\.\s+//' | sed -E 's/\s+\[.*$//')
|
||||
fi
|
||||
fi
|
||||
|
||||
next_sink_volume=$(echo "$next_sink" | jq -r \
|
||||
'.volume | to_entries[0].value.value_percent | sub("%"; "")')
|
||||
next_sink_is_muted=$(echo "$next_sink" | jq -r '.mute')
|
||||
|
||||
if [[ $next_sink_is_muted = "true" ]] || (( next_sink_volume == 0 )); then
|
||||
icon_state="muted"
|
||||
elif (( next_sink_volume <= 33 )); then
|
||||
icon_state="low"
|
||||
elif (( next_sink_volume <= 66 )); then
|
||||
icon_state="medium"
|
||||
else
|
||||
icon_state="high"
|
||||
fi
|
||||
|
||||
next_sink_volume_icon="sink-volume-${icon_state}-symbolic"
|
||||
|
||||
if [[ $next_sink_name != $current_sink_name ]]; then
|
||||
pactl set-default-sink "$next_sink_name"
|
||||
fi
|
||||
|
||||
swayosd-client \
|
||||
--monitor "$focused_monitor" \
|
||||
--custom-message "$next_sink_description" \
|
||||
--custom-icon "$next_sink_volume_icon"
|
||||
9
bin/utils/nomarchy-cmd-present
Executable file
9
bin/utils/nomarchy-cmd-present
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Returns true if all the commands passed in as arguments exit on the system.
|
||||
|
||||
for cmd in "$@"; do
|
||||
command -v "$cmd" &>/dev/null || exit 1
|
||||
done
|
||||
|
||||
exit 0
|
||||
184
bin/utils/nomarchy-cmd-screenrecord
Executable file
184
bin/utils/nomarchy-cmd-screenrecord
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Start and stop a screenrecording, which will be saved to ~/Videos by default.
|
||||
# Alternative location can be set via NOMARCHY_SCREENRECORD_DIR or XDG_VIDEOS_DIR ENVs.
|
||||
# Resolution is capped to 4K for monitors above 4K, native otherwise.
|
||||
# Override via --resolution= (e.g. --resolution=1920x1080, --resolution=0x0 for native).
|
||||
|
||||
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
|
||||
OUTPUT_DIR="${NOMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}"
|
||||
|
||||
if [[ ! -d $OUTPUT_DIR ]]; then
|
||||
notify-send "Screen recording directory does not exist: $OUTPUT_DIR" -u critical -t 3000
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DESKTOP_AUDIO="false"
|
||||
MICROPHONE_AUDIO="false"
|
||||
WEBCAM="false"
|
||||
WEBCAM_DEVICE=""
|
||||
RESOLUTION=""
|
||||
STOP_RECORDING="false"
|
||||
RECORDING_FILE="/tmp/nnomarchy-screenrecord-filename"
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--with-desktop-audio) DESKTOP_AUDIO="true" ;;
|
||||
--with-microphone-audio) MICROPHONE_AUDIO="true" ;;
|
||||
--with-webcam) WEBCAM="true" ;;
|
||||
--webcam-device=*) WEBCAM_DEVICE="${arg#*=}" ;;
|
||||
--resolution=*) RESOLUTION="${arg#*=}" ;;
|
||||
--stop-recording) STOP_RECORDING="true" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
start_webcam_overlay() {
|
||||
cleanup_webcam
|
||||
|
||||
# Auto-detect first available webcam if none specified
|
||||
if [[ -z $WEBCAM_DEVICE ]]; then
|
||||
WEBCAM_DEVICE=$(v4l2-ctl --list-devices 2>/dev/null | grep -m1 "^[[:space:]]*/dev/video" | tr -d '\t')
|
||||
if [[ -z $WEBCAM_DEVICE ]]; then
|
||||
notify-send "No webcam devices found" -u critical -t 3000
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get monitor scale
|
||||
local scale=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .scale')
|
||||
|
||||
# Target width (base 360px, scaled to monitor)
|
||||
local target_width=$(awk "BEGIN {printf \"%.0f\", 360 * $scale}")
|
||||
|
||||
# Try preferred 16:9 resolutions in order, use first available
|
||||
local preferred_resolutions=("640x360" "1280x720" "1920x1080")
|
||||
local video_size_arg=""
|
||||
local available_formats=$(v4l2-ctl --list-formats-ext -d "$WEBCAM_DEVICE" 2>/dev/null)
|
||||
|
||||
for resolution in "${preferred_resolutions[@]}"; do
|
||||
if echo "$available_formats" | grep -q "$resolution"; then
|
||||
video_size_arg="-video_size $resolution"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
ffplay -f v4l2 $video_size_arg -framerate 30 "$WEBCAM_DEVICE" \
|
||||
-vf "crop=iw/2:ih,scale=${target_width}:-1" \
|
||||
-window_title "WebcamOverlay" \
|
||||
-noborder \
|
||||
-fflags nobuffer -flags low_delay \
|
||||
-probesize 32 -analyzeduration 0 \
|
||||
-loglevel quiet &
|
||||
sleep 1
|
||||
}
|
||||
|
||||
cleanup_webcam() {
|
||||
pkill -f "WebcamOverlay" 2>/dev/null
|
||||
}
|
||||
|
||||
default_resolution() {
|
||||
local width height
|
||||
read -r width height < <(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | "\(.width) \(.height)"')
|
||||
if ((width > 3840 || height > 2160)); then
|
||||
echo "3840x2160"
|
||||
else
|
||||
echo "0x0"
|
||||
fi
|
||||
}
|
||||
|
||||
start_screenrecording() {
|
||||
local filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4"
|
||||
local audio_devices=""
|
||||
local audio_args=()
|
||||
|
||||
[[ $DESKTOP_AUDIO == "true" ]] && audio_devices+="default_output"
|
||||
|
||||
if [[ $MICROPHONE_AUDIO == "true" ]]; then
|
||||
# Merge audio tracks into one - separate tracks only play one at a time in most players
|
||||
[[ -n $audio_devices ]] && audio_devices+="|"
|
||||
audio_devices+="default_input"
|
||||
fi
|
||||
|
||||
[[ -n $audio_devices ]] && audio_args+=(-a "$audio_devices" -ac aac)
|
||||
|
||||
local resolution="${RESOLUTION:-$(default_resolution)}"
|
||||
|
||||
gpu-screen-recorder -w portal -k auto -s "$resolution" -f 60 -fm cfr -fallback-cpu-encoding yes -o "$filename" "${audio_args[@]}" &
|
||||
local pid=$!
|
||||
|
||||
# Wait for recording to actually start (file appears after portal selection)
|
||||
while kill -0 $pid 2>/dev/null && [[ ! -f $filename ]]; do
|
||||
sleep 0.2
|
||||
done
|
||||
|
||||
if kill -0 $pid 2>/dev/null; then
|
||||
echo "$filename" >"$RECORDING_FILE"
|
||||
toggle_screenrecording_indicator
|
||||
fi
|
||||
}
|
||||
|
||||
stop_screenrecording() {
|
||||
pkill -SIGINT -f "^gpu-screen-recorder" # SIGINT required to save video properly
|
||||
|
||||
# Wait a maximum of 5 seconds to finish before hard killing
|
||||
local count=0
|
||||
while pgrep -f "^gpu-screen-recorder" >/dev/null && ((count < 50)); do
|
||||
sleep 0.1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
toggle_screenrecording_indicator
|
||||
cleanup_webcam
|
||||
|
||||
if pgrep -f "^gpu-screen-recorder" >/dev/null; then
|
||||
pkill -9 -f "^gpu-screen-recorder"
|
||||
notify-send "Screen recording error" "Recording process had to be force-killed. Video may be corrupted." -u critical -t 5000
|
||||
else
|
||||
trim_first_frame
|
||||
local filename=$(cat "$RECORDING_FILE" 2>/dev/null)
|
||||
local preview="${filename%.mp4}-preview.png"
|
||||
|
||||
# Generate a preview thumbnail from the first frame
|
||||
ffmpeg -y -i "$filename" -ss 00:00:00.1 -vframes 1 -q:v 2 "$preview" -loglevel quiet 2>/dev/null
|
||||
|
||||
(
|
||||
ACTION=$(notify-send "Screen recording saved" "Open with Super + Alt + , (or click this)" -t 10000 -i "${preview:-$filename}" -A "default=open")
|
||||
[[ $ACTION == "default" ]] && mpv "$filename"
|
||||
rm -f "$preview"
|
||||
) &
|
||||
fi
|
||||
|
||||
rm -f "$RECORDING_FILE"
|
||||
}
|
||||
|
||||
toggle_screenrecording_indicator() {
|
||||
pkill -RTMIN+8 waybar
|
||||
}
|
||||
|
||||
screenrecording_active() {
|
||||
pgrep -f "^gpu-screen-recorder" >/dev/null
|
||||
}
|
||||
|
||||
trim_first_frame() {
|
||||
local latest
|
||||
latest=$(cat "$RECORDING_FILE" 2>/dev/null)
|
||||
|
||||
if [[ -n $latest && -f $latest ]]; then
|
||||
local trimmed="${latest%.mp4}-trimmed.mp4"
|
||||
if ffmpeg -y -ss 0.1 -i "$latest" -c copy "$trimmed" -loglevel quiet 2>/dev/null; then
|
||||
mv "$trimmed" "$latest"
|
||||
else
|
||||
rm -f "$trimmed"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if screenrecording_active; then
|
||||
stop_screenrecording
|
||||
elif [[ $STOP_RECORDING == "true" ]]; then
|
||||
exit 1
|
||||
else
|
||||
[[ $WEBCAM == "true" ]] && start_webcam_overlay
|
||||
|
||||
start_screenrecording || cleanup_webcam
|
||||
fi
|
||||
36
bin/utils/nomarchy-cmd-screensaver
Executable file
36
bin/utils/nomarchy-cmd-screensaver
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run the Nnomarchy screensaver using random effects from TTE.
|
||||
|
||||
screensaver_in_focus() {
|
||||
hyprctl activewindow -j | jq -e '.class == "org.nnomarchy.screensaver"' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
exit_screensaver() {
|
||||
hyprctl keyword cursor:invisible false &>/dev/null || true
|
||||
pkill -x tte 2>/dev/null
|
||||
pkill -f org.nnomarchy.screensaver 2>/dev/null
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Exit the screensaver on signals and input from keyboard and mouse
|
||||
trap exit_screensaver SIGINT SIGTERM SIGHUP SIGQUIT
|
||||
|
||||
printf '\033]11;rgb:00/00/00\007' # Set background color to black
|
||||
|
||||
hyprctl keyword cursor:invisible true &>/dev/null
|
||||
|
||||
tty=$(tty 2>/dev/null)
|
||||
|
||||
while true; do
|
||||
tte -i ~/.config/nnomarchy/branding/screensaver.txt \
|
||||
--frame-rate 120 --canvas-width 0 --canvas-height 0 --reuse-canvas --anchor-canvas c --anchor-text c\
|
||||
--random-effect --exclude-effects dev_worm \
|
||||
--no-eol --no-restore-cursor &
|
||||
|
||||
while pgrep -t "${tty#/dev/}" -x tte >/dev/null; do
|
||||
if read -n1 -t 1 || ! screensaver_in_focus; then
|
||||
exit_screensaver
|
||||
fi
|
||||
done
|
||||
done
|
||||
133
bin/utils/nomarchy-cmd-screenshot
Executable file
133
bin/utils/nomarchy-cmd-screenshot
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Take a screenshot of the whole screen, a specific window, or a user-drawn region.
|
||||
# Saves to ~/Pictures by default, but that can be changed via NOMARCHY_SCREENSHOT_DIR or XDG_PICTURES_DIR ENVs.
|
||||
# Editor defaults to Satty but can be changed via --editor=<name> or NOMARCHY_SCREENSHOT_EDITOR env
|
||||
|
||||
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
|
||||
OUTPUT_DIR="${NOMARCHY_SCREENSHOT_DIR:-${XDG_PICTURES_DIR:-$HOME/Pictures}}"
|
||||
|
||||
if [[ ! -d $OUTPUT_DIR ]]; then
|
||||
notify-send "Screenshot directory does not exist: $OUTPUT_DIR" -u critical -t 3000
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pkill slurp && exit 0
|
||||
|
||||
SCREENSHOT_EDITOR="${NOMARCHY_SCREENSHOT_EDITOR:-satty}"
|
||||
|
||||
# Parse --editor flag from any position
|
||||
ARGS=()
|
||||
for arg in "$@"; do
|
||||
if [[ $arg == --editor=* ]]; then
|
||||
SCREENSHOT_EDITOR="${arg#--editor=}"
|
||||
else
|
||||
ARGS+=("$arg")
|
||||
fi
|
||||
done
|
||||
set -- "${ARGS[@]}"
|
||||
|
||||
open_editor() {
|
||||
local filepath="$1"
|
||||
if [[ $SCREENSHOT_EDITOR == "satty" ]]; then
|
||||
satty --filename "$filepath" \
|
||||
--output-filename "$filepath" \
|
||||
--actions-on-enter save-to-clipboard \
|
||||
--save-after-copy \
|
||||
--copy-command 'wl-copy'
|
||||
else
|
||||
$SCREENSHOT_EDITOR "$filepath"
|
||||
fi
|
||||
}
|
||||
|
||||
MODE="${1:-smart}"
|
||||
PROCESSING="${2:-slurp}"
|
||||
|
||||
# accounting for portrait/transformed displays
|
||||
JQ_MONITOR_GEO='
|
||||
def format_geo:
|
||||
.x as $x | .y as $y |
|
||||
(.width / .scale | floor) as $w |
|
||||
(.height / .scale | floor) as $h |
|
||||
.transform as $t |
|
||||
if $t == 1 or $t == 3 then
|
||||
"\($x),\($y) \($h)x\($w)"
|
||||
else
|
||||
"\($x),\($y) \($w)x\($h)"
|
||||
end;
|
||||
'
|
||||
|
||||
get_rectangles() {
|
||||
local active_workspace=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .activeWorkspace.id')
|
||||
hyprctl monitors -j | jq -r --arg ws "$active_workspace" "${JQ_MONITOR_GEO} .[] | select(.activeWorkspace.id == (\$ws | tonumber)) | format_geo"
|
||||
hyprctl clients -j | jq -r --arg ws "$active_workspace" '.[] | select(.workspace.id == ($ws | tonumber)) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"'
|
||||
}
|
||||
|
||||
# Select based on mode
|
||||
case "$MODE" in
|
||||
region)
|
||||
hyprpicker -r -z >/dev/null 2>&1 &
|
||||
PID=$!
|
||||
sleep .1
|
||||
SELECTION=$(slurp 2>/dev/null)
|
||||
kill $PID 2>/dev/null
|
||||
;;
|
||||
windows)
|
||||
hyprpicker -r -z >/dev/null 2>&1 &
|
||||
PID=$!
|
||||
sleep .1
|
||||
SELECTION=$(get_rectangles | slurp -r 2>/dev/null)
|
||||
kill $PID 2>/dev/null
|
||||
;;
|
||||
fullscreen)
|
||||
SELECTION=$(hyprctl monitors -j | jq -r "${JQ_MONITOR_GEO} .[] | select(.focused == true) | format_geo")
|
||||
;;
|
||||
smart | *)
|
||||
RECTS=$(get_rectangles)
|
||||
hyprpicker -r -z >/dev/null 2>&1 &
|
||||
PID=$!
|
||||
sleep .1
|
||||
SELECTION=$(echo "$RECTS" | slurp 2>/dev/null)
|
||||
kill $PID 2>/dev/null
|
||||
|
||||
# If the selection area is L * W < 20, we'll assume you were trying to select whichever
|
||||
# window or output it was inside of to prevent accidental 2px snapshots
|
||||
if [[ $SELECTION =~ ^([0-9]+),([0-9]+)[[:space:]]([0-9]+)x([0-9]+)$ ]]; then
|
||||
if ((${BASH_REMATCH[3]} * ${BASH_REMATCH[4]} < 20)); then
|
||||
click_x="${BASH_REMATCH[1]}"
|
||||
click_y="${BASH_REMATCH[2]}"
|
||||
|
||||
while IFS= read -r rect; do
|
||||
if [[ $rect =~ ^([0-9]+),([0-9]+)[[:space:]]([0-9]+)x([0-9]+) ]]; then
|
||||
rect_x="${BASH_REMATCH[1]}"
|
||||
rect_y="${BASH_REMATCH[2]}"
|
||||
rect_width="${BASH_REMATCH[3]}"
|
||||
rect_height="${BASH_REMATCH[4]}"
|
||||
|
||||
if ((click_x >= rect_x && click_x < rect_x + rect_width && click_y >= rect_y && click_y < rect_y + rect_height)); then
|
||||
SELECTION="${rect_x},${rect_y} ${rect_width}x${rect_height}"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done <<<"$RECTS"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
[[ -z $SELECTION ]] && exit 0
|
||||
|
||||
FILENAME="screenshot-$(date +'%Y-%m-%d_%H-%M-%S').png"
|
||||
FILEPATH="$OUTPUT_DIR/$FILENAME"
|
||||
|
||||
if [[ $PROCESSING == "slurp" ]]; then
|
||||
grim -g "$SELECTION" "$FILEPATH" || exit 1
|
||||
wl-copy <"$FILEPATH"
|
||||
|
||||
(
|
||||
ACTION=$(notify-send "Screenshot saved to clipboard and file" "Edit with Super + Alt + , (or click this)" -t 10000 -i "$FILEPATH" -A "default=edit")
|
||||
[[ $ACTION == "default" ]] && open_editor "$FILEPATH"
|
||||
) &
|
||||
else
|
||||
grim -g "$SELECTION" - | wl-copy
|
||||
fi
|
||||
46
bin/utils/nomarchy-cmd-share
Executable file
46
bin/utils/nomarchy-cmd-share
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Share clipboard, file, or folder using LocalSend. Bound to Super + Ctrl + S by default.
|
||||
|
||||
if (($# == 0)); then
|
||||
echo "Usage: nnomarchy-cmd-share [clipboard|file|folder]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MODE="$1"
|
||||
shift
|
||||
|
||||
if [[ $MODE == "clipboard" ]]; then
|
||||
TEMP_FILE=$(mktemp --suffix=.txt)
|
||||
wl-paste >"$TEMP_FILE"
|
||||
FILES="$TEMP_FILE"
|
||||
else
|
||||
if (($# > 0)); then
|
||||
FILES="$*"
|
||||
else
|
||||
if [[ $MODE == "folder" ]]; then
|
||||
# Pick a single folder from home directory
|
||||
FILES=$(find "$HOME" -type d 2>/dev/null | fzf)
|
||||
else
|
||||
# Pick one or more files from home directory
|
||||
FILES=$(find "$HOME" -type f 2>/dev/null | fzf --multi)
|
||||
fi
|
||||
[[ -z $FILES ]] && exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run LocalSend in its own systemd service (detached from terminal)
|
||||
# Convert newline-separated files to space-separated arguments
|
||||
if [[ $MODE != "clipboard" ]] && echo "$FILES" | grep -q $'\n'; then
|
||||
# Multiple files selected - convert newlines to array
|
||||
readarray -t FILE_ARRAY <<<"$FILES"
|
||||
systemd-run --user --quiet --collect localsend --headless send "${FILE_ARRAY[@]}"
|
||||
else
|
||||
# Single file or clipboard mode
|
||||
systemd-run --user --quiet --collect localsend --headless send "$FILES"
|
||||
fi
|
||||
|
||||
# Note: Temporary file will remain until system cleanup for clipboard mode
|
||||
# This ensures the file content is available for the LocalSend GUI
|
||||
|
||||
exit 0
|
||||
22
bin/utils/nomarchy-cmd-terminal-cwd
Executable file
22
bin/utils/nomarchy-cmd-terminal-cwd
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Returns the current working directory of the active terminal window,
|
||||
# so a new terminal window can be started in the same directory.
|
||||
|
||||
# Go from current active terminal to its child shell process and run cwd there
|
||||
terminal_pid=$(hyprctl activewindow | awk '/pid:/ {print $2}')
|
||||
shell_pid=$(pgrep -P "$terminal_pid" | tail -n1)
|
||||
|
||||
if [[ -n $shell_pid ]]; then
|
||||
cwd=$(readlink -f "/proc/$shell_pid/cwd" 2>/dev/null)
|
||||
shell=$(readlink -f "/proc/$shell_pid/exe" 2>/dev/null)
|
||||
|
||||
# Check if $shell is a valid shell and $cwd is a directory.
|
||||
if grep -qs "$shell" /etc/shells && [[ -d $cwd ]]; then
|
||||
echo "$cwd"
|
||||
else
|
||||
echo "$HOME"
|
||||
fi
|
||||
else
|
||||
echo "$HOME"
|
||||
fi
|
||||
45
bin/utils/nomarchy-config-direct-boot
Executable file
45
bin/utils/nomarchy-config-direct-boot
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Add an EFI boot entry for the Nnomarchy UKI, allowing the system to boot directly
|
||||
# without a bootloader like Limine. Requires UEFI firmware and a built UKI.
|
||||
|
||||
if [[ ! -d /sys/firmware/efi ]]; then
|
||||
echo "Error: System is not booted in UEFI mode" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! efibootmgr &>/dev/null; then
|
||||
echo "Error: efibootmgr is not available or not functional" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if cat /sys/class/dmi/id/bios_vendor 2>/dev/null | grep -qi "American Megatrends"; then
|
||||
echo "Error: American Megatrends firmware may not safely support custom EFI entries" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if cat /sys/class/dmi/id/bios_vendor 2>/dev/null | grep -qi "Apple"; then
|
||||
echo "Error: Apple firmware uses its own boot manager" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
uki_file=$(find /boot/EFI/Linux/ -name "nnomarchy*.efi" -printf "%f\n" 2>/dev/null | head -1)
|
||||
|
||||
if [[ -z $uki_file ]]; then
|
||||
echo "Error: No Nnomarchy UKI found in /boot/EFI/Linux/" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
boot_source=$(findmnt -n -o SOURCE /boot)
|
||||
disk=$(echo "$boot_source" | sed 's/p\?[0-9]*$//')
|
||||
part=$(echo "$boot_source" | grep -o 'p\?[0-9]*$' | sed 's/^p//')
|
||||
|
||||
if gum confirm "Setup direct boot (so snapshot booting must be done via bios)?"; then
|
||||
echo "Creating EFI boot entry for $uki_file"
|
||||
|
||||
sudo efibootmgr --create \
|
||||
--disk "$disk" \
|
||||
--part "$part" \
|
||||
--label "Nnomarchy" \
|
||||
--loader "\\EFI\\Linux\\$uki_file"
|
||||
fi
|
||||
49
bin/utils/nomarchy-drive-info
Executable file
49
bin/utils/nomarchy-drive-info
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Returns drive information about a given volumne, like /dev/nvme0, which is used by nnomarchy-drive-select.
|
||||
|
||||
if (($# == 0)); then
|
||||
echo "Usage: nnomarchy-drive-info [/dev/drive]"
|
||||
exit 1
|
||||
else
|
||||
drive="$1"
|
||||
fi
|
||||
|
||||
# Find the root drive in case we are looking at partitions
|
||||
root_drive=$(lsblk -no PKNAME "$drive" 2>/dev/null | tail -n1)
|
||||
if [[ -n $root_drive ]]; then
|
||||
root_drive="/dev/$root_drive"
|
||||
else
|
||||
root_drive="$drive"
|
||||
fi
|
||||
|
||||
# Get basic disk information
|
||||
size=$(lsblk -dno SIZE "$drive" 2>/dev/null)
|
||||
vendor=$(lsblk -dno VENDOR "$root_drive" 2>/dev/null | sed 's/ *$//')
|
||||
model=$(lsblk -dno MODEL "$root_drive" 2>/dev/null | sed 's/ *$//')
|
||||
|
||||
# Combine vendor and model, avoiding duplication
|
||||
label=""
|
||||
if [[ -n $vendor && -n $model ]]; then
|
||||
if [[ $model == *$vendor* ]]; then
|
||||
label="$model"
|
||||
else
|
||||
label="$vendor $model"
|
||||
fi
|
||||
elif [[ -n $model ]]; then
|
||||
label="$model"
|
||||
elif [[ -n $vendor ]]; then
|
||||
label="$vendor"
|
||||
fi
|
||||
|
||||
# Format display string
|
||||
display="$drive"
|
||||
[[ -n $size ]] && display="$display ($size)"
|
||||
[[ -n $label ]] && display="$display - $label"
|
||||
|
||||
# Append compact partition summary
|
||||
part_summary=$(lsblk -nro TYPE,NAME,FSTYPE,MOUNTPOINT "$root_drive" 2>/dev/null | \
|
||||
awk '$1=="part" { printf "%s%s%s", s, ($3==""?"unknown":$3), ($4==""?"":"("$4")"); s=", " }')
|
||||
[[ -n $part_summary ]] && display+=" [$part_summary]"
|
||||
|
||||
echo "$display"
|
||||
18
bin/utils/nomarchy-drive-select
Executable file
18
bin/utils/nomarchy-drive-select
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Select a drive from a list with info that includes space and brand. Used by nnomarchy-drive-set-password.
|
||||
|
||||
if (($# == 0)); then
|
||||
drives=$(lsblk -dpno NAME | grep -E '/dev/(sd|hd|vd|nvme|mmcblk|xv)')
|
||||
else
|
||||
drives="$@"
|
||||
fi
|
||||
|
||||
drives_with_info=""
|
||||
while IFS= read -r drive; do
|
||||
[[ -n $drive ]] || continue
|
||||
drives_with_info+="$(nnomarchy-drive-info "$drive")"$'\n'
|
||||
done <<<"$drives"
|
||||
|
||||
selected_drive="$(printf "%s" "$drives_with_info" | gum choose --header "Select drive")" || exit 1
|
||||
printf "%s\n" "$selected_drive" | awk '{print $1}'
|
||||
23
bin/utils/nomarchy-drive-set-password
Executable file
23
bin/utils/nomarchy-drive-set-password
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set a new encryption password for a drive selected.
|
||||
|
||||
encrypted_drives=$(blkid -t TYPE=crypto_LUKS -o device)
|
||||
|
||||
if [[ -n $encrypted_drives ]]; then
|
||||
if (( $(wc -l <<<encrypted_drives) == 1 )); then
|
||||
drive_to_change="$encrypted_drives"
|
||||
else
|
||||
drive_to_change="$(nnomarchy-drive-select "$encrypted_drives")"
|
||||
fi
|
||||
|
||||
if [[ -n $drive_to_change ]]; then
|
||||
echo "Changing full-disk encryption password for $drive_to_change"
|
||||
sudo cryptsetup luksChangeKey --pbkdf argon2id --iter-time 2000 "$drive_to_change"
|
||||
else
|
||||
echo "No drive selected."
|
||||
fi
|
||||
else
|
||||
echo "No encrypted drives available."
|
||||
exit 1
|
||||
fi
|
||||
18
bin/utils/nomarchy-hook
Executable file
18
bin/utils/nomarchy-hook
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run a named hook, like post-update (available in ~/.config/nnomarchy/hooks/post-update).
|
||||
|
||||
set -e
|
||||
|
||||
if (( $# < 1 )); then
|
||||
echo "Usage: nnomarchy-hook [name] [args...]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HOOK=$1
|
||||
HOOK_PATH="$HOME/.config/nnomarchy/hooks/$1"
|
||||
shift
|
||||
|
||||
if [[ -f $HOOK_PATH ]]; then
|
||||
bash "$HOOK_PATH" "$@"
|
||||
fi
|
||||
17
bin/utils/nomarchy-lock-screen
Executable file
17
bin/utils/nomarchy-lock-screen
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Locks the system using hyprlock, but not before ensuring 1password has also been locked, and the screensaver stopped.
|
||||
|
||||
# Lock the screen
|
||||
pidof hyprlock || hyprlock &
|
||||
|
||||
# Set keyboard layout to default (first layout)
|
||||
hyprctl switchxkblayout all 0 > /dev/null 2>&1
|
||||
|
||||
# Ensure 1password is locked
|
||||
if pgrep -x "1password" >/dev/null; then
|
||||
1password --lock &
|
||||
fi
|
||||
|
||||
# Avoid running screensaver when locked
|
||||
pkill -f org.nnomarchy.screensaver
|
||||
379
bin/utils/nomarchy-menu
Executable file
379
bin/utils/nomarchy-menu
Executable file
@@ -0,0 +1,379 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Launch the Nnomarchy Menu or takes a parameter to jump straight to a submenu.
|
||||
|
||||
export PATH="$HOME/.local/share/nnomarchy/bin:$PATH"
|
||||
|
||||
# Set to true when going directly to a submenu, so we can exit directly
|
||||
BACK_TO_EXIT=false
|
||||
|
||||
back_to() {
|
||||
local parent_menu="$1"
|
||||
|
||||
if [[ $BACK_TO_EXIT == "true" ]]; then
|
||||
exit 0
|
||||
elif [[ -n $parent_menu ]]; then
|
||||
"$parent_menu"
|
||||
else
|
||||
show_main_menu
|
||||
fi
|
||||
}
|
||||
|
||||
toggle_existing_menu() {
|
||||
if pgrep -f "walker.*--dmenu" >/dev/null; then
|
||||
walker --close >/dev/null 2>&1
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
menu() {
|
||||
local prompt="$1"
|
||||
local options="$2"
|
||||
local extra="$3"
|
||||
local preselect="$4"
|
||||
|
||||
read -r -a args <<<"$extra"
|
||||
|
||||
if [[ -n $preselect ]]; then
|
||||
local index
|
||||
index=$(echo -e "$options" | grep -nxF "$preselect" | cut -d: -f1)
|
||||
if [[ -n $index ]]; then
|
||||
args+=("-c" "$index")
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "$options" | nnomarchy-launch-walker --dmenu --width 295 --minheight 1 --maxheight 630 -p "$prompt…" "${args[@]}" 2>/dev/null
|
||||
}
|
||||
|
||||
terminal() {
|
||||
xdg-terminal-exec --app-id=org.nnomarchy.terminal "$@"
|
||||
}
|
||||
|
||||
present_terminal() {
|
||||
nnomarchy-launch-floating-terminal-with-presentation $1
|
||||
}
|
||||
|
||||
open_in_editor() {
|
||||
notify-send -u low "Editing config file" "$1"
|
||||
nnomarchy-launch-editor "$1"
|
||||
}
|
||||
|
||||
show_learn_menu() {
|
||||
case $(menu "Learn" " Keybindings\n Nnomarchy\n Hyprland\n Arch\n Neovim\n Bash") in
|
||||
*Keybindings*) nnomarchy-menu-keybindings ;;
|
||||
*Nnomarchy*) nnomarchy-launch-webapp "https://learn.omacom.io/2/the-nnomarchy-manual" ;;
|
||||
*Hyprland*) nnomarchy-launch-webapp "https://wiki.hypr.land/" ;;
|
||||
*Arch*) nnomarchy-launch-webapp "https://wiki.archlinux.org/title/Main_page" ;;
|
||||
*Bash*) nnomarchy-launch-webapp "https://devhints.io/bash" ;;
|
||||
*Neovim*) nnomarchy-launch-webapp "https://www.lazyvim.org/keymaps" ;;
|
||||
*) show_main_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_trigger_menu() {
|
||||
case $(menu "Trigger" " Capture\n Share\n Toggle\n Hardware") in
|
||||
*Capture*) show_capture_menu ;;
|
||||
*Share*) show_share_menu ;;
|
||||
*Toggle*) show_toggle_menu ;;
|
||||
*Hardware*) show_hardware_menu ;;
|
||||
*) show_main_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_capture_menu() {
|
||||
case $(menu "Capture" " Screenshot\n Screenrecord\n Color") in
|
||||
*Screenshot*) nnomarchy-cmd-screenshot ;;
|
||||
*Screenrecord*) show_screenrecord_menu ;;
|
||||
*Color*) pkill hyprpicker || hyprpicker -a ;;
|
||||
*) back_to show_trigger_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_webcam_list() {
|
||||
v4l2-ctl --list-devices 2>/dev/null | while IFS= read -r line; do
|
||||
if [[ $line != $'\t'* && -n $line ]]; then
|
||||
local name="$line"
|
||||
IFS= read -r device || break
|
||||
device=$(echo "$device" | tr -d '\t' | head -1)
|
||||
[[ -n $device ]] && echo "$device $name"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
show_webcam_select_menu() {
|
||||
local devices=$(get_webcam_list)
|
||||
local count=$(echo "$devices" | grep -c . 2>/dev/null || echo 0)
|
||||
|
||||
if [[ -z $devices ]] || ((count == 0)); then
|
||||
notify-send "No webcam devices found" -u critical -t 3000
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ((count == 1)); then
|
||||
echo "$devices" | awk '{print $1}'
|
||||
else
|
||||
menu "Select Webcam" "$devices" | awk '{print $1}'
|
||||
fi
|
||||
}
|
||||
|
||||
show_screenrecord_menu() {
|
||||
nnomarchy-cmd-screenrecord --stop-recording && exit 0
|
||||
|
||||
case $(menu "Screenrecord" " With no audio\n With desktop audio\n With desktop + microphone audio\n With desktop + microphone audio + webcam") in
|
||||
*"With no audio") nnomarchy-cmd-screenrecord ;;
|
||||
*"With desktop audio") nnomarchy-cmd-screenrecord --with-desktop-audio ;;
|
||||
*"With desktop + microphone audio") nnomarchy-cmd-screenrecord --with-desktop-audio --with-microphone-audio ;;
|
||||
*"With desktop + microphone audio + webcam")
|
||||
local device=$(show_webcam_select_menu) || {
|
||||
back_to show_capture_menu
|
||||
return
|
||||
}
|
||||
nnomarchy-cmd-screenrecord --with-desktop-audio --with-microphone-audio --with-webcam --webcam-device="$device"
|
||||
;;
|
||||
*) back_to show_capture_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_share_menu() {
|
||||
case $(menu "Share" " Clipboard\n File \n Folder") in
|
||||
*Clipboard*) nnomarchy-cmd-share clipboard ;;
|
||||
*File*) terminal bash -c "nnomarchy-cmd-share file" ;;
|
||||
*Folder*) terminal bash -c "nnomarchy-cmd-share folder" ;;
|
||||
*) back_to show_trigger_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_toggle_menu() {
|
||||
case $(menu "Toggle" " Screensaver\n Nightlight\n Idle Lock\n Top Bar\n Workspace Layout\n Window Gaps\n 1-Window Ratio\n Display Scaling") in
|
||||
|
||||
*Screensaver*) nnomarchy-toggle-screensaver ;;
|
||||
*Nightlight*) nnomarchy-toggle-nightlight ;;
|
||||
*Idle*) nnomarchy-toggle-idle ;;
|
||||
*Bar*) nnomarchy-toggle-waybar ;;
|
||||
*Layout*) nnomarchy-hyprland-workspace-layout-toggle ;;
|
||||
*Ratio*) nnomarchy-hyprland-window-single-square-aspect-toggle ;;
|
||||
*Gaps*) nnomarchy-hyprland-window-gaps-toggle ;;
|
||||
*Scaling*) nnomarchy-hyprland-monitor-scaling-cycle ;;
|
||||
*) back_to show_trigger_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_hardware_menu() {
|
||||
case $(menu "Toggle" " Hybrid GPU") in
|
||||
*"Hybrid GPU"*) present_terminal nnomarchy-toggle-hybrid-gpu ;;
|
||||
*) show_trigger_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_style_menu() {
|
||||
case $(menu "Style" " Theme\n Font\n Background\n Hyprland\n Screensaver\n About") in
|
||||
*Theme*) show_theme_menu ;;
|
||||
*Font*) show_font_menu ;;
|
||||
*Background*) show_background_menu ;;
|
||||
*Hyprland*) open_in_editor ~/.config/hypr/looknfeel.conf ;;
|
||||
*Screensaver*) open_in_editor ~/.config/nnomarchy/branding/screensaver.txt ;;
|
||||
*About*) open_in_editor ~/.config/nnomarchy/branding/about.txt ;;
|
||||
*) show_main_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_theme_menu() {
|
||||
nnomarchy-launch-walker -m menus:nnomarchythemes --width 800 --minheight 400
|
||||
}
|
||||
|
||||
show_background_menu() {
|
||||
nnomarchy-launch-walker -m menus:nnomarchyBackgroundSelector --width 800 --minheight 400
|
||||
}
|
||||
|
||||
show_font_menu() {
|
||||
theme=$(menu "Font" "$(nnomarchy-font-list)" "--width 350" "$(nnomarchy-font-current)")
|
||||
if [[ $theme == "CNCLD" || -z $theme ]]; then
|
||||
back_to show_style_menu
|
||||
else
|
||||
nnomarchy-font-set "$theme"
|
||||
fi
|
||||
}
|
||||
|
||||
show_setup_menu() {
|
||||
local options=" Audio\n Wifi\n Bluetooth\n Power Profile\n System Sleep\n Monitors"
|
||||
[[ -f ~/.config/hypr/bindings.conf ]] && options="$options\n Keybindings"
|
||||
options="$options\n Key Remapping"
|
||||
[[ -f ~/.config/hypr/input.conf ]] && options="$options\n Input"
|
||||
options="$options\n DNS\n Security\n Config"
|
||||
|
||||
case $(menu "Setup" "$options") in
|
||||
*Audio*) nnomarchy-launch-audio ;;
|
||||
*Wifi*) nnomarchy-launch-wifi ;;
|
||||
*Bluetooth*) nnomarchy-launch-bluetooth ;;
|
||||
*Power*) show_setup_power_menu ;;
|
||||
*System*) show_setup_system_menu ;;
|
||||
*Monitors*) open_in_editor ~/.config/hypr/monitors.conf ;;
|
||||
*Keybindings*) open_in_editor ~/.config/hypr/bindings.conf ;;
|
||||
*Input*) open_in_editor ~/.config/hypr/input.conf ;;
|
||||
*Key\ Remapping*) nnomarchy-setup-makima && open_in_editor "$HOME/.config/makima/AT Translated Set 2 keyboard.toml" && nnomarchy-restart-makima ;;
|
||||
*DNS*) present_terminal nnomarchy-setup-dns ;;
|
||||
*Security*) show_setup_security_menu ;;
|
||||
*Config*) show_setup_config_menu ;;
|
||||
*) show_main_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_setup_power_menu() {
|
||||
profile=$(menu "Power Profile" "$(nnomarchy-powerprofiles-list)" "" "$(powerprofilesctl get)")
|
||||
|
||||
if [[ $profile == "CNCLD" || -z $profile ]]; then
|
||||
back_to show_setup_menu
|
||||
else
|
||||
powerprofilesctl set "$profile"
|
||||
fi
|
||||
}
|
||||
|
||||
show_setup_security_menu() {
|
||||
case $(menu "Setup" " Fingerprint\n Fido2") in
|
||||
*Fingerprint*) present_terminal nnomarchy-setup-fingerprint ;;
|
||||
*Fido2*) present_terminal nnomarchy-setup-fido2 ;;
|
||||
*) show_setup_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_setup_config_menu() {
|
||||
case $(menu "Setup" " Defaults\n Hyprland\n Hypridle\n Hyprlock\n Hyprsunset\n Swayosd\n Walker\n Waybar\n XCompose") in
|
||||
*Defaults*) open_in_editor ~/.config/uwsm/default ;;
|
||||
*Hyprland*) open_in_editor ~/.config/hypr/hyprland.conf ;;
|
||||
*Hypridle*) open_in_editor ~/.config/hypr/hypridle.conf && nnomarchy-restart-hypridle ;;
|
||||
*Hyprlock*) open_in_editor ~/.config/hypr/hyprlock.conf ;;
|
||||
*Hyprsunset*) open_in_editor ~/.config/hypr/hyprsunset.conf && nnomarchy-restart-hyprsunset ;;
|
||||
*Swayosd*) open_in_editor ~/.config/swayosd/config.toml && nnomarchy-restart-swayosd ;;
|
||||
*Walker*) open_in_editor ~/.config/walker/config.toml && nnomarchy-restart-walker ;;
|
||||
*Waybar*) open_in_editor ~/.config/waybar/config.jsonc && nnomarchy-restart-waybar ;;
|
||||
*XCompose*) open_in_editor ~/.XCompose && nnomarchy-restart-xcompose ;;
|
||||
*) show_setup_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_setup_system_menu() {
|
||||
local options=""
|
||||
|
||||
if [[ $NNOMARCHY_TOGGLE_SUSPEND == "false" ]]; then
|
||||
options="$options Enable Suspend"
|
||||
else
|
||||
options="$options Disable Suspend"
|
||||
fi
|
||||
|
||||
if nnomarchy-hibernation-available; then
|
||||
options="$options\n Disable Hibernate"
|
||||
else
|
||||
options="$options\n Enable Hibernate"
|
||||
fi
|
||||
|
||||
case $(menu "System" "$options") in
|
||||
*Suspend*) nnomarchy-toggle-suspend ;;
|
||||
*"Enable Hibernate"*) present_terminal nnomarchy-hibernation-setup ;;
|
||||
*"Disable Hibernate"*) present_terminal nnomarchy-hibernation-remove ;;
|
||||
*) show_setup_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
|
||||
show_update_menu() {
|
||||
case $(menu "Update" " Nnomarchy\n Extra Themes\n Process\n Hardware\n Firmware\n Password\n Timezone\n Time") in
|
||||
*Nnomarchy*) present_terminal nnomarchy-update ;;
|
||||
*Themes*) present_terminal nnomarchy-theme-update ;;
|
||||
*Process*) show_update_process_menu ;;
|
||||
*Hardware*) show_update_hardware_menu ;;
|
||||
*Firmware*) present_terminal nnomarchy-update-firmware ;;
|
||||
*Timezone*) present_terminal nnomarchy-tz-select ;;
|
||||
*Time*) present_terminal nnomarchy-update-time ;;
|
||||
*Password*) show_update_password_menu ;;
|
||||
*) show_main_menu ;;
|
||||
esac
|
||||
}
|
||||
show_update_process_menu() {
|
||||
case $(menu "Restart" " Hypridle\n Hyprsunset\n Swayosd\n Walker\n Waybar") in
|
||||
*Hypridle*) nnomarchy-restart-hypridle ;;
|
||||
*Hyprsunset*) nnomarchy-restart-hyprsunset ;;
|
||||
*Swayosd*) nnomarchy-restart-swayosd ;;
|
||||
*Walker*) nnomarchy-restart-walker ;;
|
||||
*Waybar*) nnomarchy-restart-waybar ;;
|
||||
*) show_update_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
|
||||
show_update_hardware_menu() {
|
||||
case $(menu "Restart" " Audio\n Wi-Fi\n Bluetooth") in
|
||||
*Audio*) present_terminal nnomarchy-restart-pipewire ;;
|
||||
*Wi-Fi*) present_terminal nnomarchy-restart-wifi ;;
|
||||
*Bluetooth*) present_terminal nnomarchy-restart-bluetooth ;;
|
||||
*) show_update_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_update_password_menu() {
|
||||
case $(menu "Update Password" " Drive Encryption\n User") in
|
||||
*Drive*) present_terminal nnomarchy-drive-set-password ;;
|
||||
*User*) present_terminal passwd ;;
|
||||
*) show_update_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_about() {
|
||||
nnomarchy-launch-about
|
||||
}
|
||||
|
||||
show_system_menu() {
|
||||
local options=" Screensaver\n Lock"
|
||||
[[ $NNOMARCHY_TOGGLE_SUSPEND != "false" ]] && options="$options\n Suspend"
|
||||
nnomarchy-hibernation-available && options="$options\n Hibernate"
|
||||
options="$options\n Logout\n Restart\n Shutdown"
|
||||
|
||||
case $(menu "System" "$options") in
|
||||
*Screensaver*) nnomarchy-launch-screensaver force ;;
|
||||
*Lock*) nnomarchy-lock-screen ;;
|
||||
*Suspend*) systemctl suspend ;;
|
||||
*Hibernate*) systemctl hibernate ;;
|
||||
*Logout*) nnomarchy-system-logout ;;
|
||||
*Restart*) nnomarchy-system-reboot ;;
|
||||
*Shutdown*) nnomarchy-system-shutdown ;;
|
||||
*) back_to show_main_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_main_menu() {
|
||||
go_to_menu "$(menu "Go" " Apps\n Learn\n Trigger\n Style\n Setup\n Update\n About\n System")"
|
||||
}
|
||||
|
||||
go_to_menu() {
|
||||
case "${1,,}" in
|
||||
*apps*) walker -p "Launch…" ;;
|
||||
*learn*) show_learn_menu ;;
|
||||
*trigger*) show_trigger_menu ;;
|
||||
*toggle*) show_toggle_menu ;;
|
||||
*share*) show_share_menu ;;
|
||||
*background*) show_background_menu ;;
|
||||
*capture*) show_capture_menu ;;
|
||||
*style*) show_style_menu ;;
|
||||
*theme*) show_theme_menu ;;
|
||||
*screenrecord*) show_screenrecord_menu ;;
|
||||
*setup*) show_setup_menu ;;
|
||||
*power*) show_setup_power_menu ;;
|
||||
*update*) show_update_menu ;;
|
||||
*about*) show_about ;;
|
||||
*system*) show_system_menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Allow user extensions and overrides
|
||||
USER_EXTENSIONS="$HOME/.config/nnomarchy/extensions/menu.sh"
|
||||
[[ -f $USER_EXTENSIONS ]] && source "$USER_EXTENSIONS"
|
||||
|
||||
toggle_existing_menu
|
||||
|
||||
if [[ -n $1 ]]; then
|
||||
BACK_TO_EXIT=true
|
||||
go_to_menu "$1"
|
||||
else
|
||||
show_main_menu
|
||||
fi
|
||||
247
bin/utils/nomarchy-menu-keybindings
Executable file
247
bin/utils/nomarchy-menu-keybindings
Executable file
@@ -0,0 +1,247 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Display Hyprland keybindings defined in your configuration using walker for an interactive search menu.
|
||||
|
||||
declare -A KEYCODE_SYM_MAP
|
||||
|
||||
build_keymap_cache() {
|
||||
local keymap
|
||||
keymap="$(xkbcli compile-keymap)" || {
|
||||
echo "Failed to compile keymap" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
while IFS=, read -r code sym; do
|
||||
[[ -z $code || -z $sym ]] && continue
|
||||
KEYCODE_SYM_MAP["$code"]="$sym"
|
||||
done < <(
|
||||
awk '
|
||||
BEGIN { sec = "" }
|
||||
/xkb_keycodes/ { sec = "codes"; next }
|
||||
/xkb_symbols/ { sec = "syms"; next }
|
||||
sec == "codes" {
|
||||
if (match($0, /<([A-Za-z0-9_]+)>\s*=\s*([0-9]+)\s*;/, m)) code_by_name[m[1]] = m[2]
|
||||
}
|
||||
sec == "syms" {
|
||||
if (match($0, /key\s*<([A-Za-z0-9_]+)>\s*\{\s*\[\s*([^, \]]+)/, m)) sym_by_name[m[1]] = m[2]
|
||||
}
|
||||
END {
|
||||
for (k in code_by_name) {
|
||||
c = code_by_name[k]
|
||||
s = sym_by_name[k]
|
||||
if (c != "" && s != "" && s != "NoSymbol") print c "," s
|
||||
}
|
||||
}
|
||||
' <<<"$keymap"
|
||||
)
|
||||
}
|
||||
|
||||
lookup_keycode_cached() {
|
||||
printf '%s\n' "${KEYCODE_SYM_MAP[$1]}"
|
||||
}
|
||||
|
||||
parse_keycodes() {
|
||||
local start end elapsed
|
||||
[[ ${DEBUG:-0} == "1" ]] && start=$(date +%s.%N)
|
||||
while IFS= read -r line; do
|
||||
if [[ $line =~ code:([0-9]+) ]]; then
|
||||
code="${BASH_REMATCH[1]}"
|
||||
symbol=$(lookup_keycode_cached "$code" "$XKB_KEYMAP_CACHE")
|
||||
echo "${line/code:${code}/$symbol}"
|
||||
elif [[ $line =~ mouse:([0-9]+) ]]; then
|
||||
code="${BASH_REMATCH[1]}"
|
||||
|
||||
case "$code" in
|
||||
272) symbol="LEFT MOUSE BUTTON" ;;
|
||||
273) symbol="RIGHT MOUSE BUTTON" ;;
|
||||
274) symbol="MIDDLE MOUSE BUTTON" ;;
|
||||
*) symbol="mouse:${code}" ;;
|
||||
esac
|
||||
|
||||
echo "${line/mouse:${code}/$symbol}"
|
||||
else
|
||||
echo "$line"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $DEBUG == "1" ]]; then
|
||||
end=$(date +%s.%N)
|
||||
# fall back to awk if bc is missing
|
||||
if command -v bc >/dev/null 2>&1; then
|
||||
elapsed=$(echo "$end - $start" | bc)
|
||||
else
|
||||
elapsed=$(awk -v s="$start" -v e="$end" 'BEGIN{printf "%.6f", (e - s)}')
|
||||
fi
|
||||
echo "[DEBUG] parse_keycodes elapsed: ${elapsed}s" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# Fetch dynamic keybindings from Hyprland
|
||||
#
|
||||
# Also do some pre-processing:
|
||||
# - Remove standard Nnomarchy bin path prefix
|
||||
# - Remove uwsm prefix
|
||||
# - Map numeric modifier key mask to a textual rendition
|
||||
# - Output comma-separated values that the parser can understand
|
||||
dynamic_bindings() {
|
||||
hyprctl -j binds |
|
||||
jq -r '.[] | {modmask, key, keycode, description, dispatcher, arg} | "\(.modmask),\(.key)@\(.keycode),\(.description),\(.dispatcher),\(.arg)"' |
|
||||
sed -r \
|
||||
-e 's/null//' \
|
||||
-e 's,~/.local/share/nnomarchy/bin/,,' \
|
||||
-e 's,uwsm app -- ,,' \
|
||||
-e 's,uwsm-app -- ,,' \
|
||||
-e 's/@0//' \
|
||||
-e 's/,@/,code:/' \
|
||||
-e 's/^0,/,/' \
|
||||
-e 's/^1,/SHIFT,/' \
|
||||
-e 's/^4,/CTRL,/' \
|
||||
-e 's/^5,/SHIFT CTRL,/' \
|
||||
-e 's/^8,/ALT,/' \
|
||||
-e 's/^9,/SHIFT ALT,/' \
|
||||
-e 's/^12,/CTRL ALT,/' \
|
||||
-e 's/^13,/SHIFT CTRL ALT,/' \
|
||||
-e 's/^64,/SUPER,/' \
|
||||
-e 's/^65,/SUPER SHIFT,/' \
|
||||
-e 's/^68,/SUPER CTRL,/' \
|
||||
-e 's/^69,/SUPER SHIFT CTRL,/' \
|
||||
-e 's/^72,/SUPER ALT,/' \
|
||||
-e 's/^73,/SUPER SHIFT ALT,/' \
|
||||
-e 's/^76,/SUPER CTRL ALT,/' \
|
||||
-e 's/^77,/SUPER SHIFT CTRL ALT,/'
|
||||
}
|
||||
|
||||
# Hardcoded bindings, like the copy-url extension and such
|
||||
static_bindings() {
|
||||
echo "SHIFT ALT,L,Copy URL from Web App,extension,copy-url"
|
||||
}
|
||||
|
||||
# Parse and format keybindings
|
||||
#
|
||||
# `awk` does the heavy lifting:
|
||||
# - Set the field separator to a comma ','.
|
||||
# - Joins the key combination (e.g., "SUPER + Q").
|
||||
# - Joins the command that the key executes.
|
||||
# - Prints everything in a nicely aligned format.
|
||||
parse_bindings() {
|
||||
awk -F, '
|
||||
{
|
||||
# Combine the modifier and key (first two fields)
|
||||
key_combo = $1 " + " $2;
|
||||
|
||||
# Clean up: strip leading "+" if present, trim spaces
|
||||
gsub(/^[ \t]*\+?[ \t]*/, "", key_combo);
|
||||
gsub(/[ \t]+$/, "", key_combo);
|
||||
|
||||
# Use description, if set
|
||||
action = $3;
|
||||
|
||||
if (action == "") {
|
||||
# Reconstruct the command from the remaining fields
|
||||
for (i = 4; i <= NF; i++) {
|
||||
action = action $i (i < NF ? "," : "");
|
||||
}
|
||||
|
||||
# Clean up trailing commas, remove leading "exec, ", and trim
|
||||
sub(/,$/, "", action);
|
||||
gsub(/(^|,)[[:space:]]*exec[[:space:]]*,?/, "", action);
|
||||
gsub(/^[ \t]+|[ \t]+$/, "", action);
|
||||
gsub(/[ \t]+/, " ", key_combo); # Collapse multiple spaces to one
|
||||
|
||||
# Escape XML entities
|
||||
gsub(/&/, "\\&", action);
|
||||
gsub(/</, "\\<", action);
|
||||
gsub(/>/, "\\>", action);
|
||||
gsub(/"/, "\\"", action);
|
||||
gsub(/'"'"'/, "\\'", action);
|
||||
}
|
||||
|
||||
if (action != "") {
|
||||
printf "%-35s → %s\n", key_combo, action;
|
||||
}
|
||||
}'
|
||||
}
|
||||
|
||||
prioritize_entries() {
|
||||
awk '
|
||||
{
|
||||
line = $0
|
||||
prio = 50
|
||||
if (match(line, /Terminal/)) prio = 0
|
||||
if (match(line, /Tmux/)) prio = 1
|
||||
if (match(line, /Browser/) && !match(line, /Browser[[:space:]]*\(/) && !match(line, /SUPER SHIFT.*\+.*B.*→.*Browser/)) prio = 2
|
||||
if (match(line, /File manager/) && !match(line, /File manager \(cwd\)/)) prio = 3
|
||||
if (match(line, /Launch apps/)) prio = 4
|
||||
if (match(line, /Nnomarchy menu/)) prio = 5
|
||||
if (match(line, /System menu/)) prio = 6
|
||||
if (match(line, /Theme menu/)) prio = 7
|
||||
if (match(line, /Full screen/)) prio = 8
|
||||
if (match(line, /Full width/)) prio = 9
|
||||
if (match(line, /Close window/)) prio = 10
|
||||
if (match(line, /Close all windows/)) prio = 11
|
||||
if (match(line, /Lock system/)) prio = 12
|
||||
if (match(line, /Toggle window floating/)) prio = 13
|
||||
if (match(line, /Toggle window split/)) prio = 14
|
||||
if (match(line, /Pop window/)) prio = 15
|
||||
if (match(line, /Universal/)) prio = 16
|
||||
if (match(line, /Clipboard/)) prio = 17
|
||||
if (match(line, /Audio controls/)) prio = 18
|
||||
if (match(line, /Bluetooth controls/)) prio = 19
|
||||
if (match(line, /Wifi controls/)) prio = 20
|
||||
if (match(line, /Emoji picker/)) prio = 21
|
||||
if (match(line, /Color picker/)) prio = 22
|
||||
if (match(line, /Screenshot/)) prio = 23
|
||||
if (match(line, /Screenrecording/)) prio = 24
|
||||
if (match(line, /SUPER SHIFT.*\+.*B.*→.*Browser/)) prio = 25
|
||||
if (match(line, /File manager \(cwd\)/)) prio = 26
|
||||
if (match(line, /(Switch|Next|Former|Previous).*workspace/)) prio = 27
|
||||
if (match(line, /Move window to workspace/)) prio = 28
|
||||
if (match(line, /Move window silently to workspace/)) prio = 29
|
||||
if (match(line, /Swap window/)) prio = 30
|
||||
if (match(line, /Move window focus/)) prio = 31
|
||||
if (match(line, /Move window$/)) prio = 32
|
||||
if (match(line, /Resize window/)) prio = 33
|
||||
if (match(line, /Expand window/)) prio = 34
|
||||
if (match(line, /Shrink window/)) prio = 35
|
||||
if (match(line, /scratchpad/)) prio = 36
|
||||
if (match(line, /notification/)) prio = 37
|
||||
if (match(line, /Toggle window transparency/)) prio = 38
|
||||
if (match(line, /Toggle workspace gaps/)) prio = 39
|
||||
if (match(line, /Toggle nightlight/)) prio = 40
|
||||
if (match(line, /Toggle locking/)) prio = 41
|
||||
if (match(line, /group/)) prio = 94
|
||||
if (match(line, /Scroll active workspace/)) prio = 95
|
||||
if (match(line, /Cycle to/)) prio = 96
|
||||
if (match(line, /Reveal active/)) prio = 97
|
||||
if (match(line, /Apple Display/)) prio = 98
|
||||
if (match(line, /XF86/)) prio = 99
|
||||
|
||||
# print "priority<TAB>line"
|
||||
printf "%d\t%s\n", prio, line
|
||||
}' |
|
||||
sort -k1,1n -k2,2 |
|
||||
cut -f2-
|
||||
}
|
||||
|
||||
output_keybindings() {
|
||||
build_keymap_cache
|
||||
|
||||
{
|
||||
dynamic_bindings
|
||||
static_bindings
|
||||
} |
|
||||
sort -u |
|
||||
parse_keycodes |
|
||||
parse_bindings |
|
||||
prioritize_entries
|
||||
}
|
||||
|
||||
if [[ $1 == "--print" || $1 == "-p" ]]; then
|
||||
output_keybindings
|
||||
else
|
||||
monitor_height=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .height')
|
||||
menu_height=$((monitor_height * 40 / 100))
|
||||
|
||||
output_keybindings |
|
||||
walker --dmenu -p 'Keybindings' --width 800 --height "$menu_height"
|
||||
fi
|
||||
15
bin/utils/nomarchy-notification-dismiss
Executable file
15
bin/utils/nomarchy-notification-dismiss
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Dismiss a mako notification on the basis of its summary. Used by the first-run notifications to dismiss them after clicking for action.
|
||||
|
||||
if (($# == 0)); then
|
||||
echo "Usage: nnomarchy-notification-dismiss <summary>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Find the first notification whose 'summary' matches the regex in $1
|
||||
notification_id=$(makoctl list | grep -F "$1" | head -n1 | sed -E 's/^Notification ([0-9]+):.*/\1/')
|
||||
|
||||
if [[ -n $notification_id ]]; then
|
||||
makoctl dismiss -n $notification_id
|
||||
fi
|
||||
24
bin/utils/nomarchy-npx-install
Executable file
24
bin/utils/nomarchy-npx-install
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install an npx wrapper for a given npm package.
|
||||
# Usage: nnomarchy-npx-install <package> [command-name]
|
||||
#
|
||||
# If command-name is omitted, it defaults to the package name.
|
||||
# Example: nnomarchy-npx-install opencode-ai opencode
|
||||
|
||||
if [[ -z $1 ]]; then
|
||||
echo "Usage: nnomarchy-npx-install <package> [command-name]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
package=$1
|
||||
command=${2:-$1}
|
||||
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
|
||||
cat > "$HOME/.local/bin/$command" <<EOF
|
||||
#!/bin/bash
|
||||
exec npx --yes $package "\$@"
|
||||
EOF
|
||||
|
||||
chmod +x "$HOME/.local/bin/$command"
|
||||
80
bin/utils/nomarchy-on-boot
Executable file
80
bin/utils/nomarchy-on-boot
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Nnomarchy on-boot initialization script.
|
||||
# Automatically detects the hardware, applies necessary runtime tweaks,
|
||||
# and sets the correct screen resolution/scaling.
|
||||
|
||||
# 1. Automatically configure optimal screen resolution and scaling
|
||||
nnomarchy-hyprland-monitor-scaling-cycle >/dev/null 2>&1
|
||||
|
||||
# 2. Hardware-specific runtime tweaks
|
||||
if nnomarchy-hw-match "Laptop 16"; then
|
||||
# Framework 16 specific tweaks
|
||||
nnomarchy-theme-set-keyboard-f16 >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if nnomarchy-hw-asus-rog; then
|
||||
# Asus ROG specific tweaks
|
||||
nnomarchy-theme-set-keyboard-asus-rog >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# 3. Declarative hardware configuration check (nixos-hardware)
|
||||
# This part ensures that if we are on an installed system, the correct
|
||||
# nixos-hardware module is selected in the configuration.
|
||||
# Skip this in the Live ISO environment
|
||||
if [[ $USER == "nixos" ]] || [[ -f /etc/nixos/hosts/live-iso.nix ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
HW_FILE="/etc/nixos/hardware-selection.nix"
|
||||
if [ -w "$HW_FILE" ]; then
|
||||
PRODUCT_NAME=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "Unknown")
|
||||
BOARD_NAME=$(cat /sys/class/dmi/id/board_name 2>/dev/null || echo "Unknown")
|
||||
CPU_VENDOR=$(lscpu | grep "Vendor ID" | awk '{print $3}')
|
||||
|
||||
NEW_HW_MODULES=""
|
||||
|
||||
if [[ "$CPU_VENDOR" == "AuthenticAMD" ]]; then
|
||||
NEW_HW_MODULES="inputs.nixos-hardware.nixosModules.common-cpu-amd"
|
||||
elif [[ "$CPU_VENDOR" == "GenuineIntel" ]]; then
|
||||
NEW_HW_MODULES="inputs.nixos-hardware.nixosModules.common-cpu-intel"
|
||||
fi
|
||||
|
||||
# Auto-detect specific known models for nixos-hardware
|
||||
if echo "$PRODUCT_NAME" | grep -qi "XPS 15 9500"; then
|
||||
NEW_HW_MODULES="$NEW_HW_MODULES\n inputs.nixos-hardware.nixosModules.dell-xps-15-9500"
|
||||
elif echo "$PRODUCT_NAME" | grep -qi "XPS 13"; then
|
||||
NEW_HW_MODULES="$NEW_HW_MODULES\n inputs.nixos-hardware.nixosModules.dell-xps-13-9300" # fallback example
|
||||
elif echo "$PRODUCT_NAME" | grep -qi "Framework Laptop 16"; then
|
||||
NEW_HW_MODULES="$NEW_HW_MODULES\n inputs.nixos-hardware.nixosModules.framework-16-7040-amd"
|
||||
elif echo "$PRODUCT_NAME" | grep -qi "Framework Laptop 13"; then
|
||||
NEW_HW_MODULES="$NEW_HW_MODULES\n inputs.nixos-hardware.nixosModules.framework-13-7040-amd"
|
||||
elif echo "$PRODUCT_NAME" | grep -qi "Surface"; then
|
||||
NEW_HW_MODULES="$NEW_HW_MODULES\n inputs.nixos-hardware.nixosModules.microsoft-surface-pro-8" # fallback example
|
||||
elif echo "$PRODUCT_NAME" | grep -qi "Zephyrus G14"; then
|
||||
NEW_HW_MODULES="$NEW_HW_MODULES\n inputs.nixos-hardware.nixosModules.asus-zephyrus-g14"
|
||||
elif echo "$PRODUCT_NAME" | grep -qi "ThinkPad X1 Carbon"; then
|
||||
NEW_HW_MODULES="$NEW_HW_MODULES\n inputs.nixos-hardware.nixosModules.lenovo-thinkpad-x1-carbon-gen9"
|
||||
fi
|
||||
|
||||
# Check if the current HW file differs from our detection
|
||||
if [ -n "$NEW_HW_MODULES" ] && ! grep -q "common-cpu" "$HW_FILE"; then
|
||||
# This is a basic detection. We overwrite it if it's completely empty or missing common-cpu.
|
||||
# It's better to let the user know, or auto-apply. We'll auto-apply for a smooth experience.
|
||||
cat <<EOF > "$HW_FILE.tmp"
|
||||
{ inputs, ... }:
|
||||
{
|
||||
imports = [
|
||||
$NEW_HW_MODULES
|
||||
];
|
||||
}
|
||||
EOF
|
||||
if ! cmp -s "$HW_FILE" "$HW_FILE.tmp"; then
|
||||
mv "$HW_FILE.tmp" "$HW_FILE"
|
||||
# We notify the user instead of running sys-update silently, as it requires root and time.
|
||||
notify-send -u normal "Hardware Auto-Detection" "New hardware profile detected. Please run 'sys-update' when ready."
|
||||
else
|
||||
rm "$HW_FILE.tmp"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
5
bin/utils/nomarchy-refresh-fastfetch
Executable file
5
bin/utils/nomarchy-refresh-fastfetch
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Overwrite the user config for fastfetch with the Nnomarchy default.
|
||||
|
||||
nnomarchy-refresh-config fastfetch/config.jsonc
|
||||
34
bin/utils/nomarchy-snapshot
Executable file
34
bin/utils/nomarchy-snapshot
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
COMMAND="$1"
|
||||
NOMARCHY_PATH=${NOMARCHY_PATH:-$HOME/.local/share/nnomarchy}
|
||||
|
||||
if [[ -z $COMMAND ]]; then
|
||||
echo "Usage: nnomarchy-snapshot <create|restore>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v snapper &>/dev/null; then
|
||||
exit 127 # nnomarchy-update can use this to just ignore if snapper is not available
|
||||
fi
|
||||
|
||||
case "$COMMAND" in
|
||||
create)
|
||||
DESC="$(nnomarchy-version)"
|
||||
|
||||
echo -e "\e[32mCreate system snapshot\e[0m"
|
||||
|
||||
# Get existing snapper config names from CSV output
|
||||
mapfile -t CONFIGS < <(sudo snapper --csvout list-configs | awk -F, 'NR>1 {print $1}')
|
||||
|
||||
for config in "${CONFIGS[@]}"; do
|
||||
sudo snapper -c "$config" create -c number -d "$DESC"
|
||||
done
|
||||
echo
|
||||
;;
|
||||
restore)
|
||||
sudo limine-snapper-restore
|
||||
;;
|
||||
esac
|
||||
28
bin/utils/nomarchy-state
Executable file
28
bin/utils/nomarchy-state
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Manage persistent runtime state files for Nnomarchy indicators.
|
||||
# Usage: nnomarchy-state <set|clear> <state-name-or-pattern>
|
||||
# Used to track whether things like reboot, restart, etc are required.
|
||||
# DO NOT use this for configuration toggles (suspend, screensaver, etc).
|
||||
# Use declarative Nnomarchy NixOS home-manager options for those instead.
|
||||
|
||||
STATE_DIR="$HOME/.local/state/nnomarchy"
|
||||
mkdir -p "$STATE_DIR"
|
||||
|
||||
COMMAND="$1"
|
||||
STATE_NAME="$2"
|
||||
|
||||
if [[ -z $COMMAND ]]; then
|
||||
echo "Usage: nnomarchy-state <set|clear> <state-name-or-pattern>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $STATE_NAME ]]; then
|
||||
echo "Usage: nnomarchy-state $COMMAND <state-name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$COMMAND" in
|
||||
set) touch "$STATE_DIR/$STATE_NAME" ;;
|
||||
clear) find "$STATE_DIR" -maxdepth 1 -type f -name "$STATE_NAME" -delete ;;
|
||||
esac
|
||||
92
bin/utils/nomarchy-sync
Executable file
92
bin/utils/nomarchy-sync
Executable file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# nnomarchy-sync: Automate backing up and restoring Nnomarchy declarative configurations and dynamic state.
|
||||
|
||||
set -e
|
||||
|
||||
if [[ -z $1 ]]; then
|
||||
echo "Usage: nnomarchy-sync <push|pull> [repo-url]"
|
||||
echo " push: Backup current state to the configured repository."
|
||||
echo " pull: Restore state from the configured repository and apply updates."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COMMAND=$1
|
||||
REPO_URL=$2
|
||||
|
||||
STATE_DIR="$HOME/.config/home-manager"
|
||||
CONFIG_DIR="/etc/nixos"
|
||||
|
||||
# Identify the target repo directory (we use a local dot-folder to stage things)
|
||||
SYNC_DIR="$HOME/.local/share/nnomarchy-sync"
|
||||
|
||||
mkdir -p "$SYNC_DIR"
|
||||
cd "$SYNC_DIR"
|
||||
|
||||
if [ ! -d ".git" ]; then
|
||||
if [[ -z $REPO_URL ]]; then
|
||||
echo "Error: No Git repository configured. Please provide a repo-url for the first run:"
|
||||
echo "Example: nnomarchy-sync push git@github.com:username/nnomarchy-backup.git"
|
||||
exit 1
|
||||
fi
|
||||
git init
|
||||
git remote add origin "$REPO_URL"
|
||||
# Basic configuration for automated commits
|
||||
git config user.name "Nnomarchy Sync"
|
||||
git config user.email "sync@nnomarchy.local"
|
||||
fi
|
||||
|
||||
if [[ "$COMMAND" == "push" ]]; then
|
||||
echo "Synchronizing local configuration and state to backup repository..."
|
||||
|
||||
# 1. Copy user flakes and nix files
|
||||
mkdir -p "$SYNC_DIR/nixos"
|
||||
cp -r "$CONFIG_DIR/flake.nix" "$CONFIG_DIR/system.nix" "$CONFIG_DIR/home.nix" "$SYNC_DIR/nixos/" 2>/dev/null || true
|
||||
|
||||
# 2. Copy state files
|
||||
mkdir -p "$SYNC_DIR/state"
|
||||
cp -r "$STATE_DIR"/*.nix "$STATE_DIR"/*.json "$SYNC_DIR/state/" 2>/dev/null || true
|
||||
|
||||
# 3. Commit and Push
|
||||
git add .
|
||||
if git diff-index --quiet HEAD --; then
|
||||
echo "No changes to backup."
|
||||
else
|
||||
git commit -m "Auto-sync backup from $(date +'%Y-%m-%d %H:%M:%S')"
|
||||
# We use a try-catch pattern for push because upstream might not exist yet
|
||||
echo "Pushing to remote..."
|
||||
git push -u origin master || git push -u origin main
|
||||
echo "Backup successful."
|
||||
fi
|
||||
|
||||
elif [[ "$COMMAND" == "pull" ]]; then
|
||||
echo "Pulling backup from remote repository..."
|
||||
git fetch
|
||||
# Hard reset to exactly match remote
|
||||
git reset --hard origin/master 2>/dev/null || git reset --hard origin/main
|
||||
|
||||
echo "Restoring configuration and state..."
|
||||
|
||||
# 1. Restore user flakes (Requires sudo)
|
||||
if [ -d "$SYNC_DIR/nixos" ]; then
|
||||
sudo cp -r "$SYNC_DIR/nixos/"* "$CONFIG_DIR/"
|
||||
sudo chmod -R u+w "$CONFIG_DIR"
|
||||
fi
|
||||
|
||||
# 2. Restore state files
|
||||
if [ -d "$SYNC_DIR/state" ]; then
|
||||
mkdir -p "$STATE_DIR"
|
||||
cp -r "$SYNC_DIR/state/"* "$STATE_DIR/"
|
||||
fi
|
||||
|
||||
echo "Applying updates..."
|
||||
# Apply the restored settings
|
||||
sudo nixos-rebuild switch --flake "$CONFIG_DIR#default"
|
||||
home-manager switch --flake "$CONFIG_DIR#default" --impure
|
||||
|
||||
echo "Restore successful."
|
||||
|
||||
else
|
||||
echo "Unknown command: $COMMAND"
|
||||
exit 1
|
||||
fi
|
||||
14
bin/utils/nomarchy-test-installer
Executable file
14
bin/utils/nomarchy-test-installer
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Build and run the Nnomarchy Installer VM for testing.
|
||||
|
||||
echo "Building Nnomarchy Installer VM..."
|
||||
nix build .#nixosConfigurations.installerVm.config.system.build.vm
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Success! Launching Installer VM..."
|
||||
./result/bin/run-nnomarchy-installer-vm
|
||||
else
|
||||
echo "Error: VM build failed."
|
||||
exit 1
|
||||
fi
|
||||
15
bin/utils/nomarchy-test-vm
Executable file
15
bin/utils/nomarchy-test-vm
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Build and run the Nnomarchy VM (installed environment) for testing.
|
||||
|
||||
echo "Building Nnomarchy VM (Installed Environment)..."
|
||||
echo "Note: To test the INSTALLER, run 'nnomarchy-test-installer' instead."
|
||||
nix build .#nixosConfigurations.vm.config.system.build.vm
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Success! Launching VM..."
|
||||
./result/bin/run-nnomarchy-vm
|
||||
else
|
||||
echo "Error: VM build failed."
|
||||
exit 1
|
||||
fi
|
||||
11
bin/utils/nomarchy-toggle-notification-silencing
Executable file
11
bin/utils/nomarchy-toggle-notification-silencing
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
makoctl mode -t do-not-disturb
|
||||
|
||||
if makoctl mode | grep -q 'do-not-disturb'; then
|
||||
notify-send -u low " Silenced notifications"
|
||||
else
|
||||
notify-send -u low " Enabled notifications"
|
||||
fi
|
||||
|
||||
pkill -RTMIN+10 waybar
|
||||
49
bin/utils/nomarchy-welcome
Executable file
49
bin/utils/nomarchy-welcome
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
FLAG_FILE="$HOME/.config/nnomarchy/.first-run-done"
|
||||
|
||||
if [ -f "$FLAG_FILE" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Ensure we have a terminal for the wizard
|
||||
if [ -z "$TERMINAL_WIZARD" ]; then
|
||||
export TERMINAL_WIZARD=1
|
||||
alacritty -e "$0"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
gum style \
|
||||
--foreground 212 --border-foreground 212 --border double \
|
||||
--align center --width 50 --margin "1 2" --padding "2 4" \
|
||||
"Nnomarchy" "The NixOS Distribution with Nomarchy Flavour"
|
||||
|
||||
echo "Welcome! Let's personalize your new system."
|
||||
echo ""
|
||||
|
||||
# 1. Select initial theme
|
||||
echo "Step 1: Choose your starting theme"
|
||||
nnomarchy-theme-selector
|
||||
|
||||
# 2. Select initial font
|
||||
echo "Step 2: Choose your preferred font"
|
||||
nnomarchy-font-selector
|
||||
|
||||
# 3. Setup Local Repo (Crucial for env-update to work)
|
||||
echo ""
|
||||
echo "Nnomarchy relies on a local git repository for declarative updates."
|
||||
if [ ! -d "/etc/nixos/.git" ]; then
|
||||
echo "Warning: /etc/nixos is not a git repository. Declarative updates might fail."
|
||||
if gum confirm "Would you like to initialize /etc/nixos as a git repo?"; then
|
||||
sudo git -C /etc/nixos init
|
||||
sudo git -C /etc/nixos add .
|
||||
sudo git -C /etc/nixos commit -m "Initial Nnomarchy System Commit"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 4. Success
|
||||
mkdir -p "$(dirname "$FLAG_FILE")"
|
||||
touch "$FLAG_FILE"
|
||||
|
||||
gum style --foreground 82 "Setup complete! Enjoy your Nnomarchy experience."
|
||||
sleep 3
|
||||
Reference in New Issue
Block a user