forked from Shinonome/alt-illogical-impulse
Initial clean flake structure - Phase 3 complete
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
# Quickshell service integration with staging system
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.dots-hyprland.quickshell;
|
||||
mainCfg = config.programs.dots-hyprland;
|
||||
|
||||
# Our working quickshell build with QtPositioning support
|
||||
workingQuickshell =
|
||||
let
|
||||
quickshellSrc = pkgs.fetchFromGitHub {
|
||||
owner = "quickshell-mirror";
|
||||
repo = "quickshell";
|
||||
rev = "a5431dd02dc23d9ef1680e67777fed00fe5f7cda";
|
||||
hash = "sha256-vqkSDvh7hWhPvNjMjEDV4KbSCv2jyl2Arh73ZXe274k=";
|
||||
};
|
||||
quickshellBase = pkgs.callPackage (quickshellSrc + "/default.nix") {
|
||||
debug = true;
|
||||
gitRev = "a5431dd02dc23d9ef1680e67777fed00fe5f7cda";
|
||||
};
|
||||
in
|
||||
quickshellBase.withModules (with pkgs.qt6; [ qtpositioning qtmultimedia ]);
|
||||
|
||||
# Service startup script that handles initial setup
|
||||
quickshellStartup = pkgs.writeShellScript "quickshell-startup" ''
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Colors for logging
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() {
|
||||
echo -e "''${GREEN}[quickshell-service]''${NC} $1" >&2
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "''${YELLOW}[quickshell-service]''${NC} WARNING: $1" >&2
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "''${RED}[quickshell-service]''${NC} ERROR: $1" >&2
|
||||
}
|
||||
|
||||
STAGING_DIR="$HOME/${mainCfg.writable-mode.stagingDir}"
|
||||
CONFIG_DIR="$HOME/.config"
|
||||
SETUP_SCRIPT="$HOME/${mainCfg.writable-mode.setupScript}"
|
||||
SETUP_MARKER="$HOME/.cache/dots-hyprland/setup-complete"
|
||||
|
||||
# Ensure cache directory exists
|
||||
mkdir -p "$(dirname "$SETUP_MARKER")"
|
||||
|
||||
# Check if initial setup has been run
|
||||
if [[ ! -f "$SETUP_MARKER" ]]; then
|
||||
log "🚀 First run detected - running initial setup"
|
||||
|
||||
# Check if staging directory exists
|
||||
if [[ ! -d "$STAGING_DIR" ]]; then
|
||||
error "Staging directory not found: $STAGING_DIR"
|
||||
error "Please run 'home-manager switch' first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if setup script exists
|
||||
if [[ ! -x "$SETUP_SCRIPT" ]]; then
|
||||
error "Setup script not found or not executable: $SETUP_SCRIPT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "📋 Running initial setup script..."
|
||||
if "$SETUP_SCRIPT"; then
|
||||
# Mark setup as complete
|
||||
echo "$(date)" > "$SETUP_MARKER"
|
||||
log "✅ Initial setup completed successfully"
|
||||
else
|
||||
error "❌ Initial setup failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log "✅ Setup already completed ($(cat "$SETUP_MARKER"))"
|
||||
fi
|
||||
|
||||
# Verify quickshell configuration exists
|
||||
if [[ ! -d "$CONFIG_DIR/quickshell" ]]; then
|
||||
error "Quickshell configuration not found at $CONFIG_DIR/quickshell"
|
||||
error "Initial setup may have failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set up environment variables
|
||||
export ILLOGICAL_IMPULSE_VIRTUAL_ENV="$HOME/.local/state/quickshell/.venv"
|
||||
export QT_SCALE_FACTOR="${toString cfg.scaling}"
|
||||
export QT_QUICK_CONTROLS_STYLE="Basic"
|
||||
export QT_QUICK_FLICKABLE_WHEEL_DECELERATION="10000"
|
||||
|
||||
# Ensure PATH includes user applications - CRITICAL for app launching
|
||||
export PATH="${config.home.profileDirectory}/bin:/run/wrappers/bin:${config.home.homeDirectory}/.nix-profile/bin:/etc/profiles/per-user/${config.home.username}/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:$PATH"
|
||||
export XDG_DATA_DIRS="${config.home.profileDirectory}/share:${config.home.homeDirectory}/.nix-profile/share:/etc/profiles/per-user/${config.home.username}/share:/nix/var/nix/profiles/default/share:/run/current-system/sw/share:$XDG_DATA_DIRS"
|
||||
|
||||
# Create application launcher wrapper that quickshell can use
|
||||
LAUNCHER_WRAPPER="$HOME/.cache/dots-hyprland/app-launcher"
|
||||
mkdir -p "$(dirname "$LAUNCHER_WRAPPER")"
|
||||
cat > "$LAUNCHER_WRAPPER" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Application launcher wrapper for quickshell
|
||||
# Ensures proper PATH and environment for launched applications
|
||||
|
||||
# Use the same PATH that quickshell has
|
||||
export PATH="${config.home.profileDirectory}/bin:/run/wrappers/bin:${config.home.homeDirectory}/.nix-profile/bin:/etc/profiles/per-user/${config.home.username}/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin"
|
||||
export XDG_DATA_DIRS="${config.home.profileDirectory}/share:${config.home.homeDirectory}/.nix-profile/share:/etc/profiles/per-user/${config.home.username}/share:/nix/var/nix/profiles/default/share:/run/current-system/sw/share"
|
||||
|
||||
# Launch the application
|
||||
exec "$@"
|
||||
EOF
|
||||
chmod +x "$LAUNCHER_WRAPPER"
|
||||
|
||||
# Export the launcher wrapper path for quickshell to use
|
||||
export DOTS_HYPRLAND_APP_LAUNCHER="$LAUNCHER_WRAPPER"
|
||||
|
||||
# Verify Python virtual environment
|
||||
if [[ ! -d "$ILLOGICAL_IMPULSE_VIRTUAL_ENV" ]]; then
|
||||
warn "Python virtual environment not found at $ILLOGICAL_IMPULSE_VIRTUAL_ENV"
|
||||
warn "Some features may not work correctly"
|
||||
fi
|
||||
|
||||
log "🎯 Starting quickshell with dots-hyprland configuration"
|
||||
log "📁 Config: $CONFIG_DIR/quickshell/ii/shell.qml"
|
||||
log "🐍 Python venv: $ILLOGICAL_IMPULSE_VIRTUAL_ENV"
|
||||
log "🚀 App launcher: $LAUNCHER_WRAPPER"
|
||||
|
||||
# Start quickshell
|
||||
exec ${workingQuickshell}/bin/quickshell -p "$CONFIG_DIR/quickshell/ii/shell.qml"
|
||||
'';
|
||||
|
||||
in
|
||||
{
|
||||
options.programs.dots-hyprland.quickshell = {
|
||||
enable = mkEnableOption "Quickshell service with staging integration";
|
||||
|
||||
autoStart = mkEnableOption "Auto-start with Hyprland session" // { default = true; };
|
||||
|
||||
restartOnFailure = mkEnableOption "Restart service on failure" // { default = true; };
|
||||
|
||||
scaling = mkOption {
|
||||
type = types.float;
|
||||
default = 1.0;
|
||||
description = "UI scaling factor";
|
||||
};
|
||||
|
||||
logLevel = mkOption {
|
||||
type = types.enum [ "debug" "info" "warning" "error" ];
|
||||
default = "info";
|
||||
description = "Logging level for quickshell service";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Install the working quickshell build and service management scripts
|
||||
home.packages = [ workingQuickshell ] ++ (with pkgs; [
|
||||
(writeShellScriptBin "quickshell-restart" ''
|
||||
systemctl --user restart quickshell.service
|
||||
echo "✅ Quickshell service restarted"
|
||||
'')
|
||||
|
||||
(writeShellScriptBin "quickshell-status" ''
|
||||
echo "🔍 Quickshell Service Status"
|
||||
echo "=========================="
|
||||
systemctl --user status quickshell.service --no-pager
|
||||
echo ""
|
||||
echo "📋 Recent logs:"
|
||||
journalctl --user -u quickshell.service -n 10 --no-pager
|
||||
'')
|
||||
|
||||
(writeShellScriptBin "quickshell-logs" ''
|
||||
echo "📋 Following quickshell logs (Ctrl+C to exit):"
|
||||
journalctl --user -u quickshell.service -f
|
||||
'')
|
||||
|
||||
(writeShellScriptBin "quickshell-debug" ''
|
||||
echo "🐛 Starting quickshell in debug mode..."
|
||||
systemctl --user stop quickshell.service
|
||||
QT_LOGGING_RULES="quickshell.*=true" ${quickshellStartup}
|
||||
'')
|
||||
]);
|
||||
|
||||
# Systemd user service for quickshell
|
||||
systemd.user.services.quickshell = {
|
||||
Unit = {
|
||||
Description = "Quickshell - QtQuick based desktop shell with dots-hyprland";
|
||||
Documentation = [ "https://quickshell.org" "https://end-4.github.io/dots-hyprland-wiki/" ];
|
||||
PartOf = [ "hyprland-session.target" ];
|
||||
After = [ "hyprland-session.target" "graphical-session.target" ];
|
||||
Wants = [ "hyprland-session.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = quickshellStartup;
|
||||
ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR2 $MAINPID";
|
||||
Restart = if cfg.restartOnFailure then "on-failure" else "no";
|
||||
RestartSec = 2;
|
||||
TimeoutStartSec = 30;
|
||||
TimeoutStopSec = 10;
|
||||
|
||||
# Environment variables - include full user environment
|
||||
Environment = [
|
||||
"QT_SCALE_FACTOR=${toString cfg.scaling}"
|
||||
"QT_QUICK_CONTROLS_STYLE=Basic"
|
||||
"QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000"
|
||||
"QT_LOGGING_RULES=${
|
||||
if cfg.logLevel == "debug" then "quickshell.*=true"
|
||||
else if cfg.logLevel == "warning" then "*.warning=true"
|
||||
else if cfg.logLevel == "error" then "*.critical=true"
|
||||
else "*.info=true"
|
||||
}"
|
||||
# Include user's full PATH so applications can be launched
|
||||
"PATH=${config.home.profileDirectory}/bin:/run/wrappers/bin:${config.home.homeDirectory}/.nix-profile/bin:/etc/profiles/per-user/${config.home.username}/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin"
|
||||
# Include XDG data directories for application discovery
|
||||
"XDG_DATA_DIRS=${config.home.profileDirectory}/share:${config.home.homeDirectory}/.nix-profile/share:/etc/profiles/per-user/${config.home.username}/share:/nix/var/nix/profiles/default/share:/run/current-system/sw/share"
|
||||
# Application launcher wrapper path
|
||||
"DOTS_HYPRLAND_APP_LAUNCHER=%h/.cache/dots-hyprland/app-launcher"
|
||||
];
|
||||
|
||||
# Working directory
|
||||
WorkingDirectory = "%h";
|
||||
|
||||
# Security settings
|
||||
PrivateNetwork = false;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = false; # Need access to home directory
|
||||
NoNewPrivileges = true;
|
||||
|
||||
# Resource limits
|
||||
MemoryMax = "2G";
|
||||
CPUQuota = "200%";
|
||||
};
|
||||
|
||||
Install = mkIf cfg.autoStart {
|
||||
WantedBy = [ "hyprland-session.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
# Create hyprland session target if it doesn't exist
|
||||
systemd.user.targets.hyprland-session = {
|
||||
Unit = {
|
||||
Description = "Hyprland compositor session";
|
||||
Documentation = [ "man:systemd.special(7)" ];
|
||||
BindsTo = [ "graphical-session.target" ];
|
||||
Wants = [ "graphical-session-pre.target" ];
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
# Touchegg gesture support for dots-hyprland
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.dots-hyprland.touchegg;
|
||||
mainCfg = config.programs.dots-hyprland;
|
||||
in
|
||||
{
|
||||
options.programs.dots-hyprland.touchegg = {
|
||||
enable = mkEnableOption "Touchegg gesture support";
|
||||
|
||||
config = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
<touchégg>
|
||||
<settings>
|
||||
<property name="animation_delay">150</property>
|
||||
<property name="action_execute_threshold">80</property>
|
||||
<property name="color">auto</property>
|
||||
<property name="borderColor">auto</property>
|
||||
</settings>
|
||||
<application name="All">
|
||||
<!-- 3-finger pinch in: Close window -->
|
||||
<gesture type="PINCH" fingers="3" direction="IN">
|
||||
<action type="CLOSE_WINDOW">
|
||||
<animate>true</animate>
|
||||
<color>F84A53</color>
|
||||
<borderColor>F84A53</borderColor>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 2-finger tap: Right click -->
|
||||
<gesture type="TAP" fingers="2" direction="UNKNOWN">
|
||||
<action type="MOUSE_CLICK">
|
||||
<button>3</button>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 3-finger tap: Middle click -->
|
||||
<gesture type="TAP" fingers="3" direction="UNKNOWN">
|
||||
<action type="MOUSE_CLICK">
|
||||
<button>2</button>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 4-finger pinch in: Fullscreen mode 0 -->
|
||||
<gesture type="PINCH" fingers="4" direction="IN">
|
||||
<action type="RUN_COMMAND">
|
||||
<command>hyprctl dispatch fullscreen 0</command>
|
||||
<repeat>false</repeat>
|
||||
<animation>NONE</animation>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 4-finger pinch out: Fullscreen mode 1 -->
|
||||
<gesture type="PINCH" fingers="4" direction="OUT">
|
||||
<action type="RUN_COMMAND">
|
||||
<command>hyprctl dispatch fullscreen 1</command>
|
||||
<repeat>false</repeat>
|
||||
<animation>NONE</animation>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- Note: 3-finger left/right swipes removed - handled by Hyprland's built-in workspace_swipe -->
|
||||
|
||||
<!-- 3-finger swipe up: Show overview -->
|
||||
<gesture type="SWIPE" fingers="3" direction="UP">
|
||||
<action type="RUN_COMMAND">
|
||||
<command>hyprctl dispatch global quickshell:overviewToggle</command>
|
||||
<repeat>false</repeat>
|
||||
<animation>NONE</animation>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 3-finger swipe down: Show all windows -->
|
||||
<gesture type="SWIPE" fingers="3" direction="DOWN">
|
||||
<action type="RUN_COMMAND">
|
||||
<command>hyprctl dispatch overview</command>
|
||||
<repeat>false</repeat>
|
||||
<animation>NONE</animation>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 4-finger swipe left: Move window left -->
|
||||
<gesture type="SWIPE" fingers="4" direction="LEFT">
|
||||
<action type="RUN_COMMAND">
|
||||
<command>hyprctl dispatch movewindow l</command>
|
||||
<repeat>false</repeat>
|
||||
<animation>NONE</animation>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 4-finger swipe right: Move window right -->
|
||||
<gesture type="SWIPE" fingers="4" direction="RIGHT">
|
||||
<action type="RUN_COMMAND">
|
||||
<command>hyprctl dispatch movewindow r</command>
|
||||
<repeat>false</repeat>
|
||||
<animation>NONE</animation>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 4-finger swipe up: Move window up -->
|
||||
<gesture type="SWIPE" fingers="4" direction="UP">
|
||||
<action type="RUN_COMMAND">
|
||||
<command>hyprctl dispatch movewindow u</command>
|
||||
<repeat>false</repeat>
|
||||
<animation>NONE</animation>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
|
||||
<!-- 4-finger swipe down: Move window down -->
|
||||
<gesture type="SWIPE" fingers="4" direction="DOWN">
|
||||
<action type="RUN_COMMAND">
|
||||
<command>hyprctl dispatch movewindow d</command>
|
||||
<repeat>false</repeat>
|
||||
<animation>NONE</animation>
|
||||
<on>begin</on>
|
||||
</action>
|
||||
</gesture>
|
||||
</application>
|
||||
|
||||
<!-- Browser-specific gestures for zoom -->
|
||||
<application name="chromium-browser">
|
||||
<gesture type="PINCH" fingers="2" direction="IN">
|
||||
<action type="SEND_KEYS">
|
||||
<repeat>true</repeat>
|
||||
<modifiers>Control_L</modifiers>
|
||||
<keys>KP_Subtract</keys>
|
||||
<decreaseKeys>KP_Add</decreaseKeys>
|
||||
</action>
|
||||
</gesture>
|
||||
<gesture type="PINCH" fingers="2" direction="OUT">
|
||||
<action type="SEND_KEYS">
|
||||
<repeat>true</repeat>
|
||||
<modifiers>Control_L</modifiers>
|
||||
<keys>KP_Add</keys>
|
||||
<decreaseKeys>KP_Subtract</decreaseKeys>
|
||||
</action>
|
||||
</gesture>
|
||||
</application>
|
||||
|
||||
<application name="google-chrome">
|
||||
<gesture type="PINCH" fingers="2" direction="IN">
|
||||
<action type="SEND_KEYS">
|
||||
<repeat>true</repeat>
|
||||
<modifiers>Control_L</modifiers>
|
||||
<keys>KP_Subtract</keys>
|
||||
<decreaseKeys>KP_Add</decreaseKeys>
|
||||
</action>
|
||||
</gesture>
|
||||
<gesture type="PINCH" fingers="2" direction="OUT">
|
||||
<action type="SEND_KEYS">
|
||||
<repeat>true</repeat>
|
||||
<modifiers>Control_L</modifiers>
|
||||
<keys>KP_Add</keys>
|
||||
<decreaseKeys>KP_Subtract</decreaseKeys>
|
||||
</action>
|
||||
</gesture>
|
||||
</application>
|
||||
|
||||
<application name="firefox">
|
||||
<gesture type="PINCH" fingers="2" direction="IN">
|
||||
<action type="SEND_KEYS">
|
||||
<repeat>true</repeat>
|
||||
<modifiers>Control_L</modifiers>
|
||||
<keys>KP_Subtract</keys>
|
||||
<decreaseKeys>KP_Add</decreaseKeys>
|
||||
</action>
|
||||
</gesture>
|
||||
<gesture type="PINCH" fingers="2" direction="OUT">
|
||||
<action type="SEND_KEYS">
|
||||
<repeat>true</repeat>
|
||||
<modifiers>Control_L</modifiers>
|
||||
<keys>KP_Add</keys>
|
||||
<decreaseKeys>KP_Subtract</decreaseKeys>
|
||||
</action>
|
||||
</gesture>
|
||||
</application>
|
||||
</touchégg>
|
||||
'';
|
||||
description = "Touchegg configuration XML";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Note: touchegg service needs to be enabled at system level
|
||||
# Add this to your NixOS configuration: services.touchegg.enable = true;
|
||||
|
||||
# Install touchegg configuration (both user and system locations)
|
||||
xdg.configFile."touchegg/touchegg.conf" = {
|
||||
text = cfg.config;
|
||||
};
|
||||
|
||||
# Also create system config that touchegg service can read
|
||||
# Note: This requires the touchegg service to be enabled at system level
|
||||
home.activation.toucheggSystemConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||
echo "📄 Creating system-wide touchegg configuration..."
|
||||
$DRY_RUN_CMD sudo mkdir -p /etc/touchegg
|
||||
$DRY_RUN_CMD sudo cp ${config.xdg.configHome}/touchegg/touchegg.conf /etc/touchegg/touchegg.conf
|
||||
echo "✅ System touchegg config updated"
|
||||
'';
|
||||
|
||||
# Create touchegg client service (required for gesture execution)
|
||||
systemd.user.services.touchegg-client = {
|
||||
Unit = {
|
||||
Description = "Touchegg Client";
|
||||
After = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${pkgs.touchegg}/bin/touchegg --client";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 3;
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
# Install touchegg and management scripts
|
||||
home.packages = [ pkgs.touchegg ] ++ [
|
||||
(pkgs.writeShellScriptBin "touchegg-restart" ''
|
||||
echo "🔄 Restarting touchegg service..."
|
||||
sudo systemctl restart touchegg
|
||||
echo "✅ Touchegg restarted"
|
||||
'')
|
||||
|
||||
(pkgs.writeShellScriptBin "touchegg-status" ''
|
||||
echo "📊 Touchegg service status:"
|
||||
systemctl status touchegg --no-pager
|
||||
echo ""
|
||||
echo "📄 Touchegg configuration:"
|
||||
echo " ~/.config/touchegg/touchegg.conf"
|
||||
if [[ -f ~/.config/touchegg/touchegg.conf ]]; then
|
||||
echo " ✅ Configuration file exists"
|
||||
else
|
||||
echo " ❌ Configuration file missing"
|
||||
fi
|
||||
'')
|
||||
|
||||
(pkgs.writeShellScriptBin "touchegg-reload-config" ''
|
||||
echo "🔄 Reloading touchegg configuration..."
|
||||
if systemctl is-active touchegg >/dev/null 2>&1; then
|
||||
sudo systemctl reload touchegg 2>/dev/null || sudo systemctl restart touchegg
|
||||
echo "✅ Touchegg configuration reloaded"
|
||||
else
|
||||
echo "❌ Touchegg service is not running"
|
||||
echo "💡 Try: sudo systemctl start touchegg"
|
||||
fi
|
||||
'')
|
||||
];
|
||||
|
||||
# Session variables for touchegg
|
||||
home.sessionVariables = {
|
||||
TOUCHEGG_CONFIG_PATH = "$HOME/.config/touchegg/touchegg.conf";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
# Configuration management for dots-hyprland
|
||||
# Replicates the installer's rsync behavior exactly
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.dots-hyprland.configuration;
|
||||
mainCfg = config.programs.dots-hyprland;
|
||||
in
|
||||
{
|
||||
options.programs.dots-hyprland.configuration = {
|
||||
enable = mkEnableOption "dots-hyprland configuration management";
|
||||
|
||||
source = mkOption {
|
||||
type = types.path;
|
||||
description = "Source path for dots-hyprland configuration";
|
||||
example = "inputs.dots-hyprland";
|
||||
};
|
||||
|
||||
copyMiscConfig = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Copy miscellaneous config files (everything except fish and hypr)";
|
||||
};
|
||||
|
||||
copyFishConfig = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Copy fish shell configuration";
|
||||
};
|
||||
|
||||
copyHyprlandConfig = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Copy Hyprland configuration";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Replicate installer's MISC config copying
|
||||
# "for i in $(find .config/ -mindepth 1 -maxdepth 1 ! -name 'fish' ! -name 'hypr' -exec basename {} \;)"
|
||||
xdg.configFile = mkMerge [
|
||||
# MISC configs (everything except fish and hypr)
|
||||
(mkIf cfg.copyMiscConfig (
|
||||
let
|
||||
# Get all directories in .config except fish and hypr
|
||||
configDirs = [
|
||||
"quickshell"
|
||||
"kitty"
|
||||
"foot"
|
||||
"fuzzel"
|
||||
"wlogout"
|
||||
"matugen"
|
||||
# Add more as discovered in the source
|
||||
];
|
||||
|
||||
configFiles = listToAttrs (map (dir: {
|
||||
name = dir;
|
||||
value = {
|
||||
source = "${cfg.source}/.config/${dir}";
|
||||
recursive = true;
|
||||
};
|
||||
}) configDirs);
|
||||
in
|
||||
configFiles
|
||||
))
|
||||
|
||||
# Fish configuration
|
||||
(mkIf cfg.copyFishConfig {
|
||||
"fish" = {
|
||||
source = "${cfg.source}/.config/fish";
|
||||
recursive = true;
|
||||
};
|
||||
})
|
||||
|
||||
# Hyprland configuration (special handling like installer)
|
||||
(mkIf cfg.copyHyprlandConfig {
|
||||
# Copy hypr directory excluding specific files
|
||||
# rsync -av --delete --exclude '/custom' --exclude '/hyprlock.conf' --exclude '/hypridle.conf' --exclude '/hyprland.conf'
|
||||
"hypr" = {
|
||||
source = pkgs.runCommand "hypr-config-filtered" {} ''
|
||||
mkdir -p $out
|
||||
|
||||
# Copy everything from source hypr directory
|
||||
cp -r ${cfg.source}/.config/hypr/* $out/ 2>/dev/null || true
|
||||
|
||||
# Remove excluded files (replicating installer --exclude logic)
|
||||
rm -rf $out/custom 2>/dev/null || true
|
||||
rm -f $out/hyprlock.conf 2>/dev/null || true
|
||||
rm -f $out/hypridle.conf 2>/dev/null || true
|
||||
rm -f $out/hyprland.conf 2>/dev/null || true
|
||||
|
||||
# Ensure we have the directory structure
|
||||
mkdir -p $out
|
||||
'';
|
||||
recursive = true;
|
||||
};
|
||||
|
||||
# Copy the main config files separately (installer does this)
|
||||
"hypr/hyprland.conf" = {
|
||||
source = "${cfg.source}/.config/hypr/hyprland.conf";
|
||||
};
|
||||
"hypr/hypridle.conf" = {
|
||||
source = "${cfg.source}/.config/hypr/hypridle.conf";
|
||||
};
|
||||
"hypr/hyprlock.conf" = {
|
||||
source = "${cfg.source}/.config/hypr/hyprlock.conf";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Copy .local/share files (replicating installer)
|
||||
home.file = {
|
||||
".local/share/icons" = mkIf cfg.copyMiscConfig {
|
||||
source = "${cfg.source}/.local/share/icons";
|
||||
recursive = true;
|
||||
};
|
||||
|
||||
".local/share/konsole" = mkIf cfg.copyMiscConfig {
|
||||
source = "${cfg.source}/.local/share/konsole";
|
||||
recursive = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Ensure XDG directories exist (installer creates these)
|
||||
home.activation.createXdgDirs = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||
$DRY_RUN_CMD mkdir -p $HOME/.local/bin
|
||||
$DRY_RUN_CMD mkdir -p $HOME/.cache
|
||||
$DRY_RUN_CMD mkdir -p $HOME/.config
|
||||
$DRY_RUN_CMD mkdir -p $HOME/.local/share
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
# Main Home Manager module for dots-hyprland
|
||||
# Supports both declarative and writable modes
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.dots-hyprland;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./python-environment.nix
|
||||
./configuration.nix
|
||||
./writable-mode.nix
|
||||
./components/quickshell-service.nix
|
||||
./components/touchegg.nix
|
||||
];
|
||||
|
||||
options.programs.dots-hyprland = {
|
||||
enable = mkEnableOption "dots-hyprland desktop environment";
|
||||
|
||||
source = mkOption {
|
||||
type = types.path;
|
||||
description = "Source path for clean dots-hyprland configuration";
|
||||
example = "inputs.dots-hyprland";
|
||||
};
|
||||
|
||||
packageSet = mkOption {
|
||||
type = types.enum [ "minimal" "essential" "all" ];
|
||||
default = "essential";
|
||||
description = "Which package set to install";
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = types.enum [ "declarative" "writable" ];
|
||||
default = "declarative";
|
||||
description = ''
|
||||
Configuration mode:
|
||||
- declarative: Files managed by Home Manager (read-only)
|
||||
- writable: Files staged to .configstaging, user copies and modifies
|
||||
'';
|
||||
};
|
||||
|
||||
writable = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
stagingDir = mkOption {
|
||||
type = types.str;
|
||||
default = ".configstaging";
|
||||
description = "Directory to stage configuration files";
|
||||
};
|
||||
|
||||
setupScript = mkOption {
|
||||
type = types.str;
|
||||
default = "initialSetup.sh";
|
||||
description = "Name of the setup script in ~/.local/bin/";
|
||||
};
|
||||
|
||||
backupExisting = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Backup existing configuration files";
|
||||
};
|
||||
|
||||
symlinkMode = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Create symlinks instead of copying files";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = "Writable mode configuration";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Install packages based on selected set
|
||||
home.packages =
|
||||
let
|
||||
packageSets = import ../packages/dots-hyprland-packages.nix { inherit lib pkgs; };
|
||||
in
|
||||
if cfg.packageSet == "minimal" then packageSets.minimalPackages
|
||||
else if cfg.packageSet == "essential" then packageSets.essentialPackages
|
||||
else packageSets.allPackages;
|
||||
|
||||
# Enable Python virtual environment (CRITICAL for both modes)
|
||||
programs.dots-hyprland.python = {
|
||||
enable = true;
|
||||
autoSetup = true;
|
||||
};
|
||||
|
||||
# Enable configuration management based on mode
|
||||
programs.dots-hyprland.configuration = mkIf (cfg.mode == "declarative") {
|
||||
enable = true;
|
||||
source = cfg.source;
|
||||
};
|
||||
|
||||
# Enable writable mode
|
||||
programs.dots-hyprland.writable-mode = mkIf (cfg.mode == "writable") {
|
||||
enable = true;
|
||||
source = cfg.source;
|
||||
inherit (cfg.writable) stagingDir setupScript backupExisting symlinkMode;
|
||||
};
|
||||
|
||||
# Enable quickshell service (works with both modes)
|
||||
programs.dots-hyprland.quickshell = {
|
||||
enable = true;
|
||||
autoStart = true;
|
||||
restartOnFailure = true;
|
||||
logLevel = "info";
|
||||
};
|
||||
|
||||
# Enable touchegg gesture support
|
||||
programs.dots-hyprland.touchegg = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# Enable custom keybindings
|
||||
|
||||
# Set critical environment variable (required for both modes)
|
||||
home.sessionVariables = {
|
||||
ILLOGICAL_IMPULSE_VIRTUAL_ENV = "$HOME/.local/state/quickshell/.venv";
|
||||
};
|
||||
|
||||
# Ensure XDG directories exist (installer requirement)
|
||||
xdg.enable = true;
|
||||
xdg.userDirs.enable = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
# Python Virtual Environment for dots-hyprland
|
||||
# This replicates the installer's Python setup exactly
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.dots-hyprland.python;
|
||||
mainCfg = config.programs.dots-hyprland;
|
||||
|
||||
# Virtual environment setup script that replicates installer behavior
|
||||
setupVenvScript = pkgs.writeShellScript "setup-dots-hyprland-venv" ''
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
VENV_PATH="$HOME/.local/state/quickshell/.venv"
|
||||
|
||||
echo "🐍 Setting up dots-hyprland Python virtual environment..."
|
||||
echo "📁 Target: $VENV_PATH"
|
||||
|
||||
# Create directory structure
|
||||
mkdir -p "$(dirname "$VENV_PATH")"
|
||||
|
||||
# Remove existing venv if it exists
|
||||
if [[ -d "$VENV_PATH" ]]; then
|
||||
echo "🗑️ Removing existing virtual environment..."
|
||||
rm -rf "$VENV_PATH"
|
||||
fi
|
||||
|
||||
# Set up proper library path for Python packages (64-bit only)
|
||||
export LD_LIBRARY_PATH="${lib.makeLibraryPath (with pkgs; [
|
||||
gcc-unwrapped.lib
|
||||
glibc
|
||||
zlib
|
||||
libffi
|
||||
openssl
|
||||
bzip2
|
||||
xz.out
|
||||
ncurses
|
||||
readline
|
||||
sqlite
|
||||
])}"
|
||||
|
||||
# Clear Python path to avoid conflicts
|
||||
export PYTHONPATH=""
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
echo "📚 Library path: $LD_LIBRARY_PATH"
|
||||
|
||||
# Create virtual environment with Python 3.12 (installer requirement)
|
||||
echo "🏗️ Creating Python 3.12 virtual environment..."
|
||||
${pkgs.python312}/bin/python -m venv "$VENV_PATH" --prompt .venv
|
||||
|
||||
# Activate and install exact requirements from installer
|
||||
echo "📦 Installing Python packages with proper library linking..."
|
||||
source "$VENV_PATH/bin/activate"
|
||||
|
||||
# Upgrade pip first
|
||||
pip install --upgrade pip
|
||||
|
||||
# Install exact versions from scriptdata/requirements.txt
|
||||
pip install --no-cache-dir --force-reinstall \
|
||||
build==1.2.2.post1 \
|
||||
cffi==1.17.1 \
|
||||
libsass==0.23.0 \
|
||||
material-color-utilities==0.2.1 \
|
||||
materialyoucolor==2.0.10 \
|
||||
numpy==2.2.2 \
|
||||
packaging==24.2 \
|
||||
pillow==11.1.0 \
|
||||
psutil==6.1.1 \
|
||||
pycparser==2.22 \
|
||||
pyproject-hooks==1.2.0 \
|
||||
pywayland==0.4.18 \
|
||||
setproctitle==1.3.4 \
|
||||
setuptools==80.9.0 \
|
||||
setuptools-scm==8.1.0 \
|
||||
wheel==0.45.1
|
||||
|
||||
# Test critical imports
|
||||
echo "🧪 Testing critical package imports..."
|
||||
python -c "
|
||||
import sys
|
||||
print(f'Python: {sys.version}')
|
||||
|
||||
tests = [
|
||||
('materialyoucolor', 'materialyoucolor'),
|
||||
('material_color_utilities', 'material_color_utilities'),
|
||||
('sass', 'sass'),
|
||||
('numpy', 'numpy'),
|
||||
('PIL', 'PIL'),
|
||||
('pywayland.client', 'pywayland.client'),
|
||||
('psutil', 'psutil'),
|
||||
('setproctitle', 'setproctitle')
|
||||
]
|
||||
|
||||
working = 0
|
||||
for name, module in tests:
|
||||
try:
|
||||
__import__(module)
|
||||
print(f'✅ {name}')
|
||||
working += 1
|
||||
except Exception as e:
|
||||
print(f'❌ {name}: {e}')
|
||||
|
||||
print(f'📊 {working}/{len(tests)} packages working')
|
||||
if working == len(tests):
|
||||
print('🎉 All critical packages imported successfully!')
|
||||
else:
|
||||
print('⚠️ Some packages failed - may need additional system libraries')
|
||||
"
|
||||
|
||||
deactivate
|
||||
|
||||
echo "✅ Python virtual environment setup complete!"
|
||||
echo "🔗 Environment variable: ILLOGICAL_IMPULSE_VIRTUAL_ENV=$VENV_PATH"
|
||||
echo "📚 Library path configured for NixOS compatibility"
|
||||
'';
|
||||
|
||||
# Test script to verify the Python environment works
|
||||
testVenvScript = pkgs.writeShellScript "test-dots-hyprland-venv" ''
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VENV_PATH="$HOME/.local/state/quickshell/.venv"
|
||||
|
||||
echo "🧪 Testing dots-hyprland Python virtual environment..."
|
||||
|
||||
if [[ ! -d "$VENV_PATH" ]]; then
|
||||
echo "❌ Virtual environment not found at $VENV_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$VENV_PATH/bin/activate"
|
||||
|
||||
# Test critical packages
|
||||
echo "📦 Testing Python packages..."
|
||||
python -c "import material_color_utilities; print('✅ material-color-utilities')" || echo "❌ material-color-utilities"
|
||||
python -c "import materialyoucolor; print('✅ materialyoucolor')" || echo "❌ materialyoucolor"
|
||||
python -c "import pywayland; print('✅ pywayland')" || echo "❌ pywayland"
|
||||
python -c "import PIL; print('✅ pillow')" || echo "❌ pillow"
|
||||
python -c "import numpy; print('✅ numpy')" || echo "❌ numpy"
|
||||
python -c "import psutil; print('✅ psutil')" || echo "❌ psutil"
|
||||
|
||||
deactivate
|
||||
|
||||
echo "🎉 Python environment test complete!"
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.programs.dots-hyprland.python = {
|
||||
enable = mkEnableOption "Python virtual environment for dots-hyprland";
|
||||
|
||||
venvPath = mkOption {
|
||||
type = types.str;
|
||||
default = "$HOME/.local/state/quickshell/.venv";
|
||||
description = "Path to Python virtual environment";
|
||||
};
|
||||
|
||||
autoSetup = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Automatically set up virtual environment on activation";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Install system Python and required build dependencies + test script
|
||||
home.packages = with pkgs; [
|
||||
python312
|
||||
python312Packages.pip
|
||||
python312Packages.virtualenv
|
||||
|
||||
# System dependencies for Python packages (from illogical-impulse-python PKGBUILD)
|
||||
clang
|
||||
gtk4
|
||||
libadwaita
|
||||
libsoup_3
|
||||
libportal-gtk4
|
||||
gobject-introspection
|
||||
sassc
|
||||
opencv4
|
||||
|
||||
# Critical system libraries for Python packages (64-bit)
|
||||
gcc-unwrapped.lib # Provides proper libstdc++.so.6
|
||||
glibc
|
||||
zlib
|
||||
libffi
|
||||
openssl
|
||||
|
||||
# Additional libraries that might be needed
|
||||
bzip2
|
||||
xz
|
||||
ncurses
|
||||
readline
|
||||
sqlite
|
||||
|
||||
# Development tools
|
||||
pkg-config
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
|
||||
# Test script
|
||||
(writeShellScriptBin "test-dots-hyprland-venv" ''
|
||||
${testVenvScript}
|
||||
'')
|
||||
];
|
||||
|
||||
# Set up virtual environment on Home Manager activation
|
||||
home.activation.setupDotsHyprlandVenv = mkIf cfg.autoSetup (
|
||||
lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||
$DRY_RUN_CMD ${setupVenvScript}
|
||||
''
|
||||
);
|
||||
|
||||
# Set critical environment variable and library paths
|
||||
home.sessionVariables = {
|
||||
ILLOGICAL_IMPULSE_VIRTUAL_ENV = cfg.venvPath;
|
||||
# Ensure Python packages can find system libraries (64-bit only)
|
||||
LD_LIBRARY_PATH = lib.makeLibraryPath (with pkgs; [
|
||||
gcc-unwrapped.lib
|
||||
glibc
|
||||
zlib
|
||||
libffi
|
||||
openssl
|
||||
bzip2
|
||||
xz.out
|
||||
ncurses
|
||||
readline
|
||||
sqlite
|
||||
]);
|
||||
# Additional environment variables for Python
|
||||
PYTHONPATH = ""; # Clear to avoid conflicts
|
||||
PYTHONDONTWRITEBYTECODE = "1"; # Prevent .pyc files
|
||||
|
||||
# QML import paths for quickshell
|
||||
QML2_IMPORT_PATH = lib.concatStringsSep ":" (with pkgs; [
|
||||
"${kdePackages.qt5compat}/lib/qt-6/qml"
|
||||
"${kdePackages.qtdeclarative}/lib/qt-6/qml"
|
||||
"${kdePackages.qtwayland}/lib/qt-6/qml"
|
||||
]);
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
# Writable mode for dots-hyprland
|
||||
# Stages configuration to .configstaging and provides setup script
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.dots-hyprland.writable-mode;
|
||||
mainCfg = config.programs.dots-hyprland;
|
||||
|
||||
# Create the initial setup script
|
||||
setupScript = pkgs.writeShellScript "dots-hyprland-setup" ''
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log() {
|
||||
echo -e "''${GREEN}[dots-hyprland]''${NC} $1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "''${YELLOW}[dots-hyprland]''${NC} WARNING: $1"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "''${RED}[dots-hyprland]''${NC} ERROR: $1"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "''${BLUE}[dots-hyprland]''${NC} $1"
|
||||
}
|
||||
|
||||
STAGING_DIR="$HOME/${cfg.stagingDir}"
|
||||
CONFIG_DIR="$HOME/.config"
|
||||
BACKUP_DIR="$HOME/.config-backup-$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
log "🚀 dots-hyprland Initial Setup"
|
||||
log "📁 Staging: $STAGING_DIR"
|
||||
log "🎯 Target: $CONFIG_DIR"
|
||||
|
||||
# Check if staging directory exists
|
||||
if [[ ! -d "$STAGING_DIR" ]]; then
|
||||
error "Staging directory not found: $STAGING_DIR"
|
||||
error "Please run 'home-manager switch' first to create the staging area"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Backup existing configuration if requested
|
||||
${optionalString cfg.backupExisting ''
|
||||
if [[ -d "$CONFIG_DIR" ]]; then
|
||||
log "💾 Creating backup at $BACKUP_DIR"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Backup specific directories that will be overwritten
|
||||
for dir in quickshell hypr fish foot kitty fuzzel wlogout; do
|
||||
if [[ -d "$CONFIG_DIR/$dir" ]]; then
|
||||
info " Backing up $dir"
|
||||
cp -r "$CONFIG_DIR/$dir" "$BACKUP_DIR/" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
log "✅ Backup complete"
|
||||
fi
|
||||
''}
|
||||
|
||||
# Function to copy or symlink files
|
||||
copy_config() {
|
||||
local src="$1"
|
||||
local dst="$2"
|
||||
local name="$(basename "$src")"
|
||||
|
||||
if [[ -d "$src" ]]; then
|
||||
info "📂 Processing directory: $name"
|
||||
mkdir -p "$dst"
|
||||
|
||||
${if cfg.symlinkMode then ''
|
||||
# Create symlink
|
||||
if [[ -L "$dst" ]]; then
|
||||
rm "$dst"
|
||||
elif [[ -d "$dst" ]]; then
|
||||
rm -rf "$dst"
|
||||
fi
|
||||
ln -sf "$src" "$dst"
|
||||
info " 🔗 Symlinked: $name"
|
||||
'' else ''
|
||||
# Copy files
|
||||
cp -rf "$src"/* "$dst/" 2>/dev/null || true
|
||||
info " 📋 Copied: $name"
|
||||
''}
|
||||
elif [[ -f "$src" ]]; then
|
||||
info "📄 Processing file: $name"
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
|
||||
${if cfg.symlinkMode then ''
|
||||
# Create symlink
|
||||
if [[ -L "$dst" ]] || [[ -f "$dst" ]]; then
|
||||
rm "$dst"
|
||||
fi
|
||||
ln -sf "$src" "$dst"
|
||||
info " 🔗 Symlinked: $name"
|
||||
'' else ''
|
||||
# Copy file
|
||||
cp "$src" "$dst"
|
||||
info " 📋 Copied: $name"
|
||||
''}
|
||||
fi
|
||||
}
|
||||
|
||||
# Copy/symlink all staged configuration
|
||||
log "🔄 ${if cfg.symlinkMode then "Symlinking" else "Copying"} configuration files..."
|
||||
|
||||
# Process all directories in staging
|
||||
for item in "$STAGING_DIR"/*; do
|
||||
if [[ -e "$item" ]]; then
|
||||
name="$(basename "$item")"
|
||||
copy_config "$item" "$CONFIG_DIR/$name"
|
||||
fi
|
||||
done
|
||||
|
||||
# Copy .local/share files if they exist
|
||||
if [[ -d "$STAGING_DIR/.local/share" ]]; then
|
||||
log "📦 Processing .local/share files..."
|
||||
mkdir -p "$HOME/.local/share"
|
||||
copy_config "$STAGING_DIR/.local/share/icons" "$HOME/.local/share/icons"
|
||||
copy_config "$STAGING_DIR/.local/share/konsole" "$HOME/.local/share/konsole"
|
||||
fi
|
||||
|
||||
log "✅ Configuration setup complete!"
|
||||
log ""
|
||||
log "📋 Next steps:"
|
||||
log " 1. Your configuration is now ${if cfg.symlinkMode then "symlinked" else "copied"} to ~/.config/"
|
||||
log " 2. ${if cfg.symlinkMode then "Files are symlinked - changes to staging will reflect immediately" else "Files are copied - you can now modify them freely"}"
|
||||
log " 3. Test quickshell: quickshell"
|
||||
log " 4. Test Python environment: test-dots-hyprland-venv"
|
||||
${optionalString cfg.backupExisting ''
|
||||
log " 5. Your original config was backed up to: $BACKUP_DIR"
|
||||
''}
|
||||
log ""
|
||||
log "🎉 Enjoy your dots-hyprland setup!"
|
||||
'';
|
||||
|
||||
# Create a status/info script
|
||||
statusScript = pkgs.writeShellScript "dots-hyprland-status" ''
|
||||
#!/usr/bin/env bash
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "''${GREEN}dots-hyprland Status''${NC}"
|
||||
echo "===================="
|
||||
|
||||
# Check staging directory
|
||||
STAGING_DIR="$HOME/${cfg.stagingDir}"
|
||||
if [[ -d "$STAGING_DIR" ]]; then
|
||||
echo -e "✅ Staging directory: ''${GREEN}$STAGING_DIR''${NC}"
|
||||
echo " $(find "$STAGING_DIR" -type f | wc -l) files staged"
|
||||
else
|
||||
echo -e "❌ Staging directory: ''${RED}Not found''${NC}"
|
||||
fi
|
||||
|
||||
# Check Python virtual environment
|
||||
VENV_PATH="$HOME/.local/state/quickshell/.venv"
|
||||
if [[ -d "$VENV_PATH" ]]; then
|
||||
echo -e "✅ Python venv: ''${GREEN}$VENV_PATH''${NC}"
|
||||
if [[ -f "$VENV_PATH/bin/python" ]]; then
|
||||
VERSION=$("$VENV_PATH/bin/python" --version 2>&1)
|
||||
echo " $VERSION"
|
||||
fi
|
||||
else
|
||||
echo -e "❌ Python venv: ''${RED}Not found''${NC}"
|
||||
fi
|
||||
|
||||
# Check quickshell config
|
||||
if [[ -d "$HOME/.config/quickshell" ]]; then
|
||||
echo -e "✅ Quickshell config: ''${GREEN}~/.config/quickshell''${NC}"
|
||||
if [[ -L "$HOME/.config/quickshell" ]]; then
|
||||
echo " (symlinked to staging)"
|
||||
else
|
||||
echo " (copied from staging)"
|
||||
fi
|
||||
else
|
||||
echo -e "❌ Quickshell config: ''${RED}Not found''${NC}"
|
||||
fi
|
||||
|
||||
# Check environment variable
|
||||
if [[ -n "$ILLOGICAL_IMPULSE_VIRTUAL_ENV" ]]; then
|
||||
echo -e "✅ Environment variable: ''${GREEN}ILLOGICAL_IMPULSE_VIRTUAL_ENV''${NC}"
|
||||
echo " $ILLOGICAL_IMPULSE_VIRTUAL_ENV"
|
||||
else
|
||||
echo -e "❌ Environment variable: ''${RED}ILLOGICAL_IMPULSE_VIRTUAL_ENV not set''${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " ${cfg.setupScript} - Run initial setup"
|
||||
echo " dots-hyprland-status - Show this status"
|
||||
echo " test-dots-hyprland-venv - Test Python environment"
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.programs.dots-hyprland.writable-mode = {
|
||||
enable = mkEnableOption "Writable mode for dots-hyprland configuration";
|
||||
|
||||
source = mkOption {
|
||||
type = types.path;
|
||||
description = "Source path for dots-hyprland configuration";
|
||||
};
|
||||
|
||||
stagingDir = mkOption {
|
||||
type = types.str;
|
||||
default = ".configstaging";
|
||||
description = "Directory to stage configuration files";
|
||||
};
|
||||
|
||||
setupScript = mkOption {
|
||||
type = types.str;
|
||||
default = "initialSetup.sh";
|
||||
description = "Name of the setup script";
|
||||
};
|
||||
|
||||
backupExisting = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Backup existing configuration files";
|
||||
};
|
||||
|
||||
symlinkMode = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Create symlinks instead of copying files";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Stage all configuration files and install scripts
|
||||
home.file =
|
||||
let
|
||||
# Get all config directories from source
|
||||
configDirs = [
|
||||
"quickshell" "hypr" "fish" "foot" "kitty" "fuzzel" "wlogout" "matugen"
|
||||
];
|
||||
|
||||
# Create staging entries for each config directory
|
||||
stagingEntries = listToAttrs (map (dir: {
|
||||
name = "${cfg.stagingDir}/${dir}";
|
||||
value = {
|
||||
source = "${cfg.source}/.config/${dir}";
|
||||
recursive = true;
|
||||
};
|
||||
}) configDirs);
|
||||
|
||||
# Add NixOS-specific patches
|
||||
nixosPatches = {
|
||||
};
|
||||
|
||||
# Add .local/share files to staging
|
||||
localShareEntries = {
|
||||
"${cfg.stagingDir}/.local/share/icons" = {
|
||||
source = "${cfg.source}/.local/share/icons";
|
||||
recursive = true;
|
||||
};
|
||||
"${cfg.stagingDir}/.local/share/konsole" = {
|
||||
source = "${cfg.source}/.local/share/konsole";
|
||||
recursive = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Scripts and utilities
|
||||
scriptEntries = {
|
||||
".local/bin/${cfg.setupScript}" = {
|
||||
source = setupScript;
|
||||
executable = true;
|
||||
};
|
||||
|
||||
".local/bin/dots-hyprland-status" = {
|
||||
source = statusScript;
|
||||
executable = true;
|
||||
};
|
||||
|
||||
"${cfg.stagingDir}/README.md" = {
|
||||
text = ''
|
||||
# dots-hyprland Configuration Staging
|
||||
|
||||
This directory contains the staged configuration files from the original dots-hyprland repository.
|
||||
|
||||
## Setup
|
||||
|
||||
Run the setup script to copy/symlink these files to your ~/.config directory:
|
||||
|
||||
```bash
|
||||
~/.local/bin/${cfg.setupScript}
|
||||
```
|
||||
|
||||
## Mode: ${if cfg.symlinkMode then "Symlink" else "Copy"}
|
||||
|
||||
${if cfg.symlinkMode then ''
|
||||
**Symlink Mode**: Files will be symlinked to ~/.config/
|
||||
- Changes to files in staging will reflect immediately
|
||||
- Useful for development and testing
|
||||
- Files remain managed by Home Manager
|
||||
'' else ''
|
||||
**Copy Mode**: Files will be copied to ~/.config/
|
||||
- You can modify the copied files freely
|
||||
- Changes won't affect the staging area
|
||||
- Full user control over configuration
|
||||
''}
|
||||
|
||||
## Status
|
||||
|
||||
Check the current status with:
|
||||
|
||||
```bash
|
||||
dots-hyprland-status
|
||||
```
|
||||
|
||||
## Files Staged
|
||||
|
||||
- quickshell/ - Widget system configuration
|
||||
- hypr/ - Hyprland window manager configuration
|
||||
- fish/ - Fish shell configuration
|
||||
- foot/ - Foot terminal configuration
|
||||
- kitty/ - Kitty terminal configuration
|
||||
- fuzzel/ - Fuzzel launcher configuration
|
||||
- wlogout/ - Logout menu configuration
|
||||
- .local/share/icons/ - Custom icons
|
||||
- .local/share/konsole/ - Konsole profiles
|
||||
|
||||
## Python Environment
|
||||
|
||||
The Python virtual environment is managed separately and will be created at:
|
||||
`~/.local/state/quickshell/.venv`
|
||||
|
||||
Test it with: `test-dots-hyprland-venv`
|
||||
'';
|
||||
};
|
||||
};
|
||||
in
|
||||
stagingEntries // localShareEntries // scriptEntries // nixosPatches;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user