forked from Shinonome/alt-illogical-impulse
Initial clean flake structure - Phase 3 complete
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
||||
# Nix build results
|
||||
result
|
||||
result-*
|
||||
|
||||
# Nix development
|
||||
.direnv/
|
||||
.envrc
|
||||
|
||||
# Cache directories
|
||||
.cache/
|
||||
*.tmp
|
||||
|
||||
# Editor files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Temporary files
|
||||
*.bak
|
||||
*.orig
|
||||
|
||||
# External repositories (for reference only)
|
||||
dots-hyprland/
|
||||
dots-hyprland-wiki/
|
||||
@@ -0,0 +1,227 @@
|
||||
# dots-hyprland for NixOS
|
||||
|
||||
A NixOS adaptation of [end-4's dots-hyprland](https://github.com/end-4/dots-hyprland) desktop environment, bringing the beautiful "illogical-impulse" style to NixOS with full declarative configuration.
|
||||
|
||||
## 🎯 Project Status: Phase 3 Complete ✅
|
||||
|
||||
**Current Achievement: Core Desktop Environment Functional**
|
||||
|
||||
- ✅ **Quickshell Integration** - Official flake support resolved
|
||||
- ✅ **Hyprland Configuration** - Complete window manager setup with Material You theming
|
||||
- ✅ **Essential Applications** - foot terminal, fuzzel launcher, nautilus file manager
|
||||
- ✅ **Home Manager Integration** - Fully declarative configuration
|
||||
- ✅ **Package Management** - All dependencies properly integrated
|
||||
- ✅ **Development Environment** - Ready for Phase 4 advanced features
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
- NixOS with flakes enabled
|
||||
- Home Manager (optional but recommended)
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone <repository-url>
|
||||
cd dots-hyprland-nixos
|
||||
|
||||
# Build and activate Home Manager configuration
|
||||
nix build .#homeConfigurations.example.activationPackage
|
||||
./result/activate
|
||||
|
||||
# Or use with your existing Home Manager setup
|
||||
# Add to your flake inputs:
|
||||
# dots-hyprland.url = "github:your-org/dots-hyprland-nixos";
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Enter development environment
|
||||
nix develop
|
||||
|
||||
# Available development tools:
|
||||
# - update-flake: Manage flake inputs and GitHub synchronization
|
||||
# - compare-modes: Compare declarative vs writable configuration modes
|
||||
# - test-python-env: Test Python virtual environment setup
|
||||
# - test-quickshell: Test quickshell configuration
|
||||
|
||||
# Flake management examples:
|
||||
update-flake status # Show current flake status
|
||||
update-flake update # Update all flake inputs
|
||||
update-flake update-source # Update only dots-hyprland source
|
||||
update-flake verify # Test that configurations build
|
||||
update-flake help # Show all available options
|
||||
```
|
||||
|
||||
## 📋 Features
|
||||
|
||||
### ✅ Implemented (Phase 3)
|
||||
- **Hyprland Window Manager** - Complete configuration with Material You theming
|
||||
- **foot Terminal** - Tokyo Night color scheme, JetBrainsMono Nerd Font
|
||||
- **fuzzel Launcher** - Material You themed application launcher
|
||||
- **Essential Keybinds** - All core window management and application shortcuts
|
||||
- **Package Integration** - Declarative package management through Nix
|
||||
- **Home Manager Support** - Full integration with Home Manager modules
|
||||
|
||||
### 🔄 In Progress (Phase 4)
|
||||
- **AI Integration** - Gemini and Ollama support
|
||||
- **Advanced Widgets** - Overview with live previews, sidebars
|
||||
- **Comprehensive Theming** - Dynamic Material You color generation
|
||||
- **Quality of Life** - Screen corners, session management, cheatsheet
|
||||
|
||||
### 📅 Planned (Future Phases)
|
||||
- **NixOS System Integration** - Full system-level configuration
|
||||
- **Testing & Validation** - Comprehensive test suite
|
||||
- **Community & Maintenance** - Documentation, contribution guidelines
|
||||
|
||||
## 🔄 Flake Management
|
||||
|
||||
The project includes a comprehensive flake management utility for keeping your configuration synchronized with GitHub:
|
||||
|
||||
### Quick Commands
|
||||
|
||||
```bash
|
||||
# Check current status
|
||||
update-flake status
|
||||
|
||||
# Update all flake inputs
|
||||
update-flake update
|
||||
|
||||
# Update only dots-hyprland source
|
||||
update-flake update-source
|
||||
|
||||
# Verify configurations build
|
||||
update-flake verify
|
||||
|
||||
# Update and verify in one command
|
||||
update-flake update --auto-verify
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
|
||||
```bash
|
||||
# Pin to a specific commit
|
||||
update-flake pin abc123def
|
||||
|
||||
# Switch to tracking a different branch
|
||||
update-flake branch main
|
||||
|
||||
# Dry run to see what would happen
|
||||
update-flake update --dry-run
|
||||
```
|
||||
|
||||
The utility automatically detects synchronization status and provides clear feedback about your flake's relationship to the GitHub repository.
|
||||
|
||||
## 🎨 Configuration
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
```nix
|
||||
{
|
||||
programs.dots-hyprland = {
|
||||
enable = true;
|
||||
style = "illogical-impulse";
|
||||
|
||||
components = {
|
||||
hyprland = true;
|
||||
quickshell = true;
|
||||
theming = false; # Phase 4
|
||||
ai = false; # Phase 4
|
||||
audio = true;
|
||||
};
|
||||
|
||||
features = {
|
||||
overview = true;
|
||||
sidebar = false; # Phase 4
|
||||
notifications = true;
|
||||
mediaControls = true;
|
||||
};
|
||||
|
||||
keybinds = {
|
||||
modifier = "SUPER";
|
||||
terminal = "foot";
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Keybinds
|
||||
|
||||
| Key Combination | Action |
|
||||
|----------------|--------|
|
||||
| `SUPER + Return` | Open terminal |
|
||||
| `SUPER + Space` | Open application launcher |
|
||||
| `SUPER + Q` | Close window |
|
||||
| `SUPER + E` | Open file manager |
|
||||
| `SUPER + F` | Toggle fullscreen |
|
||||
| `SUPER + V` | Toggle floating |
|
||||
| `SUPER + 1-0` | Switch to workspace |
|
||||
| `SUPER + Shift + 1-0` | Move window to workspace |
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
### Module Structure
|
||||
```
|
||||
modules/
|
||||
├── home-manager.nix # Main Home Manager integration
|
||||
├── nixos.nix # NixOS system integration
|
||||
└── components/
|
||||
├── packages.nix # Package management
|
||||
├── hyprland.nix # Hyprland configuration
|
||||
└── applications.nix # Application configurations
|
||||
```
|
||||
|
||||
### Flake Structure
|
||||
```
|
||||
├── flake.nix # Main flake with inputs/outputs
|
||||
├── modules/ # NixOS/Home Manager modules
|
||||
├── packages/ # Custom package derivations
|
||||
├── configs/ # Configuration templates
|
||||
└── assets/ # Static assets (icons, themes)
|
||||
```
|
||||
|
||||
## 🎯 Gameplan Progress
|
||||
|
||||
This project follows a systematic 7-phase development approach:
|
||||
|
||||
- [x] **Phase 1: Dependency Analysis** - All dependencies mapped to NixOS
|
||||
- [x] **Phase 2: Module Structure** - Complete flake and module architecture
|
||||
- [x] **Phase 3: Core Implementation** - ✅ **CURRENT MILESTONE**
|
||||
- [ ] **Phase 4: Advanced Features** - AI, advanced widgets, comprehensive theming
|
||||
- [ ] **Phase 5: NixOS Adaptations** - Full NixOS integration patterns
|
||||
- [ ] **Phase 6: Testing & Validation** - Comprehensive testing suite
|
||||
- [ ] **Phase 7: Community & Maintenance** - Documentation, contribution guidelines
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
This project is in active development. Contributions are welcome!
|
||||
|
||||
### Development Setup
|
||||
1. Clone the repository
|
||||
2. Run `nix develop` to enter the development environment
|
||||
3. Make your changes
|
||||
4. Test with `nix build .#homeConfigurations.example.activationPackage`
|
||||
5. Submit a pull request
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the GPL-3.0 License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
- **end-4** - Original dots-hyprland creator
|
||||
- **outfoxxed** - Quickshell developer (official Nix flake support was crucial!)
|
||||
- **NixOS Community** - For the amazing ecosystem
|
||||
- **Hyprland Team** - For the fantastic window manager
|
||||
|
||||
## 📞 Support
|
||||
|
||||
- **Issues**: Report bugs and request features via GitHub Issues
|
||||
- **Discussions**: General questions and ideas via GitHub Discussions
|
||||
- **Community**: Join the NixOS and Hyprland communities for broader support
|
||||
|
||||
---
|
||||
|
||||
**Status**: Phase 3 Complete - Core desktop environment functional and ready for advanced features! 🚀
|
||||
Generated
+100
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"nodes": {
|
||||
"dots-hyprland": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1754709786,
|
||||
"narHash": "sha256-NDEupEt2F2yMCI2cWNy1tE8FsuLwW4NGvgJierzMPwQ=",
|
||||
"owner": "celesrenata",
|
||||
"repo": "dots-hyprland",
|
||||
"rev": "65b10e45fdc082f6f1b7a6135393f870510e2f51",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "celesrenata",
|
||||
"ref": "installer-replication",
|
||||
"repo": "dots-hyprland",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1754613544,
|
||||
"narHash": "sha256-ueR1mGX4I4DWfDRRxxMphbKDNisDeMPMusN72VV1+cc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "cc2fa2331aebf9661d22bb507d362b39852ac73f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1754498491,
|
||||
"narHash": "sha256-erbiH2agUTD0Z30xcVSFcDHzkRvkRXOQ3lb887bcVrs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c2ae88e026f9525daf89587f3cbee584b92b6134",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1749285348,
|
||||
"narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3e3afe5174c561dee0df6f2c2b2236990146329f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"quickshell": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753595452,
|
||||
"narHash": "sha256-vqkSDvh7hWhPvNjMjEDV4KbSCv2jyl2Arh73ZXe274k=",
|
||||
"owner": "outfoxxed",
|
||||
"repo": "quickshell",
|
||||
"rev": "a5431dd02dc23d9ef1680e67777fed00fe5f7cda",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "outfoxxed",
|
||||
"repo": "quickshell",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"dots-hyprland": "dots-hyprland",
|
||||
"home-manager": "home-manager",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"quickshell": "quickshell"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
{
|
||||
description = "NixOS adaptation of end-4's dots-hyprland using installer replication";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
# Official quickshell flake (our breakthrough discovery!)
|
||||
quickshell.url = "github:outfoxxed/quickshell";
|
||||
|
||||
# Original dots-hyprland source from GitHub - tracks installer-replication branch
|
||||
dots-hyprland = {
|
||||
url = "github:celesrenata/dots-hyprland/installer-replication";
|
||||
flake = false; # Use as source only, don't build
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, home-manager, quickshell, dots-hyprland, ... }:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ self.overlays.default ];
|
||||
};
|
||||
in
|
||||
{
|
||||
# Package overlays
|
||||
overlays.default = final: prev: {
|
||||
# Make quickshell available from official flake
|
||||
quickshell = quickshell.packages.${system}.default;
|
||||
};
|
||||
|
||||
# Packages
|
||||
packages.${system} = {
|
||||
# Flake management utilities
|
||||
update-flake = pkgs.writeShellScriptBin "update-flake" ''
|
||||
# dots-hyprland Flake Update Utility
|
||||
# Manages flake input updates and GitHub synchronization
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log() {
|
||||
echo -e "''${GREEN}[update-flake]''${NC} $1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "''${YELLOW}[update-flake]''${NC} WARNING: $1"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "''${RED}[update-flake]''${NC} ERROR: $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "''${BLUE}[update-flake]''${NC} $1"
|
||||
}
|
||||
|
||||
header() {
|
||||
echo -e "''${CYAN}=== $1 ===''${NC}"
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat << EOF
|
||||
dots-hyprland Flake Update Utility
|
||||
|
||||
USAGE:
|
||||
update-flake [OPTIONS] [COMMAND]
|
||||
|
||||
COMMANDS:
|
||||
update Update all flake inputs (default)
|
||||
update-source Update only dots-hyprland source input
|
||||
pin <commit> Pin dots-hyprland to specific commit
|
||||
branch <name> Switch to tracking a specific branch
|
||||
status Show current flake input status
|
||||
verify Verify flake builds after update
|
||||
help Show this help message
|
||||
|
||||
OPTIONS:
|
||||
--auto-verify Automatically verify builds after update
|
||||
--dry-run Show what would be done without executing
|
||||
|
||||
EXAMPLES:
|
||||
update-flake # Update all inputs
|
||||
update-flake update-source # Update only dots-hyprland source
|
||||
update-flake pin abc123def # Pin to specific commit
|
||||
update-flake branch main # Track main branch
|
||||
update-flake status # Show current status
|
||||
update-flake update --auto-verify # Update and verify builds
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
get_current_commit() {
|
||||
git rev-parse HEAD
|
||||
}
|
||||
|
||||
get_current_branch() {
|
||||
git branch --show-current
|
||||
}
|
||||
|
||||
get_flake_source_info() {
|
||||
if [[ -f flake.lock ]]; then
|
||||
local rev=$(${pkgs.jq}/bin/jq -r '.nodes."dots-hyprland".locked.rev // "unknown"' flake.lock)
|
||||
local ref=$(${pkgs.jq}/bin/jq -r '.nodes."dots-hyprland".original.ref // .nodes."dots-hyprland".original.rev // "unknown"' flake.lock)
|
||||
echo "$rev|$ref"
|
||||
else
|
||||
echo "unknown|unknown"
|
||||
fi
|
||||
}
|
||||
|
||||
show_status() {
|
||||
header "Flake Status"
|
||||
|
||||
local current_commit=$(get_current_commit)
|
||||
local current_branch=$(get_current_branch)
|
||||
local flake_info=$(get_flake_source_info)
|
||||
local flake_rev=$(echo "$flake_info" | cut -d'|' -f1)
|
||||
local flake_ref=$(echo "$flake_info" | cut -d'|' -f2)
|
||||
|
||||
echo "📁 Project Directory: $(pwd)"
|
||||
echo "🌿 Current Branch: $current_branch"
|
||||
echo "📝 Current Commit: ''${current_commit:0:12}..."
|
||||
echo "🔒 Flake Locked To: ''${flake_rev:0:12}..."
|
||||
echo "🎯 Flake Tracking: $flake_ref"
|
||||
echo ""
|
||||
|
||||
if [[ "$flake_rev" == "$current_commit" ]]; then
|
||||
log "✅ Flake is synchronized with current commit"
|
||||
elif [[ "$flake_ref" == "$current_branch" ]]; then
|
||||
warn "🔄 Flake tracks branch but may need update"
|
||||
info "Run 'update-flake update' to sync with latest commits"
|
||||
else
|
||||
warn "⚠️ Flake is out of sync"
|
||||
info "Flake: $flake_ref (''${flake_rev:0:12}...)"
|
||||
info "Local: $current_branch (''${current_commit:0:12}...)"
|
||||
fi
|
||||
}
|
||||
|
||||
update_all_inputs() {
|
||||
header "Updating All Flake Inputs"
|
||||
|
||||
log "Running nix flake update..."
|
||||
if nix flake update; then
|
||||
log "✅ All inputs updated successfully"
|
||||
else
|
||||
error "Failed to update flake inputs"
|
||||
fi
|
||||
}
|
||||
|
||||
update_source_only() {
|
||||
header "Updating dots-hyprland Source Input"
|
||||
|
||||
log "Running nix flake lock --update-input dots-hyprland..."
|
||||
if nix flake lock --update-input dots-hyprland; then
|
||||
log "✅ dots-hyprland source updated successfully"
|
||||
else
|
||||
error "Failed to update dots-hyprland source input"
|
||||
fi
|
||||
}
|
||||
|
||||
verify_builds() {
|
||||
header "Verifying Flake Builds"
|
||||
|
||||
local configs=("declarative" "writable")
|
||||
local success=true
|
||||
|
||||
for config in "''${configs[@]}"; do
|
||||
info "🔨 Testing $config configuration..."
|
||||
if nix build ".#homeConfigurations.$config.activationPackage" --no-link --quiet; then
|
||||
log "✅ $config configuration builds successfully"
|
||||
else
|
||||
error "❌ $config configuration failed to build"
|
||||
success=false
|
||||
fi
|
||||
done
|
||||
|
||||
if $success; then
|
||||
log "🎉 All configurations build successfully!"
|
||||
else
|
||||
error "Some configurations failed to build"
|
||||
fi
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
AUTO_VERIFY=false
|
||||
DRY_RUN=false
|
||||
COMMAND="update"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--auto-verify)
|
||||
AUTO_VERIFY=true
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
update|update-source|status|verify|help)
|
||||
COMMAND="$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
if [[ "$1" != -* ]]; then
|
||||
COMMAND="$1"
|
||||
shift
|
||||
else
|
||||
error "Unknown option: $1"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Main execution
|
||||
case "$COMMAND" in
|
||||
help)
|
||||
show_help
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
update)
|
||||
if $DRY_RUN; then
|
||||
info "DRY RUN: Would update all flake inputs"
|
||||
show_status
|
||||
else
|
||||
update_all_inputs
|
||||
if $AUTO_VERIFY; then
|
||||
verify_builds
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
update-source)
|
||||
if $DRY_RUN; then
|
||||
info "DRY RUN: Would update dots-hyprland source input"
|
||||
show_status
|
||||
else
|
||||
update_source_only
|
||||
if $AUTO_VERIFY; then
|
||||
verify_builds
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
verify)
|
||||
verify_builds
|
||||
;;
|
||||
*)
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
|
||||
# Test utilities
|
||||
test-python-env = pkgs.writeShellScriptBin "test-python-env" ''
|
||||
#!/usr/bin/env bash
|
||||
echo "🧪 Testing dots-hyprland Python environment..."
|
||||
|
||||
VENV_PATH="$HOME/.local/state/quickshell/.venv"
|
||||
|
||||
if [[ ! -d "$VENV_PATH" ]]; then
|
||||
echo "❌ Virtual environment not found at $VENV_PATH"
|
||||
echo "💡 Run: home-manager switch"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$VENV_PATH/bin/activate"
|
||||
python -c "
|
||||
import sys
|
||||
print(f'✅ Python {sys.version}')
|
||||
|
||||
try:
|
||||
import material_color_utilities
|
||||
print('✅ material-color-utilities')
|
||||
except ImportError:
|
||||
print('❌ material-color-utilities')
|
||||
|
||||
try:
|
||||
import materialyoucolor
|
||||
print('✅ materialyoucolor')
|
||||
except ImportError:
|
||||
print('❌ materialyoucolor')
|
||||
|
||||
try:
|
||||
import pywayland
|
||||
print('✅ pywayland')
|
||||
except ImportError:
|
||||
print('❌ pywayland')
|
||||
"
|
||||
deactivate
|
||||
'';
|
||||
|
||||
# Test quickshell with clean config
|
||||
test-quickshell = pkgs.writeShellScriptBin "test-quickshell" ''
|
||||
#!/usr/bin/env bash
|
||||
echo "🧪 Testing quickshell with dots-hyprland config..."
|
||||
|
||||
if [[ ! -d "$HOME/.config/quickshell" ]]; then
|
||||
echo "❌ No quickshell configuration found"
|
||||
echo "💡 Run: home-manager switch"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$HOME/.config/quickshell"
|
||||
echo "🚀 Starting quickshell (timeout 10s)..."
|
||||
timeout 10 ${pkgs.quickshell}/bin/quickshell 2>&1 | head -20
|
||||
'';
|
||||
|
||||
# Mode comparison utility
|
||||
compare-modes = pkgs.writeShellScriptBin "compare-modes" ''
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "🔍 dots-hyprland Configuration Modes"
|
||||
echo "===================================="
|
||||
echo ""
|
||||
echo "📋 Available modes:"
|
||||
echo ""
|
||||
echo "1. 🔒 DECLARATIVE MODE"
|
||||
echo " • Files managed by Home Manager"
|
||||
echo " • Read-only configuration"
|
||||
echo " • Automatic updates with 'home-manager switch'"
|
||||
echo " • Best for: Set-and-forget users"
|
||||
echo " • Build: nix build .#homeConfigurations.declarative.activationPackage"
|
||||
echo ""
|
||||
echo "2. ✏️ WRITABLE MODE"
|
||||
echo " • Files staged to ~/.configstaging"
|
||||
echo " • User copies/modifies configuration"
|
||||
echo " • Full control over files"
|
||||
echo " • Best for: Customization and development"
|
||||
echo " • Build: nix build .#homeConfigurations.writable.activationPackage"
|
||||
echo ""
|
||||
echo "🚀 Quick start:"
|
||||
echo " # For declarative mode:"
|
||||
echo " nix build .#homeConfigurations.declarative.activationPackage && ./result/activate"
|
||||
echo ""
|
||||
echo " # For writable mode:"
|
||||
echo " nix build .#homeConfigurations.writable.activationPackage && ./result/activate"
|
||||
echo " ~/.local/bin/initialSetup.sh"
|
||||
'';
|
||||
|
||||
# Default package for easy testing
|
||||
default = self.packages.${system}.update-flake;
|
||||
};
|
||||
|
||||
# Development shell
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
nixpkgs-fmt
|
||||
nil
|
||||
git
|
||||
|
||||
# Our utilities
|
||||
self.packages.${system}.update-flake
|
||||
self.packages.${system}.test-python-env
|
||||
self.packages.${system}.test-quickshell
|
||||
self.packages.${system}.compare-modes
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo "🚀 dots-hyprland installer replication development environment"
|
||||
echo ""
|
||||
echo "📋 Available commands:"
|
||||
echo " update-flake - Manage flake inputs and GitHub sync"
|
||||
echo " compare-modes - Compare declarative vs writable modes"
|
||||
echo " test-python-env - Test Python virtual environment"
|
||||
echo " test-quickshell - Test quickshell with config"
|
||||
echo ""
|
||||
echo "🔄 Flake management:"
|
||||
echo " update-flake status - Show current flake status"
|
||||
echo " update-flake update - Update all flake inputs"
|
||||
echo " update-flake verify - Test configurations build"
|
||||
echo ""
|
||||
echo "🎯 Build configurations:"
|
||||
echo " nix build .#homeConfigurations.declarative.activationPackage"
|
||||
echo " nix build .#homeConfigurations.writable.activationPackage"
|
||||
echo ""
|
||||
echo "🔑 Key insight: Both modes use the same Python venv and packages!"
|
||||
echo "📁 Branch: $(git branch --show-current)"
|
||||
echo ""
|
||||
echo "💡 Run 'update-flake help' for full flake management options"
|
||||
'';
|
||||
};
|
||||
|
||||
# Home Manager module
|
||||
homeManagerModules.default = import ./modules/home-manager.nix;
|
||||
homeManagerModules.dots-hyprland = self.homeManagerModules.default;
|
||||
|
||||
# Example Home Manager configurations
|
||||
homeConfigurations = {
|
||||
# Declarative approach (read-only, managed by Home Manager)
|
||||
declarative = home-manager.lib.homeManagerConfiguration {
|
||||
inherit pkgs;
|
||||
modules = [
|
||||
self.homeManagerModules.default
|
||||
{
|
||||
home.username = "celes";
|
||||
home.homeDirectory = "/home/celes";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
programs.dots-hyprland = {
|
||||
enable = true;
|
||||
source = dots-hyprland;
|
||||
packageSet = "essential";
|
||||
# Declarative mode (default)
|
||||
mode = "declarative";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Writable approach (staging + user modification)
|
||||
writable = home-manager.lib.homeManagerConfiguration {
|
||||
inherit pkgs;
|
||||
modules = [
|
||||
self.homeManagerModules.default
|
||||
{
|
||||
home.username = "celes";
|
||||
home.homeDirectory = "/home/celes";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
programs.dots-hyprland = {
|
||||
enable = true;
|
||||
source = dots-hyprland;
|
||||
packageSet = "essential";
|
||||
# Writable mode - stages to .configstaging
|
||||
mode = "writable";
|
||||
writable = {
|
||||
stagingDir = ".configstaging";
|
||||
setupScript = "initialSetup.sh";
|
||||
backupExisting = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Alias for backward compatibility
|
||||
example = self.homeConfigurations.declarative;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
# Package mappings from dots-hyprland meta-packages to nixpkgs
|
||||
# Direct mapping from PKGBUILD files in arch-packages/
|
||||
{ lib, pkgs }:
|
||||
|
||||
let
|
||||
# illogical-impulse-basic PKGBUILD
|
||||
basicPackages = with pkgs; [
|
||||
axel
|
||||
bc
|
||||
coreutils
|
||||
cliphist
|
||||
cmake
|
||||
curl
|
||||
rsync
|
||||
wget
|
||||
ripgrep
|
||||
jq
|
||||
meson
|
||||
xdg-user-dirs
|
||||
];
|
||||
|
||||
# illogical-impulse-widgets PKGBUILD
|
||||
widgetPackages = with pkgs; [
|
||||
fuzzel
|
||||
glib # for gsettings
|
||||
hypridle
|
||||
hyprutils
|
||||
hyprlock
|
||||
hyprpicker
|
||||
networkmanagerapplet # nm-connection-editor
|
||||
# quickshell-git -> provided by quickshell flake input
|
||||
translate-shell
|
||||
wlogout
|
||||
|
||||
# Qt modules needed for quickshell widgets
|
||||
kdePackages.qt5compat # For Qt5Compat.GraphicalEffects
|
||||
kdePackages.qtdeclarative # For QML
|
||||
kdePackages.qtwayland # For Wayland support
|
||||
];
|
||||
|
||||
# illogical-impulse-hyprland PKGBUILD
|
||||
hyprlandPackages = with pkgs; [
|
||||
hypridle
|
||||
hyprcursor
|
||||
hyprland
|
||||
hyprland-qtutils
|
||||
# hyprland-qt-support -> might be in hyprland-qtutils
|
||||
hyprlang
|
||||
hyprlock
|
||||
hyprpicker
|
||||
hyprsunset
|
||||
hyprutils
|
||||
hyprwayland-scanner
|
||||
xdg-desktop-portal-hyprland
|
||||
wl-clipboard
|
||||
];
|
||||
|
||||
# illogical-impulse-python PKGBUILD (system dependencies)
|
||||
pythonSystemPackages = with pkgs; [
|
||||
clang
|
||||
# uv -> not needed in NixOS approach, we use pip directly
|
||||
gtk4
|
||||
libadwaita
|
||||
libsoup_3 # libsoup3
|
||||
libportal-gtk4
|
||||
gobject-introspection
|
||||
sassc
|
||||
opencv4 # python-opencv
|
||||
];
|
||||
|
||||
# Additional packages that might be needed
|
||||
audioPackages = with pkgs; [
|
||||
pipewire
|
||||
wireplumber
|
||||
pavucontrol
|
||||
playerctl
|
||||
];
|
||||
|
||||
# Font packages (from installer analysis)
|
||||
fontPackages = with pkgs; [
|
||||
# Rubik font (installer sets this as default)
|
||||
# Note: might need to add custom font derivation
|
||||
noto-fonts
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-emoji
|
||||
font-awesome
|
||||
material-design-icons
|
||||
nerd-fonts.jetbrains-mono
|
||||
nerd-fonts.fira-code
|
||||
];
|
||||
|
||||
# Theme and appearance packages
|
||||
themePackages = with pkgs; [
|
||||
matugen # for Material You color generation
|
||||
# Additional theme packages as needed
|
||||
];
|
||||
in
|
||||
{
|
||||
inherit
|
||||
basicPackages
|
||||
widgetPackages
|
||||
hyprlandPackages
|
||||
pythonSystemPackages
|
||||
audioPackages
|
||||
fontPackages
|
||||
themePackages;
|
||||
|
||||
# Combined package sets for different use cases
|
||||
essentialPackages = basicPackages ++ widgetPackages ++ hyprlandPackages;
|
||||
|
||||
allPackages = basicPackages ++ widgetPackages ++ hyprlandPackages ++
|
||||
pythonSystemPackages ++ audioPackages ++ fontPackages ++ themePackages;
|
||||
|
||||
# Minimal set for testing
|
||||
minimalPackages = basicPackages ++ widgetPackages;
|
||||
}
|
||||
Reference in New Issue
Block a user