Fixed some shellcheck errors. Added the ability to save answers to i38 questions thereby making future configuration regeneration much easier.

This commit is contained in:
Storm Dragon
2025-12-06 20:09:53 -05:00
parent fc3a2abb51
commit e1d6b71121
2 changed files with 271 additions and 118 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
I38_preferences.conf
**/__pycache__/ **/__pycache__/
*.pyc *.pyc
*.pyo *.pyo

388
i38.sh
View File

@@ -15,6 +15,7 @@
usingSway=1 # Not by default. usingSway=1 # Not by default.
i3Path="${XDG_CONFIG_HOME:-$HOME/.config}/i3" i3Path="${XDG_CONFIG_HOME:-$HOME/.config}/i3"
i3msg="i3-msg" i3msg="i3-msg"
configFile="${PWD}/I38_preferences.conf"
# Dialog accessibility # Dialog accessibility
export DIALOGOPTS='--no-lines --visit-items' export DIALOGOPTS='--no-lines --visit-items'
@@ -28,7 +29,7 @@ done
if ! python3 -c 'import i3ipc' &> /dev/null ; then if ! python3 -c 'import i3ipc' &> /dev/null ; then
missing+=("python-i3ipc") missing+=("python-i3ipc")
fi fi
if [[ -n "${missing}" ]]; then if [[ ${#missing[@]} -gt 0 ]]; then
echo "Please install the following packages and run this script again:" echo "Please install the following packages and run this script again:"
echo "${missing[*]}" echo "${missing[*]}"
exit 1 exit 1
@@ -175,7 +176,7 @@ yesno() {
# Returns: Yes 0 or No 1 # Returns: Yes 0 or No 1
# Args: Question to user. # Args: Question to user.
dialog --clear --title "I38" --yesno "$*" -1 -1 --stdout dialog --clear --title "I38" --yesno "$*" -1 -1 --stdout
echo $? return $?
} }
# Custom application keybinding functions # Custom application keybinding functions
@@ -333,7 +334,80 @@ addCustomApplication() {
break break
done done
done done
} }
load_config() {
# Load existing configuration if available
if [[ -f "$configFile" ]]; then
# shellcheck source=/dev/null
source "$configFile"
# Convert kbd string back to array if present
if [[ -n "$kbd" ]]; then
IFS=' ' read -ra kbd <<< "$kbd"
fi
# Reconstruct customApps array from numbered entries
customApps=()
local i=0
local varName
while : ; do
varName="customApp_$i"
if [[ -n "${!varName}" ]]; then
customApps+=("${!varName}")
((i++))
else
break
fi
done
return 0
fi
return 1
}
save_config() {
if yesno "Save this configuration for future runs?"; then
cat > "$configFile" << EOF
# I38 Configuration Preferences
# Generated by i38.sh on $(date)
# Edit this file to change saved preferences or delete to reconfigure from scratch
# Keyboard configuration
escapeKey="$escapeKey"
mod="$mod"
# Keyboard layouts (space-separated)
kbd="${kbd[*]}"
# Volume settings
volumeJump="$volumeJump"
# Application paths
screenReader="$screenReader"
emailClient="$emailClient"
webBrowser="$webBrowser"
textEditor="$textEditor"
fileBrowser="$fileBrowser"
ircClient="$ircClient"
# Boolean settings (0=yes, 1=no)
udiskie="$udiskie"
dex="$dex"
batteryAlert="${batteryAlert:-1}"
brlapi="$brlapi"
sounds="$sounds"
# Custom applications
EOF
# Save custom apps with numbered keys
for i in "${!customApps[@]}"; do
echo "customApp_$i=\"${customApps[$i]}\"" >> "$configFile"
done
dialog --title "I38" --msgbox "Configuration saved to $configFile\n\nYou can edit this file manually or delete it to reconfigure from scratch." 0 0
fi
}
help() { help() {
echo "${0##*/}" echo "${0##*/}"
@@ -344,6 +418,9 @@ help() {
for i in "${!command[@]}" ; do for i in "${!command[@]}" ; do
echo "-${i/:/ <parameter>}: ${command[${i}]}" echo "-${i/:/ <parameter>}: ${command[${i}]}"
done | sort done | sort
echo ""
echo "Configuration preferences can be saved to I38_preferences.conf in the current directory."
echo "Delete this file to reconfigure from scratch."
exit 0 exit 0
} }
@@ -378,8 +455,7 @@ chmod +x ~/.xinitrc
write_xprofile() { write_xprofile() {
if [[ -f "$HOME/.xprofile" ]]; then if [[ -f "$HOME/.xprofile" ]]; then
continue="$(yesno "Would you like to add accessibility variables to your $HOME/.xprofile? Without these, accessibility will be limited or may not work at all. Do you want to continue?")" if ! yesno "Would you like to add accessibility variables to your $HOME/.xprofile? Without these, accessibility will be limited or may not work at all. Do you want to continue?"; then
if [ "$continue" = "no" ]; then
exit 0 exit 0
fi fi
fi fi
@@ -467,6 +543,13 @@ while getopts "${args}" i ; do
esac esac
done done
# Load saved configuration if available
configLoaded=0
if load_config; then
configLoaded=1
dialog --title "I38" --msgbox "Loaded saved preferences from $configFile\n\nMissing or invalid values will be prompted." 0 0
fi
# Mod1 alt # Mod1 alt
# Mod4 super # Mod4 super
# Mod2 and Mod3 not usually defined. # Mod2 and Mod3 not usually defined.
@@ -475,155 +558,224 @@ done
# Ratpoison mode is enabled by default # Ratpoison mode is enabled by default
export i3Mode=0 export i3Mode=0
# Prevent setting ratpoison mode key to the same as default mode key # Prevent setting ratpoison mode key to the same as default mode key
while [[ "$escapeKey" == "$mod" ]] || [[ "$escapeKey" =~ ^Super_ && "$mod" == "Mod4" ]] || [[ "$mod" == "Mod4" && "$escapeKey" =~ ^Super_ ]]; do if [[ -z "$escapeKey" ]] || [[ -z "$mod" ]]; then
escapeKey="$(menulist "Ratpoison mode key:" Control+t Control+z Control+Escape Alt+Escape Control+space "Super Left" "Super Right")" while [[ "$escapeKey" == "$mod" ]] || [[ "$escapeKey" =~ ^Super_ && "$mod" == "Mod4" ]] || [[ "$mod" == "Mod4" && "$escapeKey" =~ ^Super_ ]]; do
escapeKey="${escapeKey//Alt/Mod1}" escapeKey="$(menulist "Ratpoison mode key:" Control+t Control+z Control+Escape Alt+Escape Control+space "Super Left" "Super Right")"
escapeKey="${escapeKey//Super Left/Super_L}" escapeKey="${escapeKey//Alt/Mod1}"
escapeKey="${escapeKey//Super Right/Super_R}" escapeKey="${escapeKey//Super Left/Super_L}"
mod="$(menulist "I3 mod key, for top level bindings:" Alt Super)" escapeKey="${escapeKey//Super Right/Super_R}"
mod="${mod//Alt/Mod1}" mod="$(menulist "I3 mod key, for top level bindings:" Alt Super)"
mod="${mod//Super/Mod4}" mod="${mod//Alt/Mod1}"
if [ "$escapeKey" == "$mod" ]; then mod="${mod//Super/Mod4}"
dialog --title "I38" --msgbox "Ratpoison and mod key cannot be the same key." -1 -1 if [ "$escapeKey" == "$mod" ]; then
elif [[ "$escapeKey" =~ ^Super_ && "$mod" == "Mod4" ]]; then dialog --title "I38" --msgbox "Ratpoison and mod key cannot be the same key." -1 -1
dialog --title "I38" --msgbox "Ratpoison mode key cannot be a Super key when mod key is Super." -1 -1 elif [[ "$escapeKey" =~ ^Super_ && "$mod" == "Mod4" ]]; then
fi dialog --title "I38" --msgbox "Ratpoison mode key cannot be a Super key when mod key is Super." -1 -1
done fi
# Multiple keyboard layouts
if [[ $(yesno "Do you want to use multiple keyboard layouts?") -eq 0 ]]; then
unset kbd
while : ; do
kbd+=("$(keyboard_menu)") || break
done done
fi fi
# Multiple keyboard layouts
if [[ ${#kbd[@]} -eq 0 ]]; then
if yesno "Do you want to use multiple keyboard layouts?"; then
unset kbd
while : ; do
kbd+=("$(keyboard_menu)") || break
done
fi
fi
# Volume jump # Volume jump
volumeJump=$(rangebox "How much should pressing the volume keys change the volume?" 1 15 5) if [[ -z "$volumeJump" ]]; then
volumeJump=$(rangebox "How much should pressing the volume keys change the volume?" 1 15 5)
fi
# Screen Reader # Screen Reader
unset programList if [[ -z "$screenReader" ]] || ! command -v "$screenReader" &> /dev/null; then
for i in cthulhu orca ; do unset programList
if command -v ${i/#-/} &> /dev/null ; then for i in cthulhu orca ; do
if [ -n "$programList" ]; then if command -v ${i/#-/} &> /dev/null ; then
programList="$programList $i" if [ -n "$programList" ]; then
else programList="$programList $i"
programList="$i" else
programList="$i"
fi
fi fi
done
if [ "$programList" != "${programList// /}" ]; then
screenReader="$(menulist ":Screen Reader" $programList)"
else
screenReader="${programList/#-/}"
fi fi
done export screenReader="$(command -v $screenReader)"
if [ "$programList" != "${programList// /}" ]; then
screenReader="$(menulist ":Screen Reader" $programList)"
else else
screenReader="${programList/#-/}" # Validate and export existing preference
export screenReader
fi fi
export screenReader="$(command -v $screenReader)"
# Email client # Email client
unset programList if [[ -z "$emailClient" ]] || ! command -v "$emailClient" &> /dev/null; then
for i in betterbird evolution thunderbird ; do unset programList
if command -v ${i/#-/} &> /dev/null ; then for i in betterbird evolution thunderbird ; do
if [ -n "$programList" ]; then if command -v ${i/#-/} &> /dev/null ; then
programList="$programList $i" if [ -n "$programList" ]; then
else programList="$programList $i"
programList="$i" else
programList="$i"
fi
fi fi
done
if [ "$programList" != "${programList// /}" ]; then
emailClient="$(menulist "Email client:" $programList)"
else
emailClient="${programList/#-/}"
fi fi
done export emailClient="$(command -v $emailClient)"
if [ "$programList" != "${programList// /}" ]; then
emailClient="$(menulist "Email client:" $programList)"
else else
emailClient="${programList/#-/}" # Validate and export existing preference
export emailClient
fi fi
export emailClient="$(command -v $emailClient)"
# Web browser # Web browser
unset programList if [[ -z "$webBrowser" ]] || ! command -v "$webBrowser" &> /dev/null; then
for i in brave chromium epiphany firefox google-chrome-stable google-chrome-unstable microsoft-edge-stable microsoft-edge-beta microsoft-edge-dev midori seamonkey vivaldi ; do unset programList
if command -v ${i/#-/} &> /dev/null ; then for i in brave chromium epiphany firefox google-chrome-stable google-chrome-unstable microsoft-edge-stable microsoft-edge-beta microsoft-edge-dev midori seamonkey vivaldi ; do
if [ -n "$programList" ]; then if command -v ${i/#-/} &> /dev/null ; then
programList="$programList $i" if [ -n "$programList" ]; then
else programList="$programList $i"
programList="$i" else
programList="$i"
fi
fi fi
done
if [ "$programList" != "${programList// /}" ]; then
webBrowser="$(menulist "Web browser:" $programList)"
else
webBrowser="${programList/#-/}"
fi fi
done export webBrowser="$(command -v $webBrowser)"
if [ "$programList" != "${programList// /}" ]; then
webBrowser="$(menulist "Web browser:" $programList)"
else else
webBrowser="${programList/#-/}" # Validate and export existing preference
export webBrowser
fi fi
export webBrowser="$(command -v $webBrowser)"
# Text editor # Text editor
unset programList if [[ -z "$textEditor" ]] || ! command -v "$textEditor" &> /dev/null; then
for i in emacs geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma ; do unset programList
if hash ${i/#-/} &> /dev/null ; then for i in emacs geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma ; do
if [ -n "$programList" ]; then if hash ${i/#-/} &> /dev/null ; then
programList="$programList $i" if [ -n "$programList" ]; then
programList="$programList $i"
else
programList="$i"
fi
fi
done
if [ "$programList" != "${programList// /}" ]; then
textEditor="$(menulist "Text editor:" $programList)"
else
textEditor="${programList/#-/}"
fi
export textEditor="$(command -v $textEditor)"
else else
programList="$i" # Validate and export existing preference
export textEditor
fi fi
fi
done
if [ "$programList" != "${programList// /}" ]; then
textEditor="$(menulist "Text editor:" $programList)"
else
textEditor="${programList/#-/}"
fi
export textEditor="$(command -v $textEditor)"
# File browser # File browser
# Configure file browser if [[ -z "$fileBrowser" ]] || ! command -v "$fileBrowser" &> /dev/null; then
unset programList unset programList
for i in caja nemo nautilus pcmanfm pcmanfm-qt thunar ; do for i in caja nemo nautilus pcmanfm pcmanfm-qt thunar ; do
if hash ${i/#-/} &> /dev/null ; then if hash ${i/#-/} &> /dev/null ; then
if [ -n "$programList" ]; then if [ -n "$programList" ]; then
programList="$programList $i" programList="$programList $i"
else else
programList="$i" programList="$i"
fi
fi fi
done
if [ "$programList" != "${programList// /}" ]; then
fileBrowser="$(menulist "File browser:" $programList)"
else
fileBrowser="${programList/#-/}"
fi fi
done export fileBrowser="$(command -v $fileBrowser)"
if [ "$programList" != "${programList// /}" ]; then
fileBrowser="$(menulist "File browser:" $programList)"
else else
fileBrowser="${programList/#-/}" # Validate and export existing preference
export fileBrowser
fi fi
export fileBrowser="$(command -v $fileBrowser)"
# IRC client # IRC client
unset programList if [[ -z "$ircClient" ]] || ! command -v "$ircClient" &> /dev/null; then
for i in albikirc Albikirc access-irc ; do unset programList
if command -v ${i/#-/} &> /dev/null ; then for i in albikirc Albikirc access-irc ; do
if [ -n "$programList" ]; then if command -v ${i/#-/} &> /dev/null ; then
programList="$programList $i" if [ -n "$programList" ]; then
programList="$programList $i"
else
programList="$i"
fi
fi
done
if [ "$programList" != "${programList// /}" ]; then
ircClient="$(menulist "IRC client:" $programList)"
else
ircClient="${programList/#-/}"
fi
export ircClient="$(command -v $ircClient)"
else
# Validate and export existing preference
export ircClient
fi
# Auto mount removable media
if [[ -z "$udiskie" ]]; then
udiskie=1
if command -v udiskie &> /dev/null ; then
if yesno "Would you like removable drives to automatically mount when plugged in?"; then
export udiskie=0
else else
programList="$i" export udiskie=1
fi fi
fi fi
done
if [ "$programList" != "${programList// /}" ]; then
ircClient="$(menulist "IRC client:" $programList)"
else
ircClient="${programList/#-/}"
fi
export ircClient="$(command -v $ircClient)"
# Auto mount removable media
udiskie=1
if command -v udiskie &> /dev/null ; then
export udiskie=$(yesno "Would you like removable drives to automatically mount when plugged in?")
fi fi
# Auto start with dex # Auto start with dex
dex=1 if [[ -z "$dex" ]]; then
if command -v dex &> /dev/null ; then dex=1
export dex=$(yesno "Would you like to autostart applications with dex?") if command -v dex &> /dev/null ; then
if yesno "Would you like to autostart applications with dex?"; then
export dex=0
else
export dex=1
fi
fi
fi fi
if [[ $dex -eq 0 ]]; then if [[ $dex -eq 0 ]]; then
dex -t "${XDG_CONFIG_HOME:-${HOME}/.config}/autostart" -c $(command -v $screenReader) dex -t "${XDG_CONFIG_HOME:-${HOME}/.config}/autostart" -c $(command -v $screenReader)
fi fi
if command -v acpi &> /dev/null ; then if [[ -z "$batteryAlert" ]]; then
batteryAlert=1 if command -v acpi &> /dev/null ; then
batteryAlert=$(yesno "Do you want low battery notifications?") if yesno "Do you want low battery notifications?"; then
batteryAlert=0
else
batteryAlert=1
fi
fi
fi
if [[ -z "$brlapi" ]]; then
if yesno "Do you want to use a braille display with ${screenReader##*/}?"; then
brlapi=0
else
brlapi=1
fi
fi
if [[ -z "$sounds" ]]; then
if yesno "Do you want window event sounds?"; then
sounds=0
else
sounds=1
fi
fi fi
brlapi=1
brlapi=$(yesno "Do you want to use a braille display with ${screenReader##*/}?")
sounds=1
sounds=$(yesno "Do you want window event sounds?")
# Custom applications for ratpoison mode # Custom applications for ratpoison mode
addCustomApplication if [[ ${#customApps[@]} -eq 0 ]]; then
addCustomApplication
fi
# Save configuration if requested (only on first run)
if [[ $configLoaded -eq 0 ]]; then
save_config
fi
if [[ -d "${i3Path}" ]]; then if [[ -d "${i3Path}" ]]; then
yesno "This will replace your existing configuration at ${i3Path}. Do you want to continue?" || exit 0 yesno "This will replace your existing configuration at ${i3Path}. Do you want to continue?" || exit 0
@@ -823,7 +975,7 @@ echo "bindsym ${mod}+Shift+F5 exec spd-say -C" >> ${i3Path}/config
# Multiple keyboard layouts if requested. # Multiple keyboard layouts if requested.
if [[ ${#kbd[@]} -gt 1 ]]; then if [[ ${#kbd[@]} -gt 1 ]]; then
echo "bindsym Mod4+space exec ${i3Path}/scripts/keyboard.sh cycle ${kbd[@]}" >> ${i3Path}/config echo "bindsym Mod4+space exec ${i3Path}/scripts/keyboard.sh cycle ${kbd[*]}" >> ${i3Path}/config
fi fi
# Create panel mode # Create panel mode
@@ -887,7 +1039,7 @@ mode "ratpoison" {
# Ratpoison mode keybindings help bound to F1 # Ratpoison mode keybindings help bound to F1
bindsym F1 exec ${i3Path}/scripts/i38-help-rp.sh, mode "default" bindsym F1 exec ${i3Path}/scripts/i38-help-rp.sh, mode "default"
# Terminal emulator bound to c # Terminal emulator bound to c
bindsym c exec $sensibleTerminal, mode "default" bindsym c exec ${i3Path}/scripts/i3-sensible-terminal.sh, mode "default"
# Text editor bound to e # Text editor bound to e
bindsym e exec $textEditor, mode "default" bindsym e exec $textEditor, mode "default"
$(if [[ ${#fileBrowser} -gt 3 ]]; then $(if [[ ${#fileBrowser} -gt 3 ]]; then