diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 6764238..0000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -modules/profiles/* filter=git-crypt diff=git-crypt -modules/profiles/vmtest.nix !filter !diff -modules/profiles/default.nix !filter !diff diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 0000000..a859999 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,47 @@ +name: Checks + +on: + pull_request: + workflow_dispatch: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + format: + name: Format (alejandra) + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v30 + - run: nix fmt -- --check . + + build: + name: Build (${{ matrix.system }}) + needs: format + strategy: + fail-fast: false + matrix: + include: + - system: x86_64-linux + runner: ubuntu-latest + - system: aarch64-darwin + runner: macos-14 + runs-on: ${{ matrix.runner }} + timeout-minutes: 180 + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v30 + - uses: nix-community/cache-nix-action@v6 + with: + primary-key: nix-${{ matrix.system }}-${{ hashFiles('flake.lock') }} + restore-prefixes-first-match: nix-${{ matrix.system }}- + gc-max-store-size-linux: 10G + gc-max-store-size-macos: 10G + - name: Build checks + run: nix flake check -L --keep-going diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..1879bb5 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,15 @@ +name: Test + +on: + workflow_dispatch: + +jobs: + update: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + - uses: DeterminateSystems/determinate-nix-action@v3 + + - name: Test + run: nix build .#nixosConfigurations.gpd.config.system.build.toplevel --dry-run diff --git a/.github/workflows/update-flake-lock.yml b/.github/workflows/update-flake-lock.yml new file mode 100644 index 0000000..b14a2fb --- /dev/null +++ b/.github/workflows/update-flake-lock.yml @@ -0,0 +1,46 @@ +name: Update flake.lock + +on: + schedule: + - cron: "0 21 * * 1" + workflow_dispatch: + +concurrency: + group: update-flake-lock + cancel-in-progress: false + +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + update: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + - uses: DeterminateSystems/determinate-nix-action@v3 + - id: update + uses: DeterminateSystems/update-flake-lock@v28 + with: + token: ${{ secrets.GH_TOKEN_FOR_UPDATES }} + base: main + branch: bot/flake-update + commit-msg: "chore: update flake.lock" + pr-title: "chore: update flake.lock" + pr-labels: | + dependencies + chore + pr-body: | + Automated changes by the [update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock) GitHub Action. + + ``` + {{ env.GIT_COMMIT_MESSAGE }} + ``` + + - name: Enable auto-merge + if: steps.update.outputs.pull-request-number != '' + env: + GH_TOKEN: ${{ secrets.GH_TOKEN_FOR_UPDATES }} + run: gh pr merge --repo "$GITHUB_REPOSITORY" --auto --squash "${{ steps.update.outputs.pull-request-number }}" diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..f398462 --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,20 @@ +keys: + - &personal_admin age13vyme78jmvjv499t7dzl2ju4epy90792nje0mvyh6ar93zae75kqyzsr2j + - &pc age146xlkyvdxgjqjt3fnawtvqgzuk0fwgjsj9gf3c0z3q5n02r49vgsz3nk4s + - &laptop age1sjlg4s9jq2qlevlkhylguul7ztxr6cassnj7xle7patzlgmy5syqan5vpz + - &gpd age1mjqu5xzvtgcpvy5tg9cnv7hk8vd9vmmgxmk8xtj3wudj2qf7ugcq53weqr + +creation_rules: + - path_regex: secrets/personal\.yaml$ + key_groups: + - age: + - *personal_admin + - *pc + - *laptop + - *gpd + + - path_regex: secrets/work\.yaml$ + key_groups: + - age: + - *personal_admin + - *pc diff --git a/README.md b/README.md index 5c9892c..386d949 100644 --- a/README.md +++ b/README.md @@ -4,103 +4,149 @@ Personal NixOS and nix-darwin configuration by [Aaron Vargas](https://github.com/aaron70). - -## Features - -- **Cross-platform** — shared module system for both NixOS and macOS via nix-darwin -- **Three-tier architecture** — profiles (who you are) → features (capabilities) → programs (tools) -- **Wrapper module system** — programs ship with auto-generated configs via `nix-wrapper-modules` -- **Tokyo Night theme** — consistent look across shell prompt (oh-my-posh), WM (niri), terminal (kitty), and desktop shell (Noctalia) -- **niri + Noctalia** on Linux — scrollable-tiling Wayland compositor with a full-featured desktop shell -- **AeroSpace** on macOS — native tiling window manager -- **GPD Win Max 2** — Steam Deck / handheld optimizations via Jovian-NixOS, fingerprint driver -- **Secrets management** — git-crypt encrypted profiles for credentials - ## Hosts -| Host | Arch | OS | Profile | GPU | Desktop | -|------|------|----|---------|-----|----------| -| `pc` | x86_64 | NixOS | personal | NVIDIA | niri + Noctalia | -| `laptop` | x86_64 | NixOS | personal | Intel | niri + Noctalia | -| `gpd` | x86_64 | NixOS (Jovian) | personal | AMD | niri + Noctalia | -| `mac` | aarch64 | macOS | work | Apple Silicon | AeroSpace | +| Host | Arch | OS | User | GPU | Desktop | Notes | +|------|------|----|---------|-----|----------|-----| +| `pc` | x86_64 | NixOS | aaronv | NVIDIA | niri + Noctalia | Personal computer, for gaming and development. | +| `laptop` | x86_64 | NixOS | aaronv | Intel | niri + Noctalia | Personal laptop, for development. | +| `gpd` | x86_64 | NixOS (Jovian) | aaronv | AMD | niri + Noctalia | Handheld console, for gaming and occasionally development. | +| `mac` | aarch64 | macOS | aaronvargas | Apple Silicon | AeroSpace | Work computer. (Not implemented yet) | + ## Architecture +The flake is wired with `flake-parts` + `import-tree`. The framework lives in `anvil/`, the concrete configuration lives in `modules/` (each subdirectory is auto-imported as a flake module). + ``` -flake.nix — flake-parts + import-tree - └── modules/ - ├── configurations/ system-level config (boot, audio, networking, etc.) - ├── hosts/ machine definitions (hardware + preferences) - ├── profiles/ user identities (personal, work, vmtest) - ├── features/ capability toggles (development, gaming) - ├── programs/ program definitions + wrappers + scripts - └── wrapperModules/ low-level wrapper templates (kitty, ghostty, oh-my-posh) +flake.nix +├── anvil/ The framework, as glue code for nixos, home and darwin modules +│ ├── declarations/ Option schemas of the framework's entities +│ ├── lib/ Helper Functions +│ └── options/ The anvil namespace where the entities are defined: anvil.hosts / anvil.users / anvil.features / anvil.programs +└── modules/ My nixos configuration modules + ├── hosts/ + ├── users/ + ├── features/ + ├── programs/ + ├── declarations/ shared option schemas + ├── dotfiles/ config templates, scripts and configuration functions + └── secrets/ sops-encrypted secrets + wiring ``` -**Key insight**: Profiles control *who you are* (which features and programs are active), features control *what you can do*, and programs control *what tools you have* — all wired through a shared `preferences` option. +**Key concepts** + +- **Entities** — hosts, users, features and programs. Each has `name`, free-form `metadata`, optional lists of children (`features`, `programs`, `users`) and per-platform fragments `nixos` / `darwin` / `home`. +- **Fragments** — a fragment is a NixOS/nix-darwin/home-manager module merged into every target that enables its entity. Hosts without a fragment just aggregate the fragments of their features/programs/users. +- **Refkeys** — children can be referenced by a plain string (`"gaming"`) or a refkey submodule `{ ref, variant, merge, override }` to select a variant or tweak an entity for a single consumer. Lists (and fragments) can also be *functions* of the context `{ host, user, program, feature }`, so a feature can, for example, read `host.metadata.mainUser`. +- **Generation** — each host's `systems.` entry (a system string or `{ system = alias; }`) yields an output. `self.lib.mkHosts` collects the host's own fragment plus the fragments of every enabled feature, program and user (deduplicated by `name` / `name@variant`) and builds `nixosConfigurations`, `darwinConfigurations` and `homeConfigurations`. +- **Context injection** — `self.lib.withContext ctx` injects the entity context into fragments, so configs stay generic and adapt to who's running them. +- **Wrappers & dotfiles** — `self.wrappers..wrap` produces a configured package from `nix-wrapper-modules`; `self.dotfiles..default` returns the config text used by those wrappers (and home-manager). The shared theme comes from `self.lib.getColors`. + +The split mirrors intent: **host/user** define *who you are*, **features** what *you can do*, **programs** what *tools you have*. ## Quick Start -```sh -# Clone and enter -git clone https://github.com/aaron70/nix && cd nix +> Note: `.envrc` (direnv) ships with the repo but the flake currently defines no `devShell`, so `direnv allow` has no effect for now. -# Unlock encrypted profiles (if you have the key) -git-crypt unlock /path/to/key +The shell installs host-specific aliases (baked for the host you're on, pointing at `host.metadata.nixPath`): -# Build and switch for a specific host (NixOS) -sudo nixos-rebuild switch --flake .#pc +| Alias | Runs | +|-------|------| +| `nswitch` | `nh os switch -H ` | +| `ntest` | `nh os test -H ` | +| `nboot` | `nh os boot -H ` | +| `nbuild-vm` | `nh os build-vm -H ` | +| `nclean` | `nh clean all --optimise -k ` | +| `nshell` | `nix-shell --command -p` | -# Or using nh (recommended) -nh os switch --host pc . +Manually (e.g. from a machine without the aliases): -# For macOS -darwin-rebuild switch --flake .#mac +```sh +# Rebuild and switch (daily driver) +sudo nixos-rebuild switch --flake .#pc # pc | laptop | gpd +darwin-rebuild switch --flake .#mac # once implemented -# Update flake inputs -nix flake update +# Update inputs +nix flake update # all inputs +nix flake lock --update-input nixpkgs # a single input -# Clean old generations -nh clean all --keep 3 +# Format all files (alejandra) +nix fmt ``` +## Workflows + +**Test a change in a VM** + +`nbuild-vm` boots the host in a QEMU VM. It uses `virtualisation.vmVariant`, which forces the password secret off and sets a fixed `initialPassword = "anvil"` (see `modules/users/aaronv.nix`). + +**Add a new host** + +1. Create `modules/hosts/.nix` declaring `anvil.hosts.` — `systems.nixos`, `users`, `features`, `programs`, `metadata` and the `nixos` fragment — plus a `-hardware` nixosModule. +2. Register the machine's age key in `.sops.yaml` (see [Secrets](#security)). +3. Build: `sudo nixos-rebuild switch --flake .#`. + +**Add a feature or program** + +- `modules/features/.nix` → `anvil.features.` with `nixos` / `darwin` / `home` fragments; it can pull in programs and other features. +- `modules/programs/.nix` → `anvil.programs.` with `getPackage` and fragments. + +Reference it by name (or a refkey) from any entity. The `modules/` import-tree automatically registers it with the flake options. + +**Add a user** + +Create `modules/users/.nix` → `anvil.users.` with its `nixos` / `darwin` / `home` fragments, then attach it on the host via `users = [...]`. + ## Security -### Git Crypt +### Secrets + +Secrets use [sops-nix](https://github.com/Mic92/sops-nix) with age. -To keep some sensitive files protected, **git-crypt** is used to encrypt and decrypt the files. +- On first activation each host generates its own age keypair at `/path/to/key.txt` (`sops.age.generateKey = true`); `SOPS_AGE_KEY_FILE` points there. +- `.sops.yaml` lists an admin key (`personal_admin`) plus one key per device (`pc`, `laptop`, `gpd`). A device can only *decrypt* (and edit) secrets if its public key appears in that file. +- `modules/secrets/personal.yaml` holds the encrypted secrets (`email`, `password`), wired by the `personal-secrets` feature: + - `password` → the user's `hashedPasswordFile`. + - git's `user.name` / `user.email` are rendered through `sops.templates."gitconfig-personal"` (see `modules/programs/git.nix`). +`age` and `sops` are installed on every host and the `sops` feature already exports `SOPS_AGE_KEY_FILE=/path/to/key.txt`, so these commands work out of the box on a managed host. The prefix is only needed when running outside a host that doesn't set it. -[git-crypt](https://github.com/AGWA/git-crypt) transparently encrypts and decrypts files when pushed or checked out. +**Commands** ```sh -# Export the private key -git-crypt export-key /path/to/key +# Edit a secret (opens your $EDITOR on the decrypted file) +SOPS_AGE_KEY_FILE=/path/to/key.txt sops modules/secrets/personal.yaml -# Unlock encrypted files with the exported key -git-crypt unlock /path/to/key +# Set a single value (no editor) +SOPS_AGE_KEY_FILE=/path/to/key.txt sops set modules/secrets/personal.yaml '["password"]' '' -# Encrypt the files again -git-crypt lock -``` +# Read/verify without touching the file +SOPS_AGE_KEY_FILE=/path/to/key.txt sops -d modules/secrets/personal.yaml +SOPS_AGE_KEY_FILE=/path/to/key.txt sops -d --extract '["email"]' modules/secrets/personal.yaml -## Maintenance +# Give a new device access: +age-keygen -o /tmp/key.txt # 1. generate a keypair +age-keygen -y /tmp/key.txt # 2. prints its public key -> age1... +# 3. add `- & age1...` under `keys:` and `- *` in the +# creation rule of `.sops.yaml` +SOPS_AGE_KEY_FILE=/path/to/key.txt sops updatekeys modules/secrets/personal.yaml # 4. re-encrypt with the new recipient set -### Update Noctalia Plugins +# Rotate the data key (re-encrypts in place) +SOPS_AGE_KEY_FILE=/path/to/key.txt sops -r -i modules/secrets/personal.yaml +``` -Get the commit hash from the latest commit on the [Plugins Repository](https://github.com/noctalia-dev/noctalia-plugins/commits/main) and replace it on the `fetchgit` function, then use `sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=` as the **sha256** and run the configuration — it will fail and give you the real **sha256**. +If a machine can't decrypt (e.g. git user/email missing), its key likely isn't in `.sops.yaml` yet — see [Troubleshooting](#troubleshooting). ## Troubleshooting +### No git user and email + +Git's `user.name` / `user.email` come from the sops-rendered `gitconfig-personal` template. If they're missing, the secrets are not being decrypted — make sure this device's age key is registered in `.sops.yaml` (see [Secrets](#security)) and rebuild. + ### No audio on headsets Open `pavucontrol` or `Bluetooth Manager` and change the audio profile. Currently works with `High Fidelity Playback (A2DP Sink, codec AAC)`. ### Setup the monitors position -`wdisplays` is installed for setting up monitor positions. Set the positions within the application and then copy the values into the niri configuration. - -### Git Credentials broken - -If NixOS rebuilds `gh`, the git credentials configuration might break since it may still point to the old `gh` path. -To fix it, run `gh auth setup-git`. +`wdisplays` is installed for setting up monitor positions. Set the positions within the application and then copy the values into `anvil.desktop.preferences.monitors` in the host's module (`modules/hosts/.nix`). diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 08c7719..0000000 --- a/TODO.md +++ /dev/null @@ -1,29 +0,0 @@ -- [x] Gargabe Collection service - - [x] Run nh clean periodically - - [x] Works for Nixos, Darwin and HomeManager -- [x] Cursor Theme (Seems like it needs HomeManager, I don't know if its worth it) -- [x] Darwing Configurations -- [x] HomeManager Configurations -- [x] HomeManager Modules -- [x] Development Feature - - [x] Programming languages: Go, Java, Javascript, Rust and Python - - [x] Docker -- [x] Feature Gaming - - [x] Games and launchers - - [x] Discord - - [x] Jovian for GPD -- [x] Fix the color on oh-my-posh prompt when there is a pending pull or push on a repository -- [x] Remove the notification about Noctalia plugins -- [x] Fix the nswitch, ntest, nbuid-vm, nclean and nshell -- [x] Rewrite Neovim configurations with wrapper? -- [/] Install atuin -- [x] Apply the quality of life improvements from [here](https://nixos.wiki/wiki/Jovian_NixOS) -- [x] Avoid mouse hanging out after a few seconds -- [/] Fix nix packages, can't be executed with `nix run` because of the crypted profiles -- [x] gx doesn't work for file references, only https links (Neovim) -- [x] Add an emoji picker (Noctalia already has a emoji picker, open the launcher and write /emo) -- [x] Add another keyboard lang ES -- [x] Nixos search packages -- [/] Maybe create a MS Teams desktop entry for the web app? () -- [x] Open clipboard history with mod+v -- [/] Try [Noctalia-greeter](https://github.com/noctalia-dev/noctalia-greeter) diff --git a/anvil/declarations/entity.nix b/anvil/declarations/entity.nix new file mode 100644 index 0000000..418d112 --- /dev/null +++ b/anvil/declarations/entity.nix @@ -0,0 +1,47 @@ +{ + self, + lib, + ... +}: +with lib; let + refKeyListType = self.lib.refkeyListType; +in { + flake.modules.generic.entity = { + imports = [self.modules.generic.fragments]; + options = { + name = mkOption { + type = types.nullOr types.str; + default = null; + description = "Host name. Defaults to the attribute name when unset."; + }; + + metadata = mkOption { + type = types.attrsOf types.anything; + default = {}; + description = '' + Free-form attrSet metadata, any fields. Accessible from this + entity's fragments via the context (e.g. `host.metadata` or + `user.metadata`). + ''; + }; + + features = mkOption { + type = types.either (types.functionTo refKeyListType) refKeyListType; + default = []; + description = '' + A list of features to enable on the entity. Each item can be a string + feature name or a refkey submodule reference. + ''; + }; + + programs = mkOption { + type = types.either (types.functionTo refKeyListType) refKeyListType; + default = []; + description = '' + A list of programs to enable on the entity. Each item can be a string + program name or a refkey submodule reference. + ''; + }; + }; + }; +} diff --git a/anvil/declarations/feature.nix b/anvil/declarations/feature.nix new file mode 100644 index 0000000..af2c5d8 --- /dev/null +++ b/anvil/declarations/feature.nix @@ -0,0 +1,13 @@ +{ + self, + lib, + ... +}: +with lib; { + flake.modules.generic.feature = { + imports = [ + self.modules.generic.entity + self.modules.generic.variants + ]; + }; +} diff --git a/anvil/declarations/fragments.nix b/anvil/declarations/fragments.nix new file mode 100644 index 0000000..5099193 --- /dev/null +++ b/anvil/declarations/fragments.nix @@ -0,0 +1,33 @@ +{lib, ...}: +with lib; { + flake.modules.generic.fragments = { + options = { + nixos = mkOption { + type = types.nullOr types.deferredModule; + default = null; + description = '' + NixOS fragment for this entity. `null` when unset; merged into + the targets that enable it. + ''; + }; + + darwin = mkOption { + type = types.nullOr types.deferredModule; + default = null; + description = '' + Darwin fragment for this entity. `null` when unset; merged into + the targets that enable it. + ''; + }; + + home = mkOption { + type = types.nullOr types.deferredModule; + default = null; + description = '' + Home fragment for this entity. `null` when unset; merged into + the targets that enable it. + ''; + }; + }; + }; +} diff --git a/anvil/declarations/host.nix b/anvil/declarations/host.nix new file mode 100644 index 0000000..ed9c352 --- /dev/null +++ b/anvil/declarations/host.nix @@ -0,0 +1,96 @@ +{ + self, + lib, + ... +}: +with lib; let + refKeyListType = self.lib.refkeyListType; +in { + flake.modules.generic.host = { + imports = [self.modules.generic.entity]; + options = { + users = mkOption { + type = refKeyListType; + default = []; + description = '' + Users attached to this host. Each attached user's fragments + merge into this host's targets of the matching selector, + evaluated with the user's own context. Hosts with an empty list + are valid: users are optional and only add per-user fragments. + ''; + }; + + stateVersion = mkOption { + type = types.str; + default = "26.11"; + description = '' + NixOS/home-manager stateVersion, injected into every nixos and + home target of this host with default priority, so a fragment can + override it. Darwin targets use `darwinStateVersion` instead + (nix-darwin's stateVersion is an integer counter, not a release + string). + ''; + }; + + darwinStateVersion = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Darwin stateVersion, injected into every darwin target of this + host with default priority, so a fragment can override it. + nix-darwin's `system.stateVersion` is an integer counter, not a + release string. When unset, the current max is injected (the + value nix-darwin recommends for new installations); set an + integer to pin an older value. The value must not exceed + nix-darwin's current `system.maxStateVersion`, or evaluation fails with a type error. + ''; + }; + + systems = mkOption { + type = types.submodule { + options = { + nixos = mkOption { + type = types.nullOr (types.either types.str (types.attrsOf types.str)); + default = null; + description = '' + NixOS targets: a system string, or a mapping from system to + output name for multiple targets. A plain string produces a + single `nixosConfigurations` named after the host. Required + (non-null) when the host declares a `nixos` fragment. + ''; + }; + + darwin = mkOption { + type = types.nullOr (types.either types.str (types.attrsOf types.str)); + default = null; + description = '' + Darwin targets: a system string, or a mapping from system to + output name for multiple targets. A plain string produces a + single `darwinConfigurations` named after the host. Required + (non-null) when the host declares a `darwin` fragment. + ''; + }; + + home = mkOption { + type = types.nullOr (types.either types.str (types.attrsOf types.str)); + default = null; + description = '' + Home targets: a system string, or a mapping from system to + output name for multiple targets. A plain string produces a + single `homeConfigurations` named after the host. Required + (non-null) when the host declares a `home` fragment. + ''; + }; + }; + }; + default = {}; + description = '' + The system of each target this host produces, keyed by selector. + Every entry (or the plain string) yields one configuration output + for that selector, evaluated with the host's fragment of that + selector. + ''; + }; + }; + }; +} diff --git a/anvil/declarations/program.nix b/anvil/declarations/program.nix new file mode 100644 index 0000000..755808a --- /dev/null +++ b/anvil/declarations/program.nix @@ -0,0 +1,23 @@ +{ + self, + lib, + ... +}: +with lib; { + flake.modules.generic.program = { + imports = [ + self.modules.generic.entity + self.modules.generic.variants + ]; + + options = { + getPackage = mkOption { + type = types.functionTo types.package; + description = '' + Function producing this program's package. Takes free-form arguments + (e.g. `{pkgs, ...}`) and returns the package to install. + ''; + }; + }; + }; +} diff --git a/anvil/declarations/refkey.nix b/anvil/declarations/refkey.nix new file mode 100644 index 0000000..9371b1f --- /dev/null +++ b/anvil/declarations/refkey.nix @@ -0,0 +1,42 @@ +{ + self, + lib, + ... +}: +with lib; let + refkeyListType = types.listOf (types.either types.str (types.submodule {imports = [self.modules.generic.refkey];})); +in { + flake.lib.refkeyListType = types.either (types.functionTo refkeyListType) refkeyListType; + + flake.modules.generic.refkey = { + options = { + ref = mkOption { + type = types.str; + description = "The name of the referencing entity."; + }; + + variant = mkOption { + type = types.nullOr types.str; + description = "An optional string referencing a variant name. When set, the entity will use this variant's configuration."; + }; + + override = mkOption { + type = types.attrsOf types.anything; + default = {}; + description = '' + Free-form attrset that overrides the referenced entity's + properties; merged with the `merge` field. + ''; + }; + + merge = mkOption { + type = types.attrsOf types.anything; + default = {}; + description = '' + Free-form attrset merged into the referenced entity's + configuration; useful to override values. + ''; + }; + }; + }; +} diff --git a/anvil/declarations/user.nix b/anvil/declarations/user.nix new file mode 100644 index 0000000..d8b9eda --- /dev/null +++ b/anvil/declarations/user.nix @@ -0,0 +1,29 @@ +{ + self, + lib, + ... +}: +with lib; { + flake.modules.generic.user = { + imports = [self.modules.generic.entity]; + options = { + description = mkOption { + type = types.nullOr types.str; + default = null; + description = "Human-readable description of the user."; + }; + + homeDir.nixos = mkOption { + type = types.nullOr types.str; + default = null; + description = "The home directory path of the user for linux modules"; + }; + + homeDir.darwin = mkOption { + type = types.nullOr types.str; + default = null; + description = "The home directory path of the user for darwin modules"; + }; + }; + }; +} diff --git a/anvil/declarations/variants.nix b/anvil/declarations/variants.nix new file mode 100644 index 0000000..7dc1275 --- /dev/null +++ b/anvil/declarations/variants.nix @@ -0,0 +1,19 @@ +{ + self, + lib, + ... +}: +with lib; { + flake.modules.generic.variants = { + options = { + variants = mkOption { + type = types.attrsOf (types.submodule {imports = [self.modules.generic.entity];}); + default = {}; + description = '' + A set of variant modules, each accepting options similar to entity options. + Used to define multiple variant configurations for a flake. + ''; + }; + }; + }; +} diff --git a/anvil/lib/common.nix b/anvil/lib/common.nix new file mode 100644 index 0000000..4ee6c40 --- /dev/null +++ b/anvil/lib/common.nix @@ -0,0 +1,85 @@ +{ + self, + lib, + ... +}: +with lib; { + flake.lib.withContext = ctx: mod: let + unwrapPath = m: + if isPath m + then import m + else m; + unwrap = m': + if + isAttrs m' + && isList (m'.imports or null) + && length m'.imports == 1 + && all (k: k == "imports" || k == "_file" || k == "key") (attrNames m') + then head m'.imports + else m'; + unwrapMod = m: unwrapPath (unwrap (unwrap (unwrapPath m))); + wrap = fragment: + if isFunction fragment + then + { + config, + lib, + pkgs, + ... + } @ args: + fragment (ctx // removeAttrs args ["host" "user" "system"]) + else fragment; + in + if isList mod + then {imports = map (m: self.lib.withContext ctx (unwrapMod m)) mod;} + else wrap (unwrapMod mod); + + flake.lib.getPropertyOrDefault = attr: property: default: + if attr ? "${property}" && attr.${property} != null + then attr.${property} + else default; + + flake.lib.getVariant = entity: variant: let + unnamed = self.lib.getPropertyOrDefault entity "name" ""; + in + if entity ? variants && entity.variants ? "${variant}" + then let + v = entity.variants.${variant}; + in + if (v.name or null) == null + then v // {name = variant;} + else v + else throw "Anvil: Entity '${unnamed}' doesn't have variant '${variant}'."; + + flake.lib.resolveRefKey = refkey: resolver: let + name = + if isString refkey + then refkey + else (self.lib.getPropertyOrDefault refkey "ref" null); + entity = resolver name; + fragments = ["nixos" "darwin" "home"]; + in + if isString refkey + then entity + else let + variant = self.lib.getPropertyOrDefault refkey "variant" null; + merge = self.lib.getPropertyOrDefault refkey "merge" {}; + override = self.lib.getPropertyOrDefault refkey "override" {}; + base = entity // override; + mergeFragments = filterAttrs (k: _: elem k fragments) merge; + mergeScalars = removeAttrs merge fragments; + composeFragment = key: fragment: let + baseFragment = base.${key} or null; + in + if baseFragment == null + then fragment + else if fragment == null + then baseFragment + else [baseFragment fragment]; + mergedFragments = mapAttrs composeFragment mergeFragments; + mergedEntity = (recursiveUpdate base mergeScalars) // mergedFragments; + in + if variant != null && mergedEntity ? variants + then self.lib.getVariant mergedEntity variant + else mergedEntity; +} diff --git a/anvil/lib/default.nix b/anvil/lib/default.nix new file mode 100644 index 0000000..a020a78 --- /dev/null +++ b/anvil/lib/default.nix @@ -0,0 +1,7 @@ +{lib, ...}: { + options.flake.lib = lib.mkOption { + type = lib.types.lazyAttrsOf lib.types.raw; + default = {}; + description = "Anvil's helper library, exposed as the flake output `lib`."; + }; +} diff --git a/anvil/lib/feature.nix b/anvil/lib/feature.nix new file mode 100644 index 0000000..f3d443f --- /dev/null +++ b/anvil/lib/feature.nix @@ -0,0 +1,68 @@ +{ + self, + config, + lib, + ... +}: +with lib; let + anvilFeatures = config.anvil.features; +in { + flake.lib.getFeature = parentType: parentName: name: + if anvilFeatures ? ${name} + then let + feature = anvilFeatures.${name}; + featureName = self.lib.getPropertyOrDefault feature "name" name; + in + if feature.name == null + then feature // {name = featureName;} + else feature + else throw "Anvil: ${parentType} '${parentName}' declares a not found feature '${name}'. Did you forget to set anvil.features.${name}?"; + + flake.lib.getFeaturesList = entity: ctx: + if isFunction entity.features + then entity.features ctx + else entity.features; + + flake.lib.getFeaturesModules = accumulator: platform: parentType: parent: ctx: features: let + acc = accumulator // {features = accumulator.features or {};}; + in + foldl + ( + acc: refkey: let + name = + if isString refkey + then refkey + else refkey.ref; + variant = + if isString refkey + then null + else self.lib.getPropertyOrDefault refkey "variant" null; + key = "${name}${ + if variant == null + then "" + else "@${variant}" + }"; + visited = acc.features ? "${key}"; + feature = self.lib.resolveRefKey refkey (self.lib.getFeature parentType parent.name); + localCtx = ctx // {inherit feature;}; + childrenPrograms = self.lib.getProgramsList feature localCtx; + childrenFeatures = self.lib.getFeaturesList feature localCtx; + newAcc = + if visited + then acc + else recursiveUpdate acc {features = {"${key}" = self.lib.withContext localCtx (self.lib.getPropertyOrDefault feature platform {});};}; + in + if visited + then newAcc + else + self.lib.getProgramsModules + (self.lib.getFeaturesModules newAcc platform parentType parent ctx childrenFeatures) + platform + parentType + parent + ctx + childrenPrograms + ) + acc + features; +} diff --git a/anvil/lib/host.nix b/anvil/lib/host.nix new file mode 100644 index 0000000..4be5a44 --- /dev/null +++ b/anvil/lib/host.nix @@ -0,0 +1,245 @@ +{ + inputs, + self, + lib, + config, + ... +}: +with lib; let + anvilHosts = config.anvil.hosts; +in { + flake.lib.getHost = name: + if anvilHosts ? ${name} + then anvilHosts.${name} + else throw "Anvil: Host '${name}' not found. Did you forget to set anvil.hosts.${name}?"; + + flake.lib.checkSystem = platform: system: name: + if ! (inputs.nixpkgs.legacyPackages ? ${system}) + then throw "anvil: host '${name}' declares unsupported system '${system}' for its ${platform} target" + else if platform == "nixos" && builtins.match ".*-darwin" system != null + then throw "anvil: host '${name}' declares a NixOS target on the non-Linux system '${system}'" + else if platform == "darwin" && builtins.match ".*-linux" system != null + then throw "anvil: host '${name}' declares a darwin target on the non-darwin system '${system}'" + else system; + + flake.lib.getHostSystemTargets = platform: hostName: host: let + systems = host.systems.${platform}; + name = self.lib.getPropertyOrDefault host "name" hostName; + targets = + if isString systems + then {${systems} = name;} + else systems; + in + if host.${platform} == null + then + if systems == null + then {} + else throw "anvil: host '${name}' sets anvil.hosts.${hostName}.systems.${platform} but declares no ${platform} fragment" + else if systems == null + then throw "anvil: host '${name}' has a ${platform} fragment but anvil.hosts.${hostName}.systems.${platform} is unset" + else if targets == {} + then throw "anvil: host '${name}' has a ${platform} fragment but anvil.hosts.${hostName}.systems.${platform} declares no target" + else if length (unique (attrValues targets)) != length (attrValues targets) + then throw "anvil: host '${name}' declares multiple ${platform} targets with the same output name" + else mapAttrs' (system: outName: nameValuePair (self.lib.checkSystem platform system name) outName) targets; + + flake.lib.mkHosts = platform: builder: let + hostTargets = + map + (hostName: let + host = self.lib.getHost hostName; + in { + inherit hostName; + targets = self.lib.getHostSystemTargets platform hostName host; + }) + (attrNames anvilHosts); + + byTarget = + zipAttrsWith (_: hosts: unique hosts) + (map ({ + hostName, + targets, + }: + mapAttrs' (_: outName: nameValuePair outName hostName) targets) + hostTargets); + + conflicts = + attrValues (mapAttrs (name: hosts: {inherit name hosts;}) + (filterAttrs (_: hosts: length hosts > 1) byTarget)); + in + if conflicts != [] + then + throw '' + anvil: Multiple hosts produce the same ${platform} configuration name: + ${concatMapStringsSep "\n" (c: " -> '${c.name}' is produced by: ${concatStringsSep ", " c.hosts}") conflicts} + If the hosts have the same name, you can set an alias for the configuration name by setting `systems.${platform} = { "" = "" };`. + '' + else + foldl' + (acc: { + targets, + hostName, + ... + }: let + host = self.lib.getHost hostName; + namedHost = + if host.name != null + then host + else host // {name = hostName;}; + in + acc // mapAttrs' (system: outName: nameValuePair outName (builder system namedHost)) targets) + {} + hostTargets; + + flake.lib.mkHostChecks = platform: configurations: mkCheck: suffix: let + hostTargets = + map + (hostName: let + host = self.lib.getHost hostName; + in { + inherit hostName; + targets = self.lib.getHostSystemTargets platform hostName host; + }) + (attrNames anvilHosts); + in + foldl' + (acc: {targets, ...}: + recursiveUpdate + acc + (mapAttrs' + (system: outName: nameValuePair system {${outName + suffix} = mkCheck configurations.${outName};}) + targets)) + {} + hostTargets; + + flake.lib.getHostModules = platform: host: let + ctx = {inherit host;}; + entityCtx = { + inherit host; + user = null; + }; + childrenPrograms = self.lib.getProgramsList host entityCtx; + childrenFeatures = self.lib.getFeaturesList host entityCtx; + childrenUsers = self.lib.getUsersList host entityCtx; + acc = + self.lib.getProgramsModules + (self.lib.getFeaturesModules {} platform "Host" host entityCtx childrenFeatures) + platform "Host" + host + entityCtx + childrenPrograms; + in + [ + (self.lib.withContext ctx (self.lib.getPropertyOrDefault host platform {})) + ] + ++ (self.lib.getUsersModules platform host childrenUsers) + ++ attrValues acc.features + ++ attrValues acc.programs; + + flake.lib.mkHomeManagerModule = platform: host: let + userRefs = self.lib.getUsersList host { + inherit host; + user = null; + }; + users = map (refkey: self.lib.resolveRefKey refkey (self.lib.getUser host)) userRefs; + usersModule = {...}: { + imports = + map (user: { + home-manager.users.${user.name} = { + imports = self.lib.getUserHomeModules host user; + config = { + programs.home-manager.enable = true; + home = { + username = user.name; + homeDirectory = mkDefault ( + if user.homeDir.${platform} == null + then + ( + if platform == "darwin" + then "/Users/${user.name}" + else "/home/${user.name}" + ) + else user.homeDir.${platform} + ); + stateVersion = host.stateVersion; + }; + }; + }; + }) + users; + }; + in + if users == [] + then {} + else if platform == "nixos" + then { + imports = [inputs.home-manager.nixosModules.default usersModule]; + config = { + home-manager.useGlobalPkgs = mkDefault true; + home-manager.useUserPackages = mkDefault true; + }; + } + else if platform == "darwin" + then { + imports = [ + inputs.home-manager.darwinModules.home-manager + usersModule + ]; + config = { + home-manager.useGlobalPkgs = mkDefault true; + home-manager.useUserPackages = mkDefault true; + }; + } + else throw "anvil: mkHomeManagerModule only supports 'nixos' or 'darwin', got '${platform}'"; + + flake.lib.mkNixosConfiguration = system: host: + inputs.nixpkgs.lib.nixosSystem { + inherit system; + modules = + [ + { + system.stateVersion = lib.mkDefault host.stateVersion; + } + ] + ++ [(self.lib.mkHomeManagerModule "nixos" host)] + ++ self.lib.getHostModules "nixos" host; + specialArgs = {}; + }; + + flake.lib.mkDarwinConfiguration = system: host: + inputs.nix-darwin.lib.darwinSystem { + inherit system; + modules = + [ + ({config, ...}: { + system.stateVersion = mkDefault ( + if host.darwinStateVersion == null + then config.system.maxStateVersion + else host.darwinStateVersion + ); + }) + ] + ++ [(self.lib.mkHomeManagerModule "darwin" host)] + ++ self.lib.getHostModules "darwin" host; + specialArgs = {}; + }; + + flake.lib.mkHomeConfiguration = system: host: + inputs.home-manager.lib.homeManagerConfiguration { + pkgs = inputs.nixpkgs.legacyPackages.${system}; + modules = + [ + { + home.stateVersion = lib.mkDefault host.stateVersion; + home.username = lib.mkDefault host.name; + home.homeDirectory = lib.mkDefault ( + if builtins.match ".*-darwin" system != null + then "/Users/${host.name}" + else "/home/${host.name}" + ); + } + ] + ++ self.lib.getHostModules "home" host; + extraSpecialArgs = {}; + }; +} diff --git a/anvil/lib/modules.nix b/anvil/lib/modules.nix new file mode 100644 index 0000000..5094b9b --- /dev/null +++ b/anvil/lib/modules.nix @@ -0,0 +1,19 @@ +{ + self, + lib, + ... +}: +with lib; { + flake.lib.installPackages = user: packages: ({...}: { + imports = [ + (self.lib.forUser user { + ${user.name}.packages = packages; + }) + ]; + environment.systemPackages = mkIf (user == null) packages; + }); + + flake.lib.forUser = user: attrSet: ({...}: { + users.users = mkIf (user != null) attrSet; + }); +} diff --git a/anvil/lib/program.nix b/anvil/lib/program.nix new file mode 100644 index 0000000..f1fe905 --- /dev/null +++ b/anvil/lib/program.nix @@ -0,0 +1,68 @@ +{ + self, + config, + lib, + ... +}: +with lib; let + anvilPrograms = config.anvil.programs; +in { + flake.lib.getProgram = parentType: parentName: name: + if anvilPrograms ? ${name} + then let + program = anvilPrograms.${name}; + programName = self.lib.getPropertyOrDefault program "name" name; + in + if program.name == null + then program // {name = programName;} + else program + else throw "Anvil: ${parentType} '${parentName}' declares a not found program '${name}'. Did you forget to set anvil.programs.${name}?"; + + flake.lib.getProgramsList = entity: ctx: + if isFunction entity.programs + then entity.programs ctx + else entity.programs; + + flake.lib.getProgramsModules = accumulator: platform: parentType: parent: ctx: programs: let + acc = accumulator // {programs = accumulator.programs or {};}; + in + foldl + ( + acc: refkey: let + name = + if isString refkey + then refkey + else refkey.ref; + variant = + if isString refkey + then null + else self.lib.getPropertyOrDefault refkey "variant" null; + key = "${name}${ + if variant == null + then "" + else "@${variant}" + }"; + visited = acc.programs ? "${key}"; + program = self.lib.resolveRefKey refkey (self.lib.getProgram parentType parent.name); + localCtx = ctx // {inherit program;}; + childrenPrograms = self.lib.getProgramsList program localCtx; + childrenFeatures = self.lib.getFeaturesList program localCtx; + newAcc = + if visited + then acc + else recursiveUpdate acc {programs = {"${key}" = self.lib.withContext localCtx (self.lib.getPropertyOrDefault program platform {});};}; + in + if visited + then newAcc + else + self.lib.getFeaturesModules + (self.lib.getProgramsModules newAcc platform parentType parent ctx childrenPrograms) + platform + parentType + parent + ctx + childrenFeatures + ) + acc + programs; +} diff --git a/anvil/lib/user.nix b/anvil/lib/user.nix new file mode 100644 index 0000000..15cb882 --- /dev/null +++ b/anvil/lib/user.nix @@ -0,0 +1,82 @@ +{ + self, + config, + lib, + ... +}: +with lib; let + anvilUsers = config.anvil.users; +in { + flake.lib.getUser = host: name: + if anvilUsers ? "${name}" + then let + user = anvilUsers.${name}; + userName = self.lib.getPropertyOrDefault user "name" name; + in + if user.name == null + then user // {name = userName;} + else user + else throw "Anvil: Host '${self.lib.getPropertyOrDefault host "name" ""}' declares a not found user '${name}'. Did you forget to set anvil.users.${name}?"; + + flake.lib.getUsersList = entity: ctx: + if isFunction entity.users + then entity.users ctx + else entity.users; + + flake.lib.getUserModules = platform: host: user: let + ctx = {inherit host user;}; + childrenPrograms = self.lib.getProgramsList user ctx; + childrenFeatures = self.lib.getFeaturesList user ctx; + acc = + self.lib.getProgramsModules + (self.lib.getFeaturesModules {} platform "User" user ctx childrenFeatures) + platform "User" + user + ctx + childrenPrograms; + in + (optional (user.${platform} != null) (self.lib.withContext ctx user.${platform})) + ++ attrValues acc.features + ++ attrValues acc.programs; + + flake.lib.getUsersModules = platform: host: users: + concatMap + ( + userName: let + user = self.lib.resolveRefKey userName (self.lib.getUser host); + in + self.lib.getUserModules platform host user + ) + users; + + flake.lib.getUserHomeModules = host: user: let + ctx = {inherit host user;}; + hostCtx = {inherit host;}; + hostAcc = + self.lib.getProgramsModules + (self.lib.getFeaturesModules + {} "home" "Host" + host + hostCtx (self.lib.getFeaturesList host hostCtx)) + "home" "Host" + host + hostCtx + (self.lib.getProgramsList host hostCtx); + acc = + self.lib.getProgramsModules + (self.lib.getFeaturesModules + hostAcc "home" "User" + user + ctx (self.lib.getFeaturesList user ctx)) + "home" "User" + user + ctx + (self.lib.getProgramsList user ctx); + in + [ + (self.lib.withContext hostCtx (self.lib.getPropertyOrDefault host "home" {})) + (self.lib.withContext ctx (self.lib.getPropertyOrDefault user "home" {})) + ] + ++ attrValues acc.features + ++ attrValues acc.programs; +} diff --git a/anvil/options/features.nix b/anvil/options/features.nix new file mode 100644 index 0000000..b1dfbd5 --- /dev/null +++ b/anvil/options/features.nix @@ -0,0 +1,12 @@ +{ + self, + lib, + ... +}: +with lib; { + options.anvil.features = mkOption { + type = types.attrsOf (types.submodule {imports = [self.modules.generic.feature];}); + default = {}; + description = "Features managed by anvil. Each is referenced via its refkey."; + }; +} diff --git a/anvil/options/hosts.nix b/anvil/options/hosts.nix new file mode 100644 index 0000000..8fbac62 --- /dev/null +++ b/anvil/options/hosts.nix @@ -0,0 +1,41 @@ +{ + self, + lib, + config, + ... +}: +with lib; { + options.anvil.hosts = mkOption { + type = types.attrsOf (types.submodule {imports = [self.modules.generic.host];}); + default = {}; + description = "Hosts managed by anvil. Each produces configurations for whichever fragments are set."; + }; + + config.flake.nixosConfigurations = self.lib.mkHosts "nixos" self.lib.mkNixosConfiguration; + config.flake.darwinConfigurations = self.lib.mkHosts "darwin" self.lib.mkDarwinConfiguration; + config.flake.homeConfigurations = self.lib.mkHosts "home" self.lib.mkHomeConfiguration; + config.flake.checks = + foldl' + (acc: platform: acc // (self.lib.mkHostChecks platform.platform platform.configurations platform.mkCheck platform.suffix)) + {} + [ + { + platform = "nixos"; + configurations = config.flake.nixosConfigurations; + mkCheck = c: c.config.system.build.toplevel; + suffix = ""; + } + { + platform = "darwin"; + configurations = config.flake.darwinConfigurations; + mkCheck = c: c.config.system.build.toplevel; + suffix = "-darwin"; + } + { + platform = "home"; + configurations = config.flake.homeConfigurations; + mkCheck = c: c.activationPackage; + suffix = "-home"; + } + ]; +} diff --git a/anvil/options/programs.nix b/anvil/options/programs.nix new file mode 100644 index 0000000..190c32a --- /dev/null +++ b/anvil/options/programs.nix @@ -0,0 +1,12 @@ +{ + self, + lib, + ... +}: +with lib; { + options.anvil.programs = mkOption { + type = types.attrsOf (types.submodule {imports = [self.modules.generic.program];}); + default = {}; + description = "Programs managed by anvil. Each is referenced via its refkey."; + }; +} diff --git a/anvil/options/users.nix b/anvil/options/users.nix new file mode 100644 index 0000000..43b63e0 --- /dev/null +++ b/anvil/options/users.nix @@ -0,0 +1,12 @@ +{ + self, + lib, + ... +}: +with lib; { + options.anvil.users = mkOption { + type = types.attrsOf (types.submodule {imports = [self.modules.generic.user];}); + default = {}; + description = "Users managed by anvil. Each is referenced by hosts via its refkey; its fragments merge into the targets of attaching hosts."; + }; +} diff --git a/flake.lock b/flake.lock index 11d5119..99240f3 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ ] }, "locked": { - "lastModified": 1782949081, - "narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=", + "lastModified": 1788450739, + "narHash": "sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e", + "rev": "31729ca8cbdb4fa927b34e5f4353e6a83f39e993", "type": "github" }, "original": { @@ -124,11 +124,11 @@ ] }, "locked": { - "lastModified": 1783963347, - "narHash": "sha256-r376E2XpakiXwModDHIxlvB6qLq4iFVEq730vxOO4JY=", + "lastModified": 1789695075, + "narHash": "sha256-HREFWgmCTp28ZdMkSFOW2QW8uI17v5CNc04W46h6aPo=", "owner": "nix-community", "repo": "home-manager", - "rev": "a45a7c451455a51ae740ec3bce4024b312809c29", + "rev": "4ac5a2ae9025eab1ebece4f9df8c315fd84a738a", "type": "github" }, "original": { @@ -140,11 +140,11 @@ }, "import-tree": { "locked": { - "lastModified": 1778781969, - "narHash": "sha256-Jjuz5CmSkur8KvLDoGa+vylEp+RkQtv4mt/qcMznpH0=", + "lastModified": 1788467110, + "narHash": "sha256-ljEMTXP/rH0tOvDzc9gzwww6KcHRPRnEHzd9lK48V7s=", "owner": "vic", "repo": "import-tree", - "rev": "d321337efd0f23a9eb14a42adb7b2c29313ab274", + "rev": "eb1b52eaecc57f7c136d07ae8a93e724dfecac46", "type": "github" }, "original": { @@ -174,11 +174,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1783616501, - "narHash": "sha256-kzxvD/qP4CZHFRuszPw0fr5N2Q7/1OxT5DBs2ERx/2Q=", + "lastModified": 1789448720, + "narHash": "sha256-AaPN5C72h8nGp+2UJVSX0RobTtUacFHTWEr+dMn4xc0=", "owner": "Jovian-Experiments", "repo": "Jovian-NixOS", - "rev": "eb1d4e013417487d515db93fafcd3e75c9e0f843", + "rev": "e2647dadda77487caba8055556dedde2e0448d83", "type": "github" }, "original": { @@ -217,11 +217,11 @@ ] }, "locked": { - "lastModified": 1783395956, - "narHash": "sha256-AAbexQvDoK+6GFJdhY6kqjA+6ECKRkidgWxkn4gMwAA=", + "lastModified": 1786845137, + "narHash": "sha256-oQFip+v0luP8NIxJzmiW4Wu8bILsbFWom5l0zonl8hQ=", "owner": "nix-darwin", "repo": "nix-darwin", - "rev": "d5bd9cd77aea4c0a8f49e7fd85545671a208ed15", + "rev": "4cff07de74b50e64bdd68cd4e722ab5b6b35ee48", "type": "github" }, "original": { @@ -255,11 +255,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1781074563, - "narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=", + "lastModified": 1787498568, + "narHash": "sha256-9i/VTdusq/+NM/tz+J1Re+ojkMB8MBf0QshnYfzHz30=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca", + "rev": "56c02bc00adcf003215cc4bd996d6efaf4cff188", "type": "github" }, "original": { @@ -350,11 +350,11 @@ }, "nixpkgs_6": { "locked": { - "lastModified": 1784007870, - "narHash": "sha256-djcLt/JJphyNt4eDY9XTly+/WbCK5lqWq9lSgCmJkkQ=", + "lastModified": 1789546076, + "narHash": "sha256-zVxLZiSnmaaPLwnhj7pwmqe3axBg/C6nG5JZsJMh2g4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "18b9261cb3294b6d2a06d03f96872827b8fe2698", + "rev": "b1b875982b17dabde9b4a37f3e229e74913e6db3", "type": "github" }, "original": { @@ -380,6 +380,22 @@ "type": "github" } }, + "nixpkgs_8": { + "locked": { + "lastModified": 1769089682, + "narHash": "sha256-9yA/LIuAVQq0lXelrZPjLuLVuZdm03p8tfmHhnDIkms=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "078d69f03934859a181e81ba987c2bb033eebfc5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, "noctalia": { "inputs": { "nixpkgs": [ @@ -387,11 +403,11 @@ ] }, "locked": { - "lastModified": 1784556533, - "narHash": "sha256-tlcP2x7d+ldS3BypTcInqrsOhi6BPuSSTeubfBMmm8Y=", + "lastModified": 1789611680, + "narHash": "sha256-obiNV+juEjUYDDusgYQukjLyoVsJJPmYppmjvIEfkSg=", "owner": "noctalia-dev", "repo": "noctalia-shell", - "rev": "815635cf7dc810616c9e6ecf4b9b4f4c54e69905", + "rev": "8c52cb71b5bcafbf67bfb8e659f1fc45f882a008", "type": "github" }, "original": { @@ -408,11 +424,11 @@ "wrappers": "wrappers" }, "locked": { - "lastModified": 1783809924, - "narHash": "sha256-uNbFHQ3Ce9zPBWCMnRZfDedbWEXHdKXE4tLTH9qXHLw=", + "lastModified": 1788222738, + "narHash": "sha256-lp0gbNAfKSU1da7YCAYFA/jN8gnUgf536Aijkzo3Slg=", "owner": "aaron70", "repo": "nvim", - "rev": "4d92dbb328cbfe94091cff36e57ba0ed0c4e45d0", + "rev": "b34108524c41693870ea1c05e987f6dce8ed4173", "type": "github" }, "original": { @@ -432,10 +448,53 @@ "nixpkgs": "nixpkgs_6", "noctalia": "noctalia", "nvim": "nvim", + "sops-nix": "sops-nix", "wrappers": "wrappers_2", + "xwayland-satellite-stable": "xwayland-satellite-stable", "zen-browser": "zen-browser" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "xwayland-satellite-stable", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769222645, + "narHash": "sha256-gu6oZ86zLudBZMq8LL1qdtYt/S69GV5keQVXdvBrVSU=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "22da29e7f3d8cff75009cbbcf992c7cb66920cfd", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1789691124, + "narHash": "sha256-k+I+R6uwHX3VcJ7326qLV6vCahZUgsVl+i8sSU/Stxk=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "1e73e8f7176d65e1b55e324de099bbfff4b2c574", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + }, "systems": { "locked": { "lastModified": 1681028828, @@ -530,11 +589,11 @@ ] }, "locked": { - "lastModified": 1782135443, - "narHash": "sha256-vAmbArdCyjqpVW+37aCy/PMBOLIqukUXLQuEKLwUhA4=", + "lastModified": 1788981141, + "narHash": "sha256-7xWS16u13YGlRNKWaAPzRbEyh4OLOXJe31k7h4AnXNU=", "owner": "BirdeeHub", "repo": "nix-wrapper-modules", - "rev": "6e7f66fa2cdf4d63162580b438f7fcf87c28a46f", + "rev": "1db3c116a6aa61823f8d8f3c47c306846428fc54", "type": "github" }, "original": { @@ -543,6 +602,26 @@ "type": "github" } }, + "xwayland-satellite-stable": { + "inputs": { + "nixpkgs": "nixpkgs_8", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1771195969, + "narHash": "sha256-BUE41HjLIGPjq3U8VXPjf8asH8GaMI7FYdgrIHKFMXA=", + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "rev": "536bd32efc935bf876d6de385ec18a1b715c9358", + "type": "github" + }, + "original": { + "owner": "Supreeeme", + "ref": "v0.8.1", + "repo": "xwayland-satellite", + "type": "github" + } + }, "zen-browser": { "inputs": { "nixpkgs": [ @@ -550,11 +629,11 @@ ] }, "locked": { - "lastModified": 1783668749, - "narHash": "sha256-EDJjJYGT5pQKTBqmz+OA2sqE20kjj6mP699JFGDzse4=", + "lastModified": 1789636270, + "narHash": "sha256-sexm8hHHB2jOB/G70czjQxdxeX68zID6G1BomFIGI+w=", "owner": "youwen5", "repo": "zen-browser-flake", - "rev": "e8041a3571e8cadb57dc18a3d6362d753510b94a", + "rev": "9c1767f705262bf08498877fd1053b6a6db12a9f", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 0dc7f14..17ead84 100644 --- a/flake.nix +++ b/flake.nix @@ -26,13 +26,21 @@ noctalia.inputs.nixpkgs.follows = "nixpkgs"; jovian.url = "github:Jovian-Experiments/Jovian-NixOS"; + + sops-nix.url = "github:Mic92/sops-nix"; + sops-nix.inputs.nixpkgs.follows = "nixpkgs"; + + # TODO: Remove this when the following issue is fixed: https://github.com/ValveSoftware/steam-for-linux/issues/13566 + # TODO: remove the overlay from steam program as well + xwayland-satellite-stable.url = "github:Supreeeme/xwayland-satellite/v0.8.1"; }; outputs = inputs: inputs.flake-parts.lib.mkFlake {inherit inputs;} { - systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"]; + systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin"]; imports = [ (inputs.import-tree ./modules) + (inputs.import-tree ./anvil) inputs.wrappers.flakeModules.wrappers inputs.flake-parts.flakeModules.modules inputs.home-manager.flakeModules.home-manager diff --git a/modules/configurations/bluetooth.nix b/modules/configurations/bluetooth.nix deleted file mode 100644 index f43c0e3..0000000 --- a/modules/configurations/bluetooth.nix +++ /dev/null @@ -1,20 +0,0 @@ -{lib, ...}: -with lib; { - flake.nixosModules.configurations = {config, ...}: { - config = mkIf config.information.hasBluetooth { - services.blueman.enable = true; - - hardware.enableAllFirmware = true; - hardware.bluetooth = { - enable = true; - powerOnBoot = true; - settings = { - General = { - Name = "${config.profile.user.username}-${config.information.hostname}"; - Experimental = true; - }; - }; - }; - }; - }; -} diff --git a/modules/configurations/boot.nix b/modules/configurations/boot.nix deleted file mode 100644 index 7670aec..0000000 --- a/modules/configurations/boot.nix +++ /dev/null @@ -1,36 +0,0 @@ -{lib, ...}: -with lib; { - flake.nixosModules.configurations = { - pkgs, - config, - ... - }: { - config = { - boot = { - # Quiet boot - consoleLogLevel = 0; - initrd.verbose = false; - - kernelParams = [ - "quiet" - "loglevel=3" - "rd.systemd.show_status=false" - "rd.udev.log_level=3" - "udev.log_priority=3" - ]; - kernelModules = ["ddcci-backlight"]; - kernelPackages = pkgs.linuxPackages_latest; - extraModulePackages = with config.boot.kernelPackages; [ddcci-driver]; - - loader.systemd-boot = { - enable = mkDefault true; - configurationLimit = mkDefault config.preferences.boot.configurationLimit; - }; - loader.efi.canTouchEfiVariables = true; - loader.timeout = 30; - - plymouth.enable = true; - }; - }; - }; -} diff --git a/modules/configurations/configurations.nix b/modules/configurations/configurations.nix deleted file mode 100644 index e4ad6dd..0000000 --- a/modules/configurations/configurations.nix +++ /dev/null @@ -1,125 +0,0 @@ -{ - self, - lib, - ... -}: -with lib; { - flake.nixosModules.configurations = { - pkgs, - config, - ... - }: { - imports = [ - self.nixosModules.profile - self.nixosModules.programs - self.nixosModules.features - ]; - - config = { - nix.settings.experimental-features = ["nix-command" "flakes"]; - nixpkgs.config.allowUnfree = true; - nixpkgs.config.allowBroken = true; - programs.nix-ld.enable = true; - - services.xserver.videoDrivers = ["nvidia"]; - hardware = { - i2c.enable = true; - graphics = { - enable = true; - enable32Bit = true; - }; - nvidia = { - # Enable modesetting for Wayland compositors - modesetting.enable = true; - # Use the open source version of the kernel module (for driver 515.43.04+) - open = true; - # Enable the Nvidia settings menu - nvidiaSettings = true; - # Select the appropriate driver version for your specific GPU - package = config.boot.kernelPackages.nvidiaPackages.stable; - powerManagement.enable = true; - }; - }; - - virtualisation.vmVariant = { - virtualisation.graphics = true; - virtualisation.qemu.options = [ - "-device virtio-vga-gl" - "-display gtk,gl=on" - ]; - }; - - services.printing.enable = true; - - services.pulseaudio.enable = false; - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - # To use JACK applications - # jack.enable = true; - }; - - networking.networkmanager.enable = true; - networking.hostName = config.profile.user.username; - # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. - - time.timeZone = mkDefault "America/Costa_Rica"; - - # Select internationalisation properties. - i18n.defaultLocale = mkDefault "en_US.UTF-8"; - i18n.extraLocaleSettings = mkDefault { - LC_ADDRESS = "es_CR.UTF-8"; - LC_IDENTIFICATION = "es_CR.UTF-8"; - LC_MEASUREMENT = "es_CR.UTF-8"; - LC_MONETARY = "es_CR.UTF-8"; - LC_NAME = "es_CR.UTF-8"; - LC_NUMERIC = "es_CR.UTF-8"; - LC_PAPER = "es_CR.UTF-8"; - LC_TELEPHONE = "es_CR.UTF-8"; - LC_TIME = "es_CR.UTF-8"; - }; - - services.xserver.xkb = { - layout = "us"; - variant = ""; - options = "compose:ralt"; - }; - environment.variables = { - GTK_IM_MODULE = "xim"; - QT_IM_MODULE = "xim"; - }; - - security.polkit.enable = true; - security.polkit.enablePkexecWrapper = true; - # environment.systemPackages = [pkgs.polkit_gnome]; NOTE: Using the built-in noctalia polkit-agent - services.fprintd.enable = true; - - services.gnome.gnome-keyring.enable = true; - security.pam.services.greetd.enableGnomeKeyring = true; - - - - services.logind.settings.Login = { - HandleLidSwitch = "suspend"; # Lid Closed - HandleLidSwitchExternalPower = "suspend"; # Lid Closed while connected to power - HandleLidSwitchDocked = "ignore"; # Lic Closed while connected to another screens - }; - # one of "ignore", "poweroff", "reboot", "halt", "kexec", "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate", "lock" - - # Faster rebuilding - documentation = { - enable = true; - doc.enable = false; - man.enable = true; - dev.enable = false; - info.enable = false; - nixos.enable = false; - }; - - system.stateVersion = config.preferences.stateVersion; - }; - }; -} diff --git a/modules/configurations/darwin.nix b/modules/configurations/darwin.nix deleted file mode 100644 index 375cc6b..0000000 --- a/modules/configurations/darwin.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ - self, - inputs, - lib, - ... -}: -with lib; { - options = { - flake = inputs.flake-parts.lib.mkSubmoduleOptions { - darwinModules = mkOption { - type = types.lazyAttrsOf types.deferredModule; - default = {}; - }; - }; - }; - - config.flake.darwinModules.configurations = {config, ...}: { - imports = [ - inputs.mac-app-util.darwinModules.default - self.darwinModules.profile - self.darwinModules.programs - self.darwinModules.features - ]; - - config = { - nix.settings.experimental-features = "nix-command flakes"; - system.configurationRevision = inputs.self.rev or inputs.self.dirtyRev or null; - # TODO: Remove this line and uncomment the following - # system.stateVersion = "25.11"; - system.stateVersion = 6; - nixpkgs.config.allowUnfree = true; - nixpkgs.config.allowBroken = true; - - networking.hostName = config.profile.user.username; - - system.primaryUser = config.profile.user.username; - launchd.user.envVariables = { - PATH = config.environment.systemPath; - }; - - # TODO: Remove this one - # virtualisation.vmVariant = { - # virtualisation.graphics = true; - # virtualisation.qemu.options = [ - # "-device virtio-vga-gl" - # "-display gtk,gl=on" - # ]; - # }; - }; - }; -} diff --git a/modules/configurations/gc.nix b/modules/configurations/gc.nix deleted file mode 100644 index 73664de..0000000 --- a/modules/configurations/gc.nix +++ /dev/null @@ -1,76 +0,0 @@ -{lib, ...}: -with lib; { - flake.nixosModules.configurations = { - config, - pkgs, - ... - }: { - config = let - notify = user: msg: - "${pkgs.sudo}/bin/sudo -u ${user} " - + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(${pkgs.coreutils}/bin/id -u ${user})/bus " - + "${pkgs.libnotify}/bin/notify-send ${lib.escapeShellArg msg}"; - username = config.profile.user.username; - in { - systemd.services.gc-periodic = { - enable = true; - description = "Periodic nix store cleanup"; - path = [config.nix.package]; - serviceConfig = { - Type = "oneshot"; - ExecStartPre = pkgs.writeShellScript "notify-start" '' - ${notify username "Starting nix store cleanup..."} - ''; - ExecStart = pkgs.writeShellScript "gc-clean" '' - set -e - ${getExe pkgs.nh} clean all --optimise -k ${toString config.preferences.boot.configurationLimit} - ''; - ExecStartPost = pkgs.writeShellScript "notify-done" '' - ${notify username "Nix store cleanup complete"} - ''; - TimeoutStopSec = "5min"; - }; - }; - - systemd.timers.gc-periodic = { - enable = true; - description = "Timer for periodic nix store cleanup via nh"; - wantedBy = ["timers.target"]; - timerConfig = { - OnCalendar = "weekly"; - Persistent = true; - RandomizedDelaySec = "30min"; - }; - }; - }; - }; - - flake.darwinModules.configurations = { - config, - pkgs, - ... - }: { - config = { - launchd.daemons.gc-periodic = { - serviceConfig = { - ProgramArguments = [ - "${pkgs.writeShellScript "gc-clean-darwin" '' - set -e - export PATH="${config.nix.package}/bin:${pkgs.nh}/bin:$PATH" - ${getExe pkgs.nh} clean all --optimise -k ${toString config.preferences.boot.configurationLimit} - ''}" - ]; - StartCalendarInterval = [ - { - Weekday = 1; - Hour = 7; - Minute = 30; - } # Monday 7:30am - ]; - StandardOutPath = "/var/log/gc-periodic.log"; - StandardErrorPath = "/var/log/gc-periodic.log"; - }; - }; - }; - }; -} diff --git a/modules/configurations/home.nix b/modules/configurations/home.nix deleted file mode 100644 index 5a3d9e9..0000000 --- a/modules/configurations/home.nix +++ /dev/null @@ -1,90 +0,0 @@ -{ - inputs, - self, - lib, - ... -}: -with lib; { - flake.nixosModules.configurations = {config, ...}: { - imports = [inputs.home-manager.nixosModules.default]; - - config = { - home-manager.users.${config.profile.user.username} = {...}: { - imports = [ - self.homeModules.configurations - self.homeModules.profile - self.homeModules.programs - self.homeModules.features - ]; - config = { - preferences.profile = mkDefault config.preferences.profile; - preferences.programs = mkDefault config.preferences.programs; - programs.home-manager.enable = true; - home = { - username = config.profile.user.username; - homeDirectory = mkDefault "/home/${config.profile.user.username}"; - stateVersion = config.preferences.stateVersion; - - file.".XCompose".text = '' - include "%L" - - # Acute accents (mimics macOS Option+e then vowel) - : "á" - : "é" - : "í" - : "ó" - : "ú" - : "Á" - : "É" - : "Í" - : "Ó" - : "Ú" - - # Tilde (mimics macOS Option+n then n) - : "ñ" - : "Ñ" - - # Diaeresis - : "ü" - : "Ü" - - # Inverted punctuation - : "¡" - : "¿" - ''; - }; - }; - }; - }; - }; - - flake.darwinModules.configurations = { - config, - pkgs, - ... - }: { - imports = [inputs.home-manager.darwinModules.home-manager]; - - config = { - home-manager.users.${config.profile.user.username} = {...}: { - imports = [ - inputs.mac-app-util.homeManagerModules.default - self.homeModules.configurations - self.homeModules.profile - self.homeModules.programs - self.homeModules.features - ]; - config = { - preferences.profile = mkDefault config.preferences.profile; - preferences.programs = mkDefault config.preferences.programs; - programs.home-manager.enable = true; - home = { - username = config.profile.user.username; - homeDirectory = mkDefault /Users/${config.profile.user.username}; - stateVersion = config.preferences.stateVersion; - }; - }; - }; - }; - }; -} diff --git a/modules/configurations/overlays.nix b/modules/configurations/overlays.nix deleted file mode 100644 index 22ab3a9..0000000 --- a/modules/configurations/overlays.nix +++ /dev/null @@ -1,9 +0,0 @@ -{lib, ...}: -with lib; { - flake.nixosModules.configurations = {config, ...}: { - config = { - nixpkgs.overlays = [ - ]; - }; - }; -} diff --git a/modules/configurations/powersave.nix b/modules/configurations/powersave.nix deleted file mode 100644 index ef70ecb..0000000 --- a/modules/configurations/powersave.nix +++ /dev/null @@ -1,62 +0,0 @@ -{...}: -# Source: https://github.com/vimjoyer/nixconf/blob/main/nixos/features/powersave.nix -{ - flake.nixosModules.configurations = { - pkgs, - lib, - ... - }: { - boot.kernelParams = ["usbcore.autosuspend=500" "amd_pstate=active"]; - services.power-profiles-daemon.enable = true; - services.thermald.enable = true; - services.upower.enable = true; - powerManagement.enable = true; - powerManagement.powertop.enable = true; - - # hardware.amdgpu.overdrive.enable = true; - services.lact.enable = true; - - systemd.services.lact-monitor = { - enable = true; - description = "Monitor PowerProfiles and update LACT profile"; - after = ["network.target" "lactd.service" "power-profiles-daemon.service"]; - wants = ["lactd.service" "power-profiles-daemon.service"]; - serviceConfig = { - Type = "simple"; - ExecStartPre = lib.getExe (pkgs.writeShellApplication { - name = "lact-initial-set"; - runtimeInputs = [pkgs.lact pkgs.glib pkgs.dbus pkgs.power-profiles-daemon]; - text = '' - profile=$(powerprofilesctl get) - if [[ $profile == "power-saver" ]]; then - lact cli profile set "power-saver" - else - lact cli profile set "default" - fi - ''; - }); - ExecStart = lib.getExe (pkgs.writeShellApplication { - name = "lact-watcher"; - runtimeInputs = [pkgs.libnotify pkgs.lact pkgs.glib pkgs.dbus]; - text = '' - gdbus monitor --system --dest net.hadess.PowerProfiles | - while read -r line; do - if [[ $line =~ ActiveProfile ]]; then - profile=$(echo "$line" | grep -oP "(?<=<').+?(?='>)") - - if [[ $profile == "power-saver" ]]; then - lact cli profile set "power-saver" - else - lact cli profile set "default" - fi - fi - done - ''; - }); - Restart = "always"; - User = "root"; - }; - wantedBy = ["multi-user.target"]; - }; - }; -} diff --git a/modules/configurations/theme.nix b/modules/configurations/theme.nix deleted file mode 100644 index 47ada7f..0000000 --- a/modules/configurations/theme.nix +++ /dev/null @@ -1,24 +0,0 @@ -{lib, ...}: -with lib; { - flake.homeModules.configurations = {pkgs, ...}: let - cursor_theme_name = "BreezeX-RosePine-Linux"; - in { - config.home = mkIf pkgs.stdenv.isLinux { - packages = with pkgs; [rose-pine-cursor]; - sessionVariables = { - XCURSOR_THEME = cursor_theme_name; - XCURSOR_SIZE = "25"; - }; - pointerCursor = { - enable = true; - gtk.enable = true; - x11.enable = true; - # package = pkgs.bibata-cursors; - # name = "Bibata-Modern-Classic"; - package = pkgs.rose-pine-cursor; - name = cursor_theme_name; - size = 25; - }; - }; - }; -} diff --git a/modules/configurations/users.nix b/modules/configurations/users.nix deleted file mode 100644 index 857ce19..0000000 --- a/modules/configurations/users.nix +++ /dev/null @@ -1,37 +0,0 @@ -{lib, ...}: -with lib; { - flake.nixosModules.configurations = {config, ...}: { - config = { - users.users.${config.profile.user.username} = { - uid = 1000; - isNormalUser = true; - description = config.profile.user.fullname; - extraGroups = ["networkmanager" "wheel" "audio"]; - group = config.profile.user.username; - }; - users.groups.${config.profile.user.username} = {}; - - virtualisation.vmVariant = { - users.users.${config.profile.user.username} = { - isNormalUser = true; - description = config.profile.user.fullname; - extraGroups = ["networkmanager" "wheel" "audio" "i2c"]; - group = config.profile.user.username; - initialPassword = "test"; - }; - users.groups.${config.profile.user.username} = {}; - }; - }; - }; - - flake.darwinModules.configurations = {config, ...}: { - config = { - users.users.${config.profile.user.username} = { - description = config.profile.user.fullname; - uid = mkDefault 501; - home = mkDefault "/Users/${config.profile.user.username}"; - }; - users.groups.${config.profile.user.username} = {}; - }; - }; -} diff --git a/modules/declarations/default.nix b/modules/declarations/default.nix new file mode 100644 index 0000000..5fa1e77 --- /dev/null +++ b/modules/declarations/default.nix @@ -0,0 +1,7 @@ +{lib, ...}: { + options.flake.declarations = lib.mkOption { + type = lib.types.lazyAttrsOf lib.types.raw; + default = {}; + description = "Anvil's declarations"; + }; +} diff --git a/modules/declarations/desktop.nix b/modules/declarations/desktop.nix new file mode 100644 index 0000000..7f03f14 --- /dev/null +++ b/modules/declarations/desktop.nix @@ -0,0 +1,93 @@ +{lib, ...}: +with lib; { + flake.declarations.desktop = {pkgs, ...}: { + options = { + modKey = mkOption { + type = types.str; + description = "The mod key to be used by the window manager."; + default = "super"; + }; + + modKeyAlt = mkOption { + type = types.str; + description = "The alternative mod key to be used by the window manager."; + default = "alt"; + }; + + terminal = mkOption { + type = types.package; + description = "The wrapped and configured terminal package."; + }; + + browser = mkOption { + type = types.package; + description = "The wrapped and configured browser package."; + }; + + desktopShell = mkOption { + type = types.package; + description = "The wrapped and configured desktop shell package."; + }; + + appLauncher = mkOption { + type = types.package; + description = "The wrapped and configured app launcher package."; + }; + + packages = mkOption { + type = types.listOf types.package; + description = "An list of packages to install."; + }; + + fontsConfig = mkOption { + type = types.package; + description = "The package with the font configurations. Export FONTCONFIG_FILE=\${fontsConfig} to apply the fonts."; + default = pkgs.makeFontsConf { + fontDirectories = with pkgs; [ + nerd-fonts.jetbrains-mono + ]; + }; + }; + + monitors = mkOption { + type = types.attrsOf (types.submodule { + options = { + primary = mkOption { + type = types.bool; + default = false; + }; + width = mkOption { + type = types.int; + example = 1920; + }; + height = mkOption { + type = types.int; + example = 1080; + }; + refreshRate = mkOption { + type = types.float; + default = 60; + }; + x = mkOption { + type = types.int; + default = 0; + }; + y = mkOption { + type = types.int; + default = 0; + }; + scale = mkOption { + type = types.float; + default = 1.0; + }; + enabled = mkOption { + type = types.bool; + default = true; + }; + }; + }); + default = {}; + }; + }; + }; +} diff --git a/modules/declarations/shell.nix b/modules/declarations/shell.nix new file mode 100644 index 0000000..652194f --- /dev/null +++ b/modules/declarations/shell.nix @@ -0,0 +1,68 @@ +{lib, ...}: +with lib; { + flake.declarations.shell = {...}: { + options = { + metadata = mkOption { + type = types.attrsOf types.raw; + description = "A free-form attrs with data for the configuration"; + default = {}; + }; + + activationScripts = mkOption { + type = types.listOf types.str; + description = "A list of activations scripts to source on the shell configuration startup"; + default = []; + }; + + packages = mkOption { + type = types.listOf types.package; + description = "A list of packages to install with the shell"; + default = []; + }; + + envVariables = mkOption { + type = types.attrsOf types.str; + description = "An attrset with env variables"; + default = {}; + }; + + shellAliases = mkOption { + type = types.attrsOf (types.nullOr types.str); + description = "An attrset with shell aliases"; + default = {}; + }; + + prompt = { + name = mkOption { + type = types.str; + description = "The name of the shell prompt"; + }; + getPackage = mkOption { + type = types.functionTo types.package; + description = "The package of the shell prompt"; + }; + activationScript = mkOption { + type = types.str; + description = "The activation script to source the prompt on the shell configuration startup"; + default = ""; + }; + }; + + multiplexer = { + name = mkOption { + type = types.str; + description = "The name of the terminal multiplexer prompt"; + }; + getPackage = mkOption { + type = types.functionTo types.package; + description = "The package of the shell multiplexer"; + }; + activationScript = mkOption { + type = types.str; + description = "The activation script to source the multiplexer on the shell configuration startup"; + default = ""; + }; + }; + }; + }; +} diff --git a/modules/dotfiles/aerospace.nix b/modules/dotfiles/aerospace.nix new file mode 100644 index 0000000..5a434b1 --- /dev/null +++ b/modules/dotfiles/aerospace.nix @@ -0,0 +1,154 @@ +{...}: { + flake.dotfiles.aerospace.default = {...}: '' + after-startup-command = [] + start-at-login = true + + # Normalizations. See: https://nikitabobko.github.io/AeroSpace/guide#normalization + enable-normalization-flatten-containers = true + enable-normalization-opposite-orientation-for-nested-containers = true + + # See: https://nikitabobko.github.io/AeroSpace/guide#layouts + # The 'accordion-padding' specifies the size of accordion padding + # You can set 0 to disable the padding feature + accordion-padding = 30 + + # Possible values: tiles|accordion + default-root-container-layout = 'accordion' + + # Possible values: horizontal|vertical|auto + # 'auto' means: wide monitor (anything wider than high) gets horizontal orientation, + # tall monitor (anything higher than wide) gets vertical orientation + default-root-container-orientation = 'auto' + + # Mouse follows focus when focused monitor changes + # Drop it from your config, if you don't like this behavior + # See https://nikitabobko.github.io/AeroSpace/guide#on-focus-changed-callbacks + # See https://nikitabobko.github.io/AeroSpace/commands#move-mouse + # Fallback value (if you omit the key): on-focused-monitor-changed = [] + on-focused-monitor-changed = ['move-mouse monitor-lazy-center'] + + # You can effectively turn off macOS "Hide application" (cmd-h) feature by toggling this flag + # Useful if you don't use this macOS feature, but accidentally hit cmd-h or cmd-alt-h key + # Also see: https://nikitabobko.github.io/AeroSpace/goodies#disable-hide-app + automatically-unhide-macos-hidden-apps = false + + # Possible values: (qwerty|dvorak|colemak) + # See https://nikitabobko.github.io/AeroSpace/guide#key-mapping + [key-mapping] + preset = 'qwerty' + + # [[on-window-detected]] + # if.app-id = 'com.microsoft.teams2' + # run = ['layout floating', 'move-node-to-workspace O'] + # + # [[on-window-detected]] + # if.app-id = 'com.microsoft.Outlook' + # run = ['layout floating', 'move-node-to-workspace O'] + + + + # Gaps between windows (inner-*) and between monitor edges (outer-*). + # Possible values: + # - Constant: gaps.outer.top = 8 + # - Per monitor: gaps.outer.top = [{ monitor.main = 16 }, { monitor."some-pattern" = 32 }, 24] + # In this example, 24 is a default value when there is no match. + # Monitor pattern is the same as for 'workspace-to-monitor-force-assignment'. + # See: + # https://nikitabobko.github.io/AeroSpace/guide#assign-workspaces-to-monitors + [gaps] + inner.horizontal = 5 + inner.vertical = 5 + outer.left = 5 + outer.bottom = 5 + outer.top = 5 + outer.right = 5 + + # 'main' binding mode declaration + # See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes + # 'main' binding mode must be always presented + # Fallback value (if you omit the key): mode.main.binding = {} + [mode.main.binding] + # See: https://nikitabobko.github.io/AeroSpace/commands#focus + alt-h = 'focus left' + alt-j = 'focus down' + alt-k = 'focus up' + alt-l = 'focus right' + + # See: https://nikitabobko.github.io/AeroSpace/commands#move + alt-shift-h = 'move left' + alt-shift-j = 'move down' + alt-shift-k = 'move up' + alt-shift-l = 'move right' + + # See: https://nikitabobko.github.io/AeroSpace/commands#resize + alt-minus = 'resize smart -50' + alt-equal = 'resize smart +50' + + # See: https://nikitabobko.github.io/AeroSpace/commands#workspace + alt-1 = 'workspace 1' + alt-2 = 'workspace 2' + alt-3 = 'workspace 3' + alt-4 = 'workspace 4' + alt-5 = 'workspace 5' + alt-6 = 'workspace 6' + alt-7 = 'workspace 7' + alt-8 = 'workspace 8' + alt-9 = 'workspace 9' + alt-u = 'workspace U' + alt-i = 'workspace I' + alt-o = 'workspace O' + alt-p = 'workspace P' + alt-t = 'workspace T' + + # See: https://nikitabobko.github.io/AeroSpace/commands#move-node-to-workspace + alt-shift-1 = 'move-node-to-workspace 1' + alt-shift-2 = 'move-node-to-workspace 2' + alt-shift-3 = 'move-node-to-workspace 3' + alt-shift-4 = 'move-node-to-workspace 4' + alt-shift-5 = 'move-node-to-workspace 5' + alt-shift-6 = 'move-node-to-workspace 6' + alt-shift-7 = 'move-node-to-workspace 7' + alt-shift-8 = 'move-node-to-workspace 8' + alt-shift-9 = 'move-node-to-workspace 9' + alt-shift-u = 'move-node-to-workspace U' + alt-shift-i = 'move-node-to-workspace I' + alt-shift-o = 'move-node-to-workspace O' + alt-shift-p = 'move-node-to-workspace P' + alt-shift-t = 'move-node-to-workspace T' + + # See: https://nikitabobko.github.io/AeroSpace/commands#workspace-back-and-forth + alt-tab = 'workspace-back-and-forth' + # See: https://nikitabobko.github.io/AeroSpace/commands#move-workspace-to-monitor + alt-period = 'move-workspace-to-monitor --wrap-around prev' + alt-comma = 'move-workspace-to-monitor --wrap-around next' + + # See: https://nikitabobko.github.io/AeroSpace/commands#mode + alt-shift-semicolon = 'mode service' + + alt-x = 'close' + alt-d = ['exec-and-forget open -n /System/Applications/Apps.app/'] + + alt-backspace = 'layout tiles accordion' + + + # 'service' binding mode declaration. + # See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes + [mode.service.binding] + esc = ['reload-config', 'mode main'] + r = ['flatten-workspace-tree', 'mode main'] # reset layout + f = ['layout floating tiling', 'mode main'] # Toggle between floating and tiling layout + backspace = ['close-all-windows-but-current', 'mode main'] + + # sticky is not yet supported https://github.com/nikitabobko/AeroSpace/issues/2 + #s = ['layout sticky tiling', 'mode main'] + + alt-shift-h = ['join-with left', 'mode main'] + alt-shift-j = ['join-with down', 'mode main'] + alt-shift-k = ['join-with up', 'mode main'] + alt-shift-l = ['join-with right', 'mode main'] + + down = 'volume down' + up = 'volume up' + shift-down = ['volume set 0', 'mode main'] + ''; +} diff --git a/modules/dotfiles/atuin.nix b/modules/dotfiles/atuin.nix new file mode 100644 index 0000000..bc0f1b4 --- /dev/null +++ b/modules/dotfiles/atuin.nix @@ -0,0 +1,30 @@ +{...}: { + flake.dotfiles.atuin.default = {...}: '' + dialect = "us" + + invert = false + enter_accept = true + + filter_mode = "global" + filter_mode_shell_up_key_binding = "global" + + keymap_mode = "vim-normal" + keymap_cursor = { emacs = "blink-block", vim_insert = "steady-bar", vim_normal = "steady-block" } + + search_mode = "daemon-fuzzy" + + # height of the search window + inline_height = 40 + style = "compact" + + [daemon] + enabled = true + autostart = true + + [keys] + prefix = "a" + + [ui] + columns = ["time", "command"] + ''; +} diff --git a/modules/dotfiles/default.nix b/modules/dotfiles/default.nix new file mode 100644 index 0000000..3f32291 --- /dev/null +++ b/modules/dotfiles/default.nix @@ -0,0 +1,11 @@ +{lib, ...}: { + options.flake.dotfiles = lib.mkOption { + type = lib.types.lazyAttrsOf lib.types.unspecified; + default = {}; + description = "Anvil's helper library for managing dotfiles, exposed as the flake output `dotfiles`."; + }; + + config = { + flake.dotfiles.resourcesPath = ../../resources; + }; +} diff --git a/modules/dotfiles/niri.nix b/modules/dotfiles/niri.nix new file mode 100644 index 0000000..3fe5e8e --- /dev/null +++ b/modules/dotfiles/niri.nix @@ -0,0 +1,425 @@ +{lib, ...}: +with lib; { + flake.dotfiles.niri.default = {config, ...}: let + terminal = getExe config.terminal; + appLauncher = getExe config.appLauncher; + browser = getExe config.browser; + desktopShell = getExe config.desktopShell; + monitorConfigurations = concatStringsSep "\n\n" (mapAttrsToList + ( + name: monitor: let + mode = "${toString monitor.width}x${toString monitor.height}@${toString monitor.refreshRate}"; + in '' + output "${name}" { + ${ + if monitor.enabled + then "" + else "off" + } + mode "${mode}" + position x=${toString monitor.x} y=${toString monitor.y} + scale ${toString monitor.scale} + variable-refresh-rate on-demand=true + ${ + if monitor.primary + then "focus-at-startup" + else "" + } + + hot-corners { + bottom-right + } + } + '' + ) + config.monitors); + in '' + // ==================== | Launch apps | ==================== + spawn-at-startup "noctalia" + // spawn-at-startup "polkit-gnome-authentication-agent-1" // NOTE: Using the built-in noctalia polkit-agent + spawn-at-startup "xwayland-satellite" + spawn-at-startup "${desktopShell}" + + + + // ==================== | Miscellaneous | ==================== + screenshot-path "~/Pictures/Screenshots/Screenshot_%Y-%m-%d_%H-%M-%S.png" + prefer-no-csd + hotkey-overlay { + skip-at-startup + } + + environment { + DISPLAY ":0" + ELECTRON_OZONE_PLATFORM_HINT "auto" + } + + debug { + // Allows notification actions and window activation from Noctalia. + honor-xdg-activation-with-invalid-serial + } + + + + // ==================== | Input | ==================== + cursor { + // xcursor-theme "" + // xcursor-size + + hide-when-typing + hide-after-inactive-ms 1000 + } + + input { + mod-key "${config.modKey}" + mod-key-nested "${config.modKeyAlt}" + warp-mouse-to-focus + focus-follows-mouse max-scroll-amount="5%" + + keyboard { + xkb { + layout "us" + variant "" + options "compose:ralt" + } + numlock + } + + touchpad { + tap + natural-scroll + accel-speed 0.2 + scroll-factor 0.9 + } + + mouse { + accel-speed -0.7 + } + } + + + + // ==================== | Layout | ==================== + layout { + gaps 5 + center-focused-column "on-overflow" + always-center-single-column + default-column-width { proportion 0.5; } + + preset-column-widths { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + + preset-window-heights { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + + focus-ring { + off + width 2 + active-color "#7fc8ff" + inactive-color "#505050" + } + + border { + // off + width 4 + active-color "#7aa2f7" + inactive-color "#505050" + urgent-color "#9b0000" + } + + struts { + left 13 + right 13 + } + + tab-indicator { + gap 4 + length total-proportion=0.5 + position "left" + place-within-column + hide-when-single-tab + } + } + + + + // ==================== | Window Rules | ==================== + window-rule { + open-maximized true + geometry-corner-radius 3 + clip-to-geometry true + + draw-border-with-background false + opacity 0.75 + variable-refresh-rate true + + background-effect { + blur true + xray true + } + } + + // Remove transparency from windows with videos + window-rule { + match title=r#"(?i)youtube"# + opacity 1.0 + background-effect { + blur false + xray false + } + } + + // Block out password managers from screencasts. + window-rule { + match app-id=r#"^org\.keepassxc\.KeePassXC$"# + match app-id=r#"^org\.gnome\.World\.Secrets$"# + match title=r#"(?i)bit(-)?warden"# + + block-out-from "screencast" + } + + // Indicate screencasted windows with red colors. + window-rule { + match is-window-cast-target=true + + focus-ring { + active-color "#f38ba8" + inactive-color "#7d0d2d" + } + + border { + inactive-color "#7d0d2d" + } + + shadow { + color "#7d0d2d70" + } + + tab-indicator { + active-color "#f38ba8" + inactive-color "#7d0d2d" + } + } + + // Steam notifications + window-rule { + match app-id="steam" title=r#"^notificationtoasts_\d+_desktop$"# + default-floating-position x=10 y=10 relative-to="bottom-right" + } + + // Steam games on fullscreen + window-rule { + match app-id=r#"^steam_app_.*$"# + + open-fullscreen true + open-on-workspace "gaming" + } + + + + // ==================== | Layer Rules | ==================== + // Noctalia backgroun on overview mode + layer-rule { + match namespace="^noctalia-backdrop" + place-within-backdrop true + } + + layer-rule { + match namespace="^noctalia-(bar-[^\"]+|notification|dock|panel|attached-panel|osd)$" + + background-effect { + xray false + blur false + } + + popups { + opacity 1.0 + // geometry-corner-radius 15 + + background-effect { + xray false + blur false + } + } + } + + blur { + passes 3 // more passes = stronger blur (default: 3) + offset 3.0 // sample distance per pass (default: 3.0) + noise 0.03 // grain overlay (default: 0.02) + saturation 1.5 // color saturation boost (default: 1.5) + } + + animations { + // off + workspace-switch { + off + } + } + + + + // ==================== | Workspaces | ==================== + spawn-at-startup "${terminal}" + workspace "terminal" + window-rule { + match at-startup=true app-id=r#"^${terminal}$"# + open-on-workspace "terminal" + open-maximized true + } + + workspace "browser" + window-rule { + match at-startup=true app-id=r#"^${browser}$"# + open-on-workspace "browser" + open-maximized true + } + + workspace "multimedia" + window-rule { + match at-startup=true app-id=r#"^spotify$"# + open-on-workspace "multimedia" + open-maximized true + } + + workspace "gaming" + window-rule { + match at-startup=true app-id=r#"^steam$"# + open-on-workspace "gaming" + open-maximized true + } + + workspace "chat" + window-rule { + match at-startup=true app-id=r#"^discord$"# + open-on-workspace "chat" + open-maximized true + } + + workspace "temporal" + + + // ==================== | Monitors | ==================== + ${monitorConfigurations} + + + + // ==================== | Bindings | ==================== + binds { + // Powers off the monitors. To turn them back on, do any input like + // moving the mouse or pressing any other key. + Ctrl+Shift+P { power-off-monitors; } + + Mod+Shift+E { quit; } + Mod+Shift+Slash { show-hotkey-overlay; } + Mod+Space repeat=false hotkey-overlay-title="Open a Terminal" { spawn "${terminal}"; } + Mod+X repeat=false hotkey-overlay-title="Closes the focused window" { close-window; } + Mod+D hotkey-overlay-title="Run the Application Launcher: ${appLauncher}" { spawn "${appLauncher}"; } + Mod+V hotkey-overlay-title="Open the clipboard history app" { spawn "clipboard-history"; } + + + XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.05+ -l 1.0"; } // "-l 1.0" limits the volume to 100%. + XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.05-"; } + XF86AudioMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; } + XF86AudioMicMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; } + + XF86AudioPlay allow-when-locked=true { spawn-sh "playerctl play-pause"; } + XF86AudioStop allow-when-locked=true { spawn-sh "playerctl stop"; } + XF86AudioPrev allow-when-locked=true { spawn-sh "playerctl previous"; } + XF86AudioNext allow-when-locked=true { spawn-sh "playerctl next"; } + + XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "+5%"; } + XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "5%-"; } + + Mod+Left { focus-column-left; } + Mod+Down { focus-window-down; } + Mod+Up { focus-window-up; } + Mod+Right { focus-column-right; } + Mod+H { focus-column-left; } + Mod+J { focus-window-down; } + Mod+K { focus-window-up; } + Mod+L { focus-column-right; } + + Mod+Shift+Left { move-column-left; } + Mod+Shift+Down { move-window-down; } + Mod+Shift+Up { move-window-up; } + Mod+Shift+Right { move-column-right; } + Mod+Shift+H { move-column-left; } + Mod+Shift+J { move-window-down; } + Mod+Shift+K { move-window-up; } + Mod+Shift+L { move-column-right; } + + Mod+Ctrl+H { consume-or-expel-window-left; } + Mod+Ctrl+L { consume-or-expel-window-right; } + + Mod+1 { focus-workspace 1; } + Mod+2 { focus-workspace 2; } + Mod+3 { focus-workspace 3; } + Mod+4 { focus-workspace 4; } + Mod+5 { focus-workspace 5; } + Mod+6 { focus-workspace 6; } + Mod+7 { focus-workspace 7; } + Mod+8 { focus-workspace 8; } + Mod+9 { focus-workspace 9; } + + Mod+Shift+1 { move-column-to-workspace 1; } + Mod+Shift+2 { move-column-to-workspace 2; } + Mod+Shift+3 { move-column-to-workspace 3; } + Mod+Shift+4 { move-column-to-workspace 4; } + Mod+Shift+5 { move-column-to-workspace 5; } + Mod+Shift+6 { move-column-to-workspace 6; } + Mod+Shift+7 { move-column-to-workspace 7; } + Mod+Shift+8 { move-column-to-workspace 8; } + Mod+Shift+9 { move-column-to-workspace 9; } + + Mod+Minus { set-window-width "-10%"; } + Mod+Equal { set-window-width "+10%"; } + Mod+Shift+Minus { set-window-height "-10%"; } + Mod+Shift+Equal { set-window-height "+10%"; } + + Mod+U { focus-workspace "terminal"; } + Mod+I { focus-workspace "browser"; } + Mod+O { focus-workspace "chat"; } + Mod+P { focus-workspace "multimedia"; } + Mod+G { focus-workspace "gaming"; } + Mod+T { focus-workspace "temporal"; } + + Mod+Shift+U { move-column-to-workspace "terminal"; } + Mod+Shift+I { move-column-to-workspace "browser"; } + Mod+Shift+O { move-column-to-workspace "chat"; } + Mod+Shift+P { move-column-to-workspace "multimedia"; } + Mod+Shift+G { move-column-to-workspace "gaming"; } + Mod+Shift+T { move-column-to-workspace "temporal"; } + + Mod+Comma { move-workspace-to-monitor-previous; } + Mod+Period { move-workspace-to-monitor-next; } + + Mod+Tab { toggle-column-tabbed-display; } + + Mod+F { maximize-column; } + Mod+Shift+F { fullscreen-window; } + // Mod+Ctrl+F { toggle-window-floating; } + Mod+Ctrl+F { + spawn-sh "if [ \"$(niri msg -j focused-window | jq -r .is_floating)\" = \"false\" ]; then niri msg action toggle-window-floating && niri msg action set-window-width -- 60% && niri msg action set-window-height -- 60%; else niri msg action toggle-window-floating; fi" + } + Mod+S { switch-preset-column-width; } + Mod+C { center-visible-columns; } + + Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } + + Ctrl+Shift+3 { screenshot-screen; } + Ctrl+Shift+5 { screenshot-window; } + Ctrl+Shift+4 { screenshot; } + + Mod+Ctrl+Shift+W { set-dynamic-cast-window; } + Mod+Ctrl+Shift+M { set-dynamic-cast-monitor; } + Mod+Ctrl+Shift+C { clear-dynamic-cast-target; } + } + ''; +} diff --git a/modules/dotfiles/noctalia.nix b/modules/dotfiles/noctalia.nix new file mode 100644 index 0000000..264c042 --- /dev/null +++ b/modules/dotfiles/noctalia.nix @@ -0,0 +1,615 @@ +{self, ...}: { + flake.dotfiles.noctalia.default = {...}: let + wallpapersPath = "${self.dotfiles.resourcesPath}/wallpapers"; + imagessPath = "${self.dotfiles.resourcesPath}/images"; + in '' + [audio] + enable_sounds = true + + [backdrop] + blur_intensity = 0.4999999888241291 + enabled = true + tint_intensity = 0.0 + + [bar] + order = [ "default" ] + + [bar.default] + background_opacity = 0.0 + capsule = true + capsule_opacity = 0.75 + capsule_padding = 10.0 + capsule_radius = "auto" + capsule_thickness = 0.89999998360872269 + center = [ "privacy", "media", "recorder_2" ] + end = [ "group:g3", "group:g2", "group:g1", "group:g4" ] + margin_edge = 5 + margin_ends = 10 + shadow = false + start = [ "control-center", "workspaces" ] + thickness = 25 + + [[bar.default.capsule_group]] + fill = "surface_variant" + id = "g3" + members = [ "network", "bluetooth" ] + opacity = 0.75 + padding = 10.0 + + [[bar.default.capsule_group]] + fill = "surface_variant" + id = "g2" + members = [ "volume", "brightness", "battery" ] + opacity = 0.75 + padding = 10.0 + + [[bar.default.capsule_group]] + fill = "surface_variant" + id = "g4" + members = [ "notifications", "session" ] + opacity = 0.75 + padding = 10.0 + + [[bar.default.capsule_group]] + fill = "surface_variant" + id = "g1" + members = [ "clock", "date" ] + opacity = 0.75 + padding = 10.0 + + [battery] + warning_threshold = 15 + + [battery.device."/org/freedesktop/UPower/devices/headset_dev_80_99_E7_F0_E1_15"] + warning_threshold = 30 + + [brightness] + enable_ddcutil = true + sync_all_monitors = true + + [calendar] + enabled = true + + [calendar.account.personal_google] + color = "primary" + name = "Personal Calendar" + type = "google" + + [control_center] + hidden_tabs = [] + + [[control_center.shortcuts]] + type = "caffeine" + + [[control_center.shortcuts]] + type = "nightlight" + + [[control_center.shortcuts]] + type = "notification" + + [[control_center.shortcuts]] + type = "power_profile" + + [[control_center.shortcuts]] + type = "clipboard" + + [[control_center.shortcuts]] + type = "noctalia/screen_recorder:toggle" + + [desktop_widgets] + schema_version = 2 + widget_order = [] + + [desktop_widgets.grid] + cell_size = 16 + major_interval = 4 + visible = true + + [desktop_widgets.widget] + + [dock] + active_monitor_only = true + active_scale = 1.1000000163912773 + auto_hide = true + background_opacity = 0.99999997764825821 + enabled = false + icon_size = 30 + launcher_icon = "layout-dashboard-filled" + launcher_position = "start" + magnification_scale = 1.3000000044703484 + main_axis_padding = 10 + reserve_space = false + shadow = false + + [idle] + behavior_order = [ "lock", "screen-off", "lock-and-suspend" ] + pre_action_fade_seconds = 10 + + [idle.behavior.lock] + action = "lock" + enabled = true + timeout = 610.0 + + [idle.behavior.lock-and-suspend] + action = "lock_and_suspend" + enabled = true + timeout = 900.0 + + [idle.behavior.screen-off] + action = "screen_off" + enabled = true + timeout = 600.0 + + [location] + auto_locate = true + + [lockscreen] + blur_intensity = 0.64999998547136784 + blurred_desktop = true + tint_intensity = 0.19999999552965164 + + [lockscreen_widgets] + enabled = true + schema_version = 2 + widget_order = [ + "lockscreen-login-box@eDP-1", + "lockscreen-login-box@HDMI-A-2", + "lockscreen-login-box@DP-3", + "lockscreen-login-box@HDMI-A-1", + "lockscreen-login-box@DP-1", + "lockscreen-login-box@winit", + "lockscreen-login-box@eDP-1", + "lockscreen-widget-0000000000000006", + "lockscreen-widget-0000000000000003", + "lockscreen-widget-0000000000000007", + "lockscreen-widget-0000000000000008" + ] + + [lockscreen_widgets.grid] + cell_size = 16 + major_interval = 4 + visible = true + + [lockscreen_widgets.widget."lockscreen-login-box@DP-1"] + box_height = 70.0 + box_width = 400.0 + cx = 960.0 + cy = 961.0 + output = "DP-1" + rotation = 0.0 + type = "login_box" + + [lockscreen_widgets.widget."lockscreen-login-box@DP-1".settings] + background_color = "surface_variant" + background_opacity = 0.88 + background_radius = 12.0 + input_opacity = 1.0 + input_radius = 6.0 + show_caps_lock = true + show_keyboard_layout = true + show_login_button = true + + [lockscreen_widgets.widget."lockscreen-login-box@DP-2"] + box_height = 70.0 + box_width = 400.0 + cx = 1280.0 + cy = 1321.0 + output = "DP-2" + rotation = 0.0 + type = "login_box" + + [lockscreen_widgets.widget."lockscreen-login-box@DP-2".settings] + background_color = "surface_variant" + background_opacity = 0.88 + background_radius = 12.0 + input_opacity = 1.0 + input_radius = 6.0 + show_caps_lock = true + show_keyboard_layout = true + show_login_button = true + + [lockscreen_widgets.widget."lockscreen-login-box@DP-3"] + box_height = 70.0 + box_width = 400.0 + cx = 960.0 + cy = 961.0 + output = "DP-3" + rotation = 0.0 + type = "login_box" + + [lockscreen_widgets.widget."lockscreen-login-box@DP-3".settings] + background_color = "surface_variant" + background_opacity = 0.88 + background_radius = 12.0 + input_opacity = 1.0 + input_radius = 6.0 + show_caps_lock = true + show_keyboard_layout = true + show_login_button = true + + [lockscreen_widgets.widget."lockscreen-login-box@HDMI-A-1"] + box_height = 70.0 + box_width = 400.0 + cx = 1280.0 + cy = 1321.0 + output = "HDMI-A-1" + rotation = 0.0 + type = "login_box" + + [lockscreen_widgets.widget."lockscreen-login-box@HDMI-A-1".settings] + background_color = "surface_variant" + background_opacity = 0.88 + background_radius = 12.0 + input_opacity = 1.0 + input_radius = 6.0 + show_caps_lock = true + show_keyboard_layout = true + show_login_button = true + + [lockscreen_widgets.widget."lockscreen-login-box@HDMI-A-2"] + box_height = 196.0 + box_width = 720.0 + cx = 960.0 + cy = 961.0 + output = "HDMI-A-2" + placement_height = 0.0 + placement_width = 0.0 + rotation = 0.0 + type = "login_box" + + [lockscreen_widgets.widget."lockscreen-login-box@HDMI-A-2".settings] + background_color = "surface_variant" + background_opacity = 0.88 + background_radius = 12.0 + center_password_text = false + input_opacity = 1.0 + input_radius = 6.0 + layout = "regular" + show_caps_lock = true + show_keyboard_layout = true + show_login_button = true + show_media = true + show_session_buttons = true + show_unlock_hint = true + show_weather = true + + [lockscreen_widgets.widget."lockscreen-login-box@eDP-1"] + box_height = 70.0 + box_width = 400.0 + cx = 960.0 + cy = 953.0 + output = "eDP-1" + placement_height = 1080.0 + placement_width = 1920.0 + rotation = 0.0 + type = "login_box" + + [lockscreen_widgets.widget."lockscreen-login-box@eDP-1".settings] + background_color = "surface_variant" + background_opacity = 0.88 + background_radius = 12.0 + center_password_text = false + input_opacity = 1.0 + input_radius = 6.0 + layout = "compact" + show_caps_lock = true + show_keyboard_layout = true + show_login_button = true + show_media = true + show_session_buttons = true + show_unlock_hint = true + show_weather = true + + [lockscreen_widgets.widget."lockscreen-login-box@winit"] + box_height = 196.0 + box_width = 720.0 + cx = 682.981201171875 + cy = 1028.0 + output = "winit" + placement_height = 1028.0 + placement_width = 1876.0 + rotation = 0.0 + type = "login_box" + + [lockscreen_widgets.widget."lockscreen-login-box@winit".settings] + background_color = "surface_variant" + background_opacity = 0.88 + background_radius = 12.0 + center_password_text = false + input_opacity = 1.0 + input_radius = 6.0 + layout = "regular" + show_caps_lock = true + show_keyboard_layout = true + show_login_button = true + show_media = true + show_session_buttons = true + show_unlock_hint = true + show_weather = true + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000001] + box_height = 0.0 + box_width = 0.0 + cx = 960.0 + cy = 156.0 + output = "DP-3" + rotation = 0.0 + type = "clock" + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000001.settings] + background = false + center_text = true + shadow = false + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000002] + box_height = 0.0 + box_width = 0.0 + cx = 960.0 + cy = 802.0 + output = "DP-3" + rotation = 0.0 + type = "media_player" + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000002.settings] + background = false + hide_when_no_media = true + shadow = false + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000003] + box_height = 128.0 + box_width = 416.0 + cx = 960.0 + cy = 796.0 + output = "eDP-1" + rotation = 0.0 + type = "media_player" + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000003.settings] + background = false + background_opacity = 0.78000000000000003 + color = "on_surface" + hide_when_no_media = true + layout = "horizontal" + shadow = false + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000004] + box_height = 0.0 + box_width = 0.0 + cx = 640.0 + cy = 538.0 + output = "eDP-1" + rotation = 0.0 + type = "media_player" + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000004.settings] + background = false + hide_when_no_media = true + shadow = false + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000006] + box_height = 0.0 + box_width = 0.0 + cx = 960.0 + cy = 188.0 + output = "eDP-1" + placement_height = 1080.0 + placement_width = 1920.0 + rotation = 0.0 + type = "clock" + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000006.settings] + background = false + center_text = true + clock_style = "digital" + shadow = false + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000007] + box_height = 0.0 + box_width = 0.0 + cx = 960.0 + cy = 172.5 + output = "DP-1" + rotation = 0.0 + type = "clock" + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000007.settings] + background = false + shadow = false + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000008] + box_height = 0.0 + box_width = 0.0 + cx = 960.0 + cy = 812.0 + output = "DP-1" + rotation = 0.0 + type = "media_player" + + [lockscreen_widgets.widget.lockscreen-widget-0000000000000008.settings] + background = false + hide_when_no_media = true + shadow = false + + [nightlight] + enabled = true + temperature_night = 3800 + + [osd] + background_opacity = 0.74999998323619366 + position = "top_right" + position_vertical = "top_right" + + [plugin_settings."noctalia/screen_recorder"] + color_range = "full" + hide_inactive = true + quality = "ultra" + replay_enabled = true + resolution = "original" + + [plugin_settings."yocraft/web-launcher"] + icon_provider = "direct" + links = [ + "GitHub|https://github.com", + "GitLab|https://gitlab.com", + "Codeberg|https://codeberg.org", + "Reddit|https://reddit.com", + "YouTube|https://youtube.com", + "Gmail|https://mail.google.com", + "Whatsapp|https://web.whatsapp.com", + "Teams|https://teams.live.com/v2" + ] + notify = false + + [plugins] + enabled = [ "noctalia/screen_recorder", "yocraft/web-launcher" ] + + [shell] + avatar_path = "${imagessPath}/avatar.jpg" + font_family = "JetBrainsMono Nerd Font Mono" + launch_apps_as_systemd_services = true + niri_overview_type_to_launch_enabled = true + polkit_agent = true + screen_time_enabled = true + settings_show_advanced = true + settings_window_translucent = true + show_location = false + telemetry_enabled = true + + [shell.greeter_sync] + auto_sync = true + + [shell.launcher] + app_grid = true + compact = true + session_search = true + + [shell.launcher.dmenu.entry.nixpkgs] + command = "echo Nixpkgs" + exec = "nixpkgs-search" + global = false + glyph = "package" + prefix = "nix" + + [shell.panel] + control_center_placement = "floating" + list_item_background = true + open_near_click_control_center = true + open_near_click_session = true + session_placement = "floating" + session_position = "auto" + wallpaper_placement = "floating" + + [shell.screen_corners] + enabled = true + size = 25 + + [[shell.session.actions]] + action = "lock" + countdown_seconds = 0.0 + enabled = true + shortcut = "1" + variant = "default" + + [[shell.session.actions]] + action = "logout" + countdown_seconds = 0.0 + enabled = true + shortcut = "2" + variant = "default" + + [[shell.session.actions]] + action = "lock_and_suspend" + countdown_seconds = 0.0 + enabled = true + glyph = "zzz" + label = "Suspend" + shortcut = "3" + variant = "default" + + [[shell.session.actions]] + action = "reboot" + countdown_seconds = 0.0 + enabled = true + shortcut = "4" + variant = "default" + + [[shell.session.actions]] + action = "shutdown" + countdown_seconds = 0.0 + enabled = true + shortcut = "5" + variant = "destructive" + + [theme] + builtin = "Tokyo-Night" + community_palette = "Tokyo Night Storm" + mode = "dark" + pure_black_dark = true + source = "builtin" + wallpaper_scheme = "m3-tonal-spot" + + [theme.templates] + builtin_ids = [ "btop" ] + community_ids = [ "zen-browser" ] + + [wallpaper] + directory = "${wallpapersPath}" + transition_on_startup = true + + [wallpaper.automation] + enabled = true + interval_seconds = 900 + + [wallpaper.default] + path = "${wallpapersPath}/wallhaven.jpg" + + [wallpaper.last] + path = "${wallpapersPath}/wallhaven.jpg" + + [wallpaper.monitors.DP-1] + path = "${wallpapersPath}/wallhaven.jpg" + + [wallpaper.monitors.HDMI-A-1] + path = "${wallpapersPath}/wallhaven.jpg" + + [wallpaper.monitors.HDMI-A-2] + path = "${wallpapersPath}/wallhaven.jpg" + + [wallpaper.monitors.eDP-1] + path = "${wallpapersPath}/wallhaven.jpg" + + [widget.brightness] + show_label = false + + [widget.control-center] + anchor = true + capsule = true + glyph = "brand-dribbble-filled" + + [widget.media] + hide_when_no_media = true + title_scroll = "always" + + [widget.network] + show_label = false + + [widget.privacy] + active_color = "error" + hide_inactive = true + + [widget.recorder] + type = "noctalia/screen_recorder:recorder" + + [widget.recorder_2] + type = "noctalia/screen_recorder:recorder" + + [widget.volume] + show_label = false + + [widget.workspaces] + anchor = true + hide_when_empty = true + pill_scale = 0.75 + show_labels = false + ''; +} diff --git a/modules/dotfiles/oh-my-posh/default.nix b/modules/dotfiles/oh-my-posh/default.nix new file mode 100644 index 0000000..4873ac1 --- /dev/null +++ b/modules/dotfiles/oh-my-posh/default.nix @@ -0,0 +1,76 @@ +{ + self, + lib, + ... +}: +with lib; { + flake.dotfiles.oh-my-posh.default = {colors, ...}: + self.dotfiles.oh-my-posh.theme { + inherit colors; + pathStyle = "folder"; + promptGlyph = "󱞩 "; + powerline = true; + upstreamIcon = true; + osIcon = true; + }; + + flake.dotfiles.oh-my-posh.activationScript.zsh = { + pkgs, + prompt, + ... + }: '' + function detect_terminal() { + if [ -n "$TMUX" ]; then + tty_path=$(tmux display-message -p '#{client_tty}' 2>/dev/null) + term_name=$(tmux display-message -p '#{client_termname}' 2>/dev/null) + else + tty_path=$(tty 2>/dev/null) + term_name="$TERM" + fi + + case "$tty_path" in + /dev/tty[0-9]*) + echo "linux_terminal" + return + ;; + esac + + case "$TERM_PROGRAM" in + Apple_Terminal) echo "apple_terminal"; return ;; + iTerm.app) echo "iterm2"; return ;; + esac + + case "$term_name" in + xterm-kitty) echo "kitty"; return ;; + xterm-ghostty) echo "ghostty"; return ;; + foot|foot-extra) echo "foot"; return ;; + esac + + # Fallback to env vars, only meaningful outside tmux + if [ -z "$TMUX" ]; then + if [ -n "$KITTY_WINDOW_ID" ]; then + echo "kitty"; return + elif [ -n "$GHOSTTY_RESOURCES_DIR" ] || [ "$TERM_PROGRAM" = "ghostty" ]; then + echo "ghostty"; return + fi + fi + + echo "unknown_terminal" + } + + case "$(detect_terminal)" in + apple_terminal|linux_terminal) + eval "$(${getExe' (prompt.getPackage { + inherit pkgs; + tty = true; + }) "oh-my-posh"} init zsh)" + ;; + *) + eval "$(${getExe' (prompt.getPackage { + inherit pkgs; + tty = false; + }) "oh-my-posh"} init zsh)" + ;; + esac + ''; +} diff --git a/modules/dotfiles/oh-my-posh/theme.nix b/modules/dotfiles/oh-my-posh/theme.nix new file mode 100644 index 0000000..e2c9526 --- /dev/null +++ b/modules/dotfiles/oh-my-posh/theme.nix @@ -0,0 +1,175 @@ +{lib, ...}: +with lib; let + mappedBranches = '' + { + "main": " main", + "main/*": " ", + "develop": " develop", + "develop/*": " ", + "feature/*": " ", + "feat/*": " ", + "bug/*": " ", + "poc/*": "󰙨 " + } + ''; +in { + flake.dotfiles.oh-my-posh.theme = { + colors, + pathStyle, + promptGlyph, + powerline, + upstreamIcon, + osIcon, + ... + }: let + pathSegment = '' + { + "type": "path", + "style": "plain", + "background": "transparent", + "foreground": "${colors.base0D}", + "template": "${ + if pathStyle == "folder" + then " {{ .Path }} " + else "{{ .Path }} " + }", + "options": { + "style": "${pathStyle}" + } + }, + ''; + + upstreamSegment = optionalString upstreamIcon '' + { + "type": "git", + "style": "plain", + "foreground": "${colors.base07}", + "background": "transparent", + "github_icon": " ", + "gitlab_icon": " ", + "bitbucket_icon": " ", + "template": "{{ .UpstreamIcon }} at ", + "properties": { + "fetch_upstream_icon": true + } + }, + ''; + + gitSegment = + if powerline + then '' + { + "type": "git", + "style": "powerline", + "powerline_symbol": "", + "leading_powerline_symbol": "", + "foreground": "transparent", + "background": "${colors.base07}", + "template": "{{ .HEAD }}{{ if gt .Behind 0 }}⇣{{ end }}{{ if gt .Ahead 0 }}⇡{{ end }}", + "properties": { + "branch_icon": "", + "fetch_status": true, + "mapped_branches": ${mappedBranches} + } + } + '' + else '' + { + "type": "git", + "style": "plain", + "powerline_symbol": "", + "leading_powerline_symbol": "", + "foreground": "${colors.base07}", + "background": "transparent", + "template": "{{ .HEAD }}{{ if gt .Behind 0 }}+{{ end }}{{ if gt .Ahead 0 }}-{{ end }}", + "properties": { + "branch_icon": "", + "fetch_status": true + } + } + ''; + + promptSegment = + if osIcon + then '' + { + "type": "os", + "style": "plain", + "foreground_templates": [ + "{{if gt .Code 0}}${colors.base08}{{end}}", + "{{if le .Code 0}}${colors.base0C}{{end}}" + ], + "background": "transparent", + "template": "{{.Icon}} " + } + '' + else '' + { + "type": "text", + "style": "plain", + "foreground_templates": [ + "{{if gt .Code 0}}${colors.base08}{{end}}", + "{{if le .Code 0}}${colors.base0C}{{end}}" + ], + "background": "transparent", + "template": "${promptGlyph}" + } + ''; + in '' + { + "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json", + "final_space": true, + "console_title_template": "{{ .Shell }} in {{ .Folder }}", + "version": 4, + "blocks": [ + { + "type": "prompt", + "alignment": "left", + "overflow": "hide", + "segments": [ + ${pathSegment} + ${upstreamSegment} + ${gitSegment} + ] + }, + { + "type": "prompt", + "alignment": "right", + "overflow": "hide", + "segments": [ + { + "type": "executiontime", + "style": "plain", + "foreground_templates": [ + "{{if gt .Code 0}}${colors.base08}{{else}}${colors.base0B}{{end}}" + ], + "template": " {{ .FormattedMs }}", + "options": { + "threshold": 1000, + "style": "austin" + } + } + ] + }, + { + "type": "prompt", + "alignment": "left", + "newline": true, + "segments": [ + ${promptSegment} + ] + } + ], + "transient_prompt": { + "foreground": "${colors.base0D}", + "background": "transparent", + "template": "${promptGlyph}" + }, + "secondary_prompt": { + "foreground": "${colors.base0D}", + "background": "transparent", + "template": "${promptGlyph}" + } + } + ''; +} diff --git a/modules/dotfiles/oh-my-posh/tty.nix b/modules/dotfiles/oh-my-posh/tty.nix new file mode 100644 index 0000000..2589f02 --- /dev/null +++ b/modules/dotfiles/oh-my-posh/tty.nix @@ -0,0 +1,11 @@ +{self, ...}: { + flake.dotfiles.oh-my-posh.tty = {colors, ...}: + self.dotfiles.oh-my-posh.theme { + inherit colors; + pathStyle = "full"; + promptGlyph = "> "; + powerline = false; + upstreamIcon = false; + osIcon = false; + }; +} diff --git a/modules/programs/scripts/cdfzf.sh b/modules/dotfiles/scripts/cdfzf.sh similarity index 100% rename from modules/programs/scripts/cdfzf.sh rename to modules/dotfiles/scripts/cdfzf.sh diff --git a/modules/programs/scripts/custom-fzf-preview.sh b/modules/dotfiles/scripts/custom-fzf-preview.sh similarity index 100% rename from modules/programs/scripts/custom-fzf-preview.sh rename to modules/dotfiles/scripts/custom-fzf-preview.sh diff --git a/modules/dotfiles/scripts/default.nix b/modules/dotfiles/scripts/default.nix new file mode 100644 index 0000000..fecdeaf --- /dev/null +++ b/modules/dotfiles/scripts/default.nix @@ -0,0 +1,8 @@ +{lib, ...}: +with lib; { + flake.dotfiles.scripts = { + "hydrate-paths" = readFile ./hydrate-paths.sh; + "custom-fzf-preview" = readFile ./custom-fzf-preview.sh; + "cdfzf" = readFile ./cdfzf.sh; + }; +} diff --git a/modules/programs/scripts/hydrate-paths.sh b/modules/dotfiles/scripts/hydrate-paths.sh similarity index 100% rename from modules/programs/scripts/hydrate-paths.sh rename to modules/dotfiles/scripts/hydrate-paths.sh diff --git a/modules/dotfiles/shell.nix b/modules/dotfiles/shell.nix new file mode 100644 index 0000000..425fcb0 --- /dev/null +++ b/modules/dotfiles/shell.nix @@ -0,0 +1,96 @@ +{ + self, + config, + lib, + ... +} @ global: +with lib; { + flake.dotfiles.shell.getConfiguration = {defaultConfiguration}: ({ + pkgs, + config, + ... + }: + with defaultConfiguration; { + config = with config; { + metadata = { + wrappers = { + atuin = self.wrappers.atuin.wrap {inherit pkgs;}; + editor = self.wrappers.editor.wrap {inherit pkgs;}; + git = self.wrappers.git.wrap {inherit pkgs;}; + }; + }; + + prompt.name = shell.prompt.name; + prompt.getPackage = { + pkgs, + tty ? false, + ... + }: + if tty + then self.wrappers."${prompt.name}-tty".wrap {inherit pkgs;} + else self.wrappers.${prompt.name}.wrap {inherit pkgs;}; + prompt.activationScript = self.dotfiles.${prompt.name}.activationScript.${shell.name} {inherit prompt pkgs;}; + + multiplexer.name = shell.multiplexer.name; + multiplexer.getPackage = self.wrappers.${multiplexer.name}.wrap; + multiplexer.activationScript = self.dotfiles.${multiplexer.name}.activationScript.${shell.name} {inherit pkgs multiplexer;}; + + activationScripts = with pkgs; [ + "command -v fzf &>/dev/null && _anvil_cache_source fzf ${fzf}/bin/fzf --zsh" + "command -v zoxide &>/dev/null && _anvil_cache_source zoxide ${zoxide}/bin/zoxide init zsh --cmd cd" + # "command -v direnv &>/dev/null && _anvil_cache_source direnv ${direnv}/bin/direnv hook zsh" + # "eval \"$(${atuin}/bin/atuin init zsh --disable-up-arrow)\"" + "command -v atuin &>/dev/null && _anvil_cache_source atuin ${atuin}/bin/atuin init zsh" + ]; + + packages = flatten (with pkgs; + with config.metadata.wrappers; [ + (multiplexer.getPackage {inherit pkgs;}) + (prompt.getPackage {inherit pkgs;}) + + # Wrapped + atuin + git + (optional global.config.anvil.programs.editor.metadata.isTerminalBased editor) + + # Scripts + (writeShellScriptBin "hydrate-paths" self.dotfiles.scripts.hydrate-paths) + (writeShellScriptBin "custom-fzf-preview" self.dotfiles.scripts.custom-fzf-preview) + (writeShellScriptBin "cdfzf" self.dotfiles.scripts.cdfzf) + + # Dependencies + bat + chafa + direnv + eza + fd + file + fzf + gcc + gh + imgcat + jq + lazygit + nh + ripgrep + sesh + unixtools.watch + zoxide + (optional pkgs.stdenv.hostPlatform.isLinux wl-clipboard) + ]); + + envVariables = {}; + + shellAliases = { + lg = "lazygit"; + nclean = "nh clean all --optimise -k 3"; + nshell = "nix-shell --command ${shell.name} -p"; + cat = "bat"; + eza = "eza --icons auto --git --group-directories-last"; + ls = "eza"; + find = "fd"; + cd = ". cdfzf"; + }; + }; + }); +} diff --git a/modules/dotfiles/theme.nix b/modules/dotfiles/theme.nix new file mode 100644 index 0000000..8d0ab26 --- /dev/null +++ b/modules/dotfiles/theme.nix @@ -0,0 +1,55 @@ +{ + self, + lib, + ... +}: let + hexColor = + lib.types.strMatching "^#[0-9a-fA-F]{6}$" + // { + description = "6-digit hex color (including '#')"; + }; + + base16Slots = [ + "base00" + "base01" + "base02" + "base03" + "base04" + "base05" + "base06" + "base07" + "base08" + "base09" + "base0A" + "base0B" + "base0C" + "base0D" + "base0E" + "base0F" + ]; +in + with lib; { + flake.modules.generic.colors = {pkgs, ...}: { + options = { + preferences.theme.colors = mkOption { + type = types.submodule { + options = genAttrs base16Slots ( + slot: + mkOption { + type = hexColor; + example = "#1a1b26"; + description = "Base16 slot ${slot}."; + } + ); + }; + description = "A complete Base16 color scheme (base00–base0F as 6-digit hex strings with '#')."; + default = self.lib.getColors; + }; + }; + }; + + flake.lib.getColors = let + theme = builtins.fromJSON (builtins.readFile "${self.dotfiles.resourcesPath}/themes/tokyo-night-moon.json"); + in + theme.palette; + } diff --git a/modules/dotfiles/tmux/scripts.nix b/modules/dotfiles/tmux/scripts.nix new file mode 100644 index 0000000..63e96d5 --- /dev/null +++ b/modules/dotfiles/tmux/scripts.nix @@ -0,0 +1,5 @@ +{lib, ...}: +with lib; { + flake.dotfiles.tmux.scripts.toggle-tmux-popup = {...}: readFile ./toggle-tmux-popup.sh; + flake.dotfiles.tmux.scripts.sessions = {...}: readFile ./sessions.sh; +} diff --git a/modules/programs/scripts/sessions.sh b/modules/dotfiles/tmux/sessions.sh old mode 100755 new mode 100644 similarity index 100% rename from modules/programs/scripts/sessions.sh rename to modules/dotfiles/tmux/sessions.sh diff --git a/modules/dotfiles/tmux/tmux.nix b/modules/dotfiles/tmux/tmux.nix new file mode 100644 index 0000000..ab72ba5 --- /dev/null +++ b/modules/dotfiles/tmux/tmux.nix @@ -0,0 +1,74 @@ +{lib, ...}: +with lib; { + flake.dotfiles.tmux.activationScript.zsh = {...}: '' + if [[ "$TMUX" == "" ]]; then + if [[ "$(tmux ls 2>/dev/null)" == "" ]]; then + tmux new -s kyoten + fi + sesh connect kyoten + fi + ''; + + flake.dotfiles.tmux.default = { + pkgs, + colors, + ... + }: { + prefix = "C-space"; + modeKeys = "vi"; + vimVisualKeys = true; + plugins = with pkgs; [ + tmuxPlugins.sensible + tmuxPlugins.resurrect + tmuxPlugins.yank + ]; + terminal = "tmux-256color"; + terminalOverrides = ",xterm-kitty:Tc,xterm-256color:Tc,linux:Tc"; + configBefore = '' + set -g default-terminal "tmux-256color" + set -g renumber-windows on # keep numbering sequential + set -g focus-events on # Enable focus events for vim autoread + + # Better pane splitting (and keep current path) + bind | split-window -h -c "#{pane_current_path}" + bind - split-window -v -c "#{pane_current_path}" + bind c new-window -c "#{pane_current_path}" + + # Vim-style pane navigation + bind h select-pane -L + bind j select-pane -D + bind k select-pane -U + bind l select-pane -R + + # Vim-style pane resizing + bind -r H resize-pane -L 5 + bind -r J resize-pane -D 5 + bind -r K resize-pane -U 5 + bind -r L resize-pane -R 5 + + # Theme: status + set -g status-style bg=${colors.base00},fg=${colors.base03},bright + set -g status-left " " + set -g status-right "#[fg=orange,bright]#S " + + # Theme: status (windows) + set -g window-status-format "●" + set -g window-status-current-format "●" + + set -g window-status-current-style "#{?window_zoomed_flag,fg=yellow,fg=${colors.base0D}\#,nobold}" + set -g window-status-bell-style "fg=red,nobold" + + bind-key x kill-pane # skip "kill-pane 1? (y/n)" prompt + # NOTE: Commented as it didn't worked well with the {name}' sessions for the floating panes + # set -g detach-on-destroy off # don't exit from tmux when closing a session + + bind-key -r f run-shell "sessions" + bind-key -r l run-shell "toggle-tmux-popup" + bind-key -r g run-shell 'tmux popup -E -d "#{pane_current_path}" -w "90%" -h "90%" -T "LazyGit" "lazygit"' + + set -gq allow-passthrough on + set -g visual-activity off + set-option -g focus-events on + ''; + }; +} diff --git a/modules/programs/scripts/toogle-tmux-popup.sh b/modules/dotfiles/tmux/toggle-tmux-popup.sh similarity index 100% rename from modules/programs/scripts/toogle-tmux-popup.sh rename to modules/dotfiles/tmux/toggle-tmux-popup.sh diff --git a/modules/dotfiles/zsh.nix b/modules/dotfiles/zsh.nix new file mode 100644 index 0000000..d4d0750 --- /dev/null +++ b/modules/dotfiles/zsh.nix @@ -0,0 +1,290 @@ +{lib, ...}: +with lib; { + flake.dotfiles.zsh.default = { + pkgs, + activationScripts ? [], + prompt, + multiplexer, + ... + }: + with pkgs; '' + # Profiling: ZSH_PROFILE_STARTUP=1 zsh -i -c exit + [[ -n ''${ZSH_PROFILE_STARTUP:-} ]] && zmodload zsh/zprof + + # Required by the (#q...) glob qualifiers in the staleness checks below + # (_anvil_cache_source and .zcompdump). Without it those qualifiers are read + # as literal text and every check silently degenerates to always-true, + # regenerating caches on every startup. + # setopt extended_glob + + # XDG cache helpers — cache eval outputs to avoid forking every startup + : ''${XDG_CACHE_HOME:=$HOME/.cache} + [[ -d $XDG_CACHE_HOME/zsh ]] || mkdir -p "$XDG_CACHE_HOME/zsh" 2>/dev/null || true + + _anvil_cache_source() { + local name="$1"; shift + local f="$XDG_CACHE_HOME/zsh/$name.zsh" + # Regenerate if missing or older than 24h (glob qualifier N.mh+24) + if [[ ! -f "$f" || -n "$f"(#qN.mh+24) ]]; then + # Write via temp+rename so concurrent shells never source or zcompile a + # half-written cache; -s guards against caching an empty generation. + local tmp="$f.tmp.$$" + if "$@" > "$tmp" 2>/dev/null && [[ -s "$tmp" ]]; then + mv -f "$tmp" "$f" + # Detach via subshell — braces would register the job in THIS shell + # and leak "[n] pid / [n] + exit N" notifications before the prompt. + [[ -s "$f" ]] && ( zcompile "$f" >/dev/null 2>&1 & ) + else + rm -f "$tmp" 2>/dev/null + return + fi + fi + source "$f" + } + + # Load zsh-defer early so subsequent plugins can be deferred + source ${zsh-defer}/share/zsh-defer/zsh-defer.plugin.zsh + + ${concatStringsSep "\n" activationScripts} + + # Make zsh-completions available BEFORE compinit so its #compdef + # registrations end up in the dump — prepending after compinit leaves the + # plugin ~inert (functions resolve lazily, but nothing registers them). + fpath=(${zsh-completions}/share/zsh/site-functions $fpath) + + # Completion — single cached compinit, compiled + autoload -Uz compinit + # Full regen when the dump is missing OR stale (>24h) — a missing dump used to + # fall through to the same fast `-C` path as a freshly-regenerated one, which is + # wrong on a brand-new $HOME (new machine, wiped cache, etc). + _anvil_zcompdump=''${ZDOTDIR:-$HOME}/.zcompdump + if [[ ! -f "$_anvil_zcompdump" || -n "$_anvil_zcompdump"(#qN.mh+24) ]]; then + compinit -i + else + compinit -C -i + fi + # Compile the dump in a detached subshell (braces would leak job-control + # notifications like "[2] + exit 1 zcompile …" into interactive startups). + [[ -s "$_anvil_zcompdump" ]] && ( zcompile "$_anvil_zcompdump" >/dev/null 2>&1 & ) + unset _anvil_zcompdump + zmodload -i zsh/complist + + # ============================== + # Environment Variables + # ============================== + + HISTFILE=$HOME/.zsh_history + HISTSIZE=100000 + SAVEHIST=$HISTSIZE + + # NOTE: zsh-autosuggestions reads these once at load time — they must stay + # assigned BEFORE the deferred `zsh-defer source` of the plugin below. + ZSH_AUTOSUGGEST_STRATEGY=(history completion) + ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20 + + CORRECT_IGNORE_FILE=".*" + CORRECT_IGNORE="_*" + + # ============================== + # ZSH Options + # ============================== + + setopt auto_cd + setopt correct + setopt interactive_comments + + # History — kept as a compatibility fallback ($HISTFILE still feeds + # zsh-autosuggestions' "history" strategy and any tool that reads it directly). + # Atuin owns interactive search (ctrl-r / up-arrow); see the plugin block below. + setopt hist_expire_dups_first + setopt hist_find_no_dups + setopt hist_ignore_space + setopt hist_ignore_all_dups + setopt hist_reduce_blanks + setopt hist_save_no_dups + setopt hist_verify + # share_history implies inc_append_history semantics + setopt share_history + # Timestamped entries in $HISTFILE (better atuin imports / tooling fidelity) + setopt extended_history + + # Completion / suggestions + setopt auto_list + # (auto_menu intentionally not set: ':completion:* menu no' below disables + # zsh's own menu because fzf-tab owns it) + setopt always_to_end + + # Vi-mode latency: zsh-vi-mode OVERWRITES KEYTIMEOUT during its init + # (KEYTIMEOUT=1 under the default NEX readkey engine), so setting + # KEYTIMEOUT here has no lasting effect. The knob that matters is + # ZVM_KEYTIMEOUT (in SECONDS, default 0.4 — explains any jk/plain-j lag); + # set it next to ZVM_VI_INSERT_ESCAPE_BINDKEY below if mode switching or + # surround combos ever feel sluggish. + + zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}' + zstyle ':completion:*' list-colors "''${(s.:.)LS_COLORS}" + zstyle ':completion:*' menu no + # fzf-tab previews — eza/bat when available, fall back to ls + if command -v eza &>/dev/null; then + zstyle ':fzf-tab:complete:cd:*' fzf-preview 'eza --icons --color=always --group-directories-first $realpath 2>/dev/null || ls --color $realpath' + zstyle ':fzf-tab:complete:*:*' fzf-preview 'if [[ -d $realpath ]]; then eza --icons --color=always --group-directories-first $realpath 2>/dev/null || ls --color $realpath; else bat --color=always --style=numbers --line-range=:100 $realpath 2>/dev/null || cat $realpath 2>/dev/null | head -n 100; fi' + else + zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls --color $realpath' + zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'ls --color $realpath' + fi + zstyle ':fzf-tab:*' use-fzf-default-opts yes + zstyle ':fzf-tab:*' fzf-flags --height=50% --layout=reverse --info=right --border + + # ============================== + # Vi Mode (zsh-vi-mode plugin — sourced last, see Plugins section) + # ============================== + # Keep the `jk` escape muscle memory from the old hand-rolled config. + ZVM_VI_INSERT_ESCAPE_BINDKEY=jk + # Cursor shape (block=normal, beam=insert) is the plugin's default behavior — + # no manual zle-keymap-select/zle-line-init functions needed anymore. + # ZVM_VI_EDITOR=nvim # uncomment if $EDITOR isn't already nvim (used by `vv`) + # If `ds"`/`cs"'`-style surround combos feel laggy or too eager to fire, tune + # ZVM_KEYTIMEOUT here — see the zsh-vi-mode README for units/defaults. + + # zsh-vi-mode runs its own `bindkey -v` on init and will silently clobber any + # keybinding set before it loads (this is a known upstream interaction — see + # jeffreytse/zsh-vi-mode README, "Since ... this plugin will overwrite the + # previous key bindings"). It calls this function automatically once it's done, + # so re-apply everything ZVM might have stomped on here instead of above. + function zvm_after_init() { + # Autosuggestions + bindkey -M viins '^y' autosuggest-accept + bindkey -M viins '^ ' autosuggest-accept + # Edit command line in $EDITOR + bindkey -M viins '^e' edit-command-line + bindkey -M vicmd '^e' edit-command-line + # Completion-friendly space + bindkey -M viins ' ' magic-space + # Atuin — ctrl-r and up-arrow, both insert and normal mode. The widget was + # renamed across atuin versions (_atuin_search_widget -> atuin-search); + # bind whichever exists so a version bump can't silently kill the keys. + local _anvil_atuin_widget= + (( $+widgets[_atuin_search_widget] )) && _anvil_atuin_widget=_atuin_search_widget + (( $+widgets[atuin-search] )) && _anvil_atuin_widget=atuin-search + if [[ -n "$_anvil_atuin_widget" ]]; then + bindkey -M viins '^r' "$_anvil_atuin_widget" + bindkey -M vicmd '^r' "$_anvil_atuin_widget" + bindkey -M viins '^[[A' "$_anvil_atuin_widget" + bindkey -M vicmd '^[[A' "$_anvil_atuin_widget" + else + echo "zsh: no known atuin widget found (checked _atuin_search_widget / atuin-search)" >&2 + fi + # Note: vicmd `k`/`j` are intentionally left as plain vi cursor movement + # (correct vi semantics) rather than remapped to history stepping, now that + # Atuin owns search. Flag if you'd rather have them step history instead. + } + + # ============================== + # Keybindings — good terminal + # ============================== + # (actual bindkey calls for these live in zvm_after_init() above; these just + # register the widgets so they exist by the time that hook runs) + + # Edit command in $EDITOR + autoload -Uz edit-command-line + zle -N edit-command-line + + # Bracketed paste + URL quoting (widget-name overrides, no bindkey needed) + autoload -Uz bracketed-paste-magic url-quote-magic + zle -N bracketed-paste bracketed-paste-magic + zle -N self-insert url-quote-magic + + # ============================== + # Hooks — always on. Each function guards itself against irrelevant + # directories (auto_venv/auto_nvm only act when a .venv/.nvmrc exists), so + # there's no separate env-var switch to remember to flip. This file is + # generated — to disable one on a specific machine, filter it out of the + # hook array from ~/.zshrc.local instead of editing here: + # chpwd_hooks=(''${chpwd_hooks:#auto_venv}) + # ============================== + autoload -Uz add-zsh-hook + + function auto_venv() { + # Deactivate when leaving the venv's project tree. Path-prefix match — a + # plain substring test would treat sibling dirs (proj vs proj-v2) as + # "still inside" and keep a stale venv active. + if [[ -n "$VIRTUAL_ENV" && "$PWD" != "''${VIRTUAL_ENV:h}"(|/*) ]]; then + deactivate 2>/dev/null || true + return + fi + [[ -n "$VIRTUAL_ENV" ]] && return + local dir="$PWD" + while [[ "$dir" != "/" ]]; do + if [[ -f "$dir/.venv/bin/activate" ]]; then + source "$dir/.venv/bin/activate" + return + fi + dir="''${dir:h}" + done + } + + function auto_nvm() { + # Prefer fnm (3-60ms) over nvm.sh (300-1500ms). This shim keeps .nvmrc compat + # without eager sourcing. Uncomment if you still use nvm.sh. + # [[ -f .nvmrc ]] && command -v nvm &>/dev/null && nvm use + # NOTE: mise users should rely on `mise activate zsh` instead — its + # legacy_version_file support honors .nvmrc automatically. Never call + # `mise use` from a hook: it WRITES a config file into the project on cd. + if [[ -f .nvmrc ]] && command -v fnm &>/dev/null; then + fnm use --silent-if-unchanged 2>/dev/null || true + fi + } + + add-zsh-hook chpwd auto_venv + add-zsh-hook chpwd auto_nvm + + # ============================== + # Plugins — deferred for speed (zsh-defer) + # Good terminal: autosuggestions + fzf-tab + fast highlight + real vi-mode + # ============================== + + # Defer UI plugins past first prompt. + # Order matters: fzf-tab must load after compinit (already true) but BEFORE any + # plugin that wraps zle widgets (autosuggestions, fast-syntax-highlighting) — + # see Aloxaf/fzf-tab README, "Important" section. zsh-vi-mode must load LAST, + # since it takes over bindkey -v and would otherwise clobber the others. + zsh-defer source ${zsh-fzf-tab}/share/fzf-tab/fzf-tab.plugin.zsh + zsh-defer source ${zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh + # fast-syntax-highlighting; ~200KB, faster than zsh-syntax-highlighting + zsh-defer source ${zsh-fast-syntax-highlighting}/share/zsh/plugins/fast-syntax-highlighting/fast-syntax-highlighting.plugin.zsh + # zsh-defer source ${zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh + # zsh-vi-mode — real vim editing (surround, text objects, `vv` to edit in $EDITOR) + zsh-defer source ${zsh-vi-mode}/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh + + # No prompt — configure manually if desired: + # starship: eval "$(starship init zsh)" (or _anvil_cache_source starship starship init zsh) + # oh-my-posh: eval "$(oh-my-posh init zsh --config ~/.config/omp.json)" + # p10k: add instant-prompt snippet at top of this file + + # Allow per-user overrides without editing this dotfile + [[ -f ''${ZDOTDIR:-$HOME}/.zshrc.local ]] && source ''${ZDOTDIR:-$HOME}/.zshrc.local + + # NOTE: zprof only sees work done while sourcing this file — plugins loaded + # through zsh-defer run AFTER this point and are invisible to the report. + [[ -n ''${ZSH_PROFILE_STARTUP:-} ]] && zprof | head -n 40 + + ${prompt.activationScript} + + ${multiplexer.activationScript} + ''; + + # Ready-made activation snippets for `default`'s `activationScripts` parameter. + # Each guards on PATH because under Nix a bare store-path check is always true + # once the tool is in the closure — only `command -v` tells you the machine + # actually wants that tool's shell integration. + # flake.dotfiles.zsh.toolInit = {pkgs, ...}: + # with pkgs; { + # fzf = "command -v fzf &>/dev/null && _anvil_cache_source fzf ${fzf}/bin/fzf --zsh"; + # zoxide = "command -v zoxide &>/dev/null && _anvil_cache_source zoxide ${zoxide}/bin/zoxide init zsh --cmd cd"; + # direnv = "command -v direnv &>/dev/null && _anvil_cache_source direnv ${direnv}/bin/direnv hook zsh"; + # # First time on a new machine: `atuin import auto` seeds it from ~/.zsh_history. + # # `atuin login` (or `atuin register`) opts that machine into encrypted sync — + # # worth wiring the sync key through sops-nix later so it's provisioned, not manual. + # atuin = "command -v atuin &>/dev/null && _anvil_cache_source atuin ${atuin}/bin/atuin init zsh"; + # }; +} diff --git a/modules/features/configurations/bluetooth.nix b/modules/features/configurations/bluetooth.nix new file mode 100644 index 0000000..4cbaf2c --- /dev/null +++ b/modules/features/configurations/bluetooth.nix @@ -0,0 +1,28 @@ +{...}: { + anvil.features.bluetooth = { + nixos = { + host, + user, + ... + }: { + config = { + services.blueman.enable = true; + + hardware.enableAllFirmware = true; + hardware.bluetooth = { + enable = true; + powerOnBoot = true; + settings = { + General = { + Name = + if user != null + then "${user.name}-${host.name}" + else "${host.metadata.mainUser}-${host.name}"; + Experimental = true; + }; + }; + }; + }; + }; + }; +} diff --git a/modules/features/configurations/boot.nix b/modules/features/configurations/boot.nix new file mode 100644 index 0000000..3e8d09f --- /dev/null +++ b/modules/features/configurations/boot.nix @@ -0,0 +1,39 @@ +{lib, ...}: +with lib; { + anvil.features.boot = { + nixos = { + host, + pkgs, + config, + ... + }: { + config = { + boot = { + # Quiet boot + consoleLogLevel = 0; + initrd.verbose = false; + + kernelParams = [ + "quiet" + "loglevel=3" + "rd.systemd.show_status=false" + "rd.udev.log_level=3" + "udev.log_priority=3" + ]; + kernelModules = ["ddcci-backlight"]; + kernelPackages = pkgs.linuxPackages_latest; + extraModulePackages = with config.boot.kernelPackages; [ddcci-driver]; + + loader.systemd-boot = { + enable = mkDefault true; + configurationLimit = mkDefault host.metadata.configurationLimit; + }; + loader.efi.canTouchEfiVariables = true; + loader.timeout = 30; + + plymouth.enable = true; + }; + }; + }; + }; +} diff --git a/modules/features/configurations/configurations.nix b/modules/features/configurations/configurations.nix new file mode 100644 index 0000000..ace7ea9 --- /dev/null +++ b/modules/features/configurations/configurations.nix @@ -0,0 +1,148 @@ +{ + inputs, + lib, + ... +}: +with lib; { + anvil.features.configurations = { + features = [ + "bluetooth" + "boot" + "gc" + "powersave" + "theme" + ]; + darwin = { + host, + config, + ... + }: { + imports = [inputs.mac-app-util.darwinModules.default]; + + config = { + nix.settings.experimental-features = "nix-command flakes"; + system.configurationRevision = inputs.self.rev or inputs.self.dirtyRev or null; + nixpkgs.config.allowUnfree = true; + nixpkgs.config.allowBroken = true; + + # networking.hostName = "${host.metadata.mainUser}-${host.name}"; + + system.primaryUser = host.metadata.mainUser; + launchd.user.envVariables = { + PATH = config.environment.systemPath; + }; + }; + }; + + nixos = { + config, + host, + ... + }: { + config = { + nix.settings.experimental-features = ["nix-command" "flakes"]; + nixpkgs.config.allowUnfree = true; + nixpkgs.config.allowBroken = true; + programs.nix-ld.enable = true; + + services.xserver.videoDrivers = ["nvidia"]; + hardware = { + i2c.enable = true; + graphics = { + enable = true; + enable32Bit = true; + }; + nvidia = { + # Enable modesetting for Wayland compositors + modesetting.enable = true; + # Use the open source version of the kernel module (for driver 515.43.04+) + open = true; + # Enable the Nvidia settings menu + nvidiaSettings = true; + # Select the appropriate driver version for your specific GPU + package = config.boot.kernelPackages.nvidiaPackages.stable; + powerManagement.enable = true; + }; + }; + + virtualisation.vmVariant = { + virtualisation.graphics = true; + virtualisation.qemu.options = [ + "-device virtio-vga-gl" + "-display gtk,gl=on" + ]; + }; + + services.printing.enable = true; + + services.pulseaudio.enable = false; + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + # To use JACK applications + # jack.enable = true; + }; + + networking.networkmanager.enable = true; + networking.hostName = "${host.metadata.mainUser}-${host.name}"; + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + + time.timeZone = mkDefault "America/Costa_Rica"; + + # Select internationalisation properties. + i18n.defaultLocale = mkDefault "en_US.UTF-8"; + i18n.extraLocaleSettings = mkDefault { + LC_ADDRESS = "es_CR.UTF-8"; + LC_IDENTIFICATION = "es_CR.UTF-8"; + LC_MEASUREMENT = "es_CR.UTF-8"; + LC_MONETARY = "es_CR.UTF-8"; + LC_NAME = "es_CR.UTF-8"; + LC_NUMERIC = "es_CR.UTF-8"; + LC_PAPER = "es_CR.UTF-8"; + LC_TELEPHONE = "es_CR.UTF-8"; + LC_TIME = "es_CR.UTF-8"; + }; + + services.xserver.xkb = { + layout = "us"; + variant = ""; + options = "compose:ralt"; + }; + environment.variables = { + # GTK_IM_MODULE = "xim"; + # QT_IM_MODULE = "xim"; + }; + + security.polkit.enable = true; + security.polkit.enablePkexecWrapper = true; + # environment.systemPackages = [pkgs.polkit_gnome]; NOTE: Using the built-in noctalia polkit-agent + services.fprintd.enable = true; + + services.gnome.gnome-keyring.enable = true; + security.pam.services.greetd.enableGnomeKeyring = true; + + services.logind.settings.Login = { + HandleLidSwitch = "suspend"; # Lid Closed + HandleLidSwitchExternalPower = "suspend"; # Lid Closed while connected to power + HandleLidSwitchDocked = "ignore"; # Lic Closed while connected to another screens + }; + # one of "ignore", "poweroff", "reboot", "halt", "kexec", "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate", "lock" + + # Faster rebuilding + documentation = { + enable = true; + doc.enable = false; + man.enable = true; + dev.enable = false; + info.enable = false; + nixos.enable = false; + }; + + system.stateVersion = host.stateVersion; + }; + }; + }; +} diff --git a/modules/features/configurations/gc.nix b/modules/features/configurations/gc.nix new file mode 100644 index 0000000..c1a01b6 --- /dev/null +++ b/modules/features/configurations/gc.nix @@ -0,0 +1,84 @@ +{lib, ...}: +with lib; { + anvil.features.gc = { + nixos = { + host, + user, + config, + pkgs, + ... + }: { + config = let + notify = user: msg: + "${pkgs.sudo}/bin/sudo -u ${user} " + + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(${pkgs.coreutils}/bin/id -u ${user})/bus " + + "${pkgs.libnotify}/bin/notify-send ${lib.escapeShellArg msg}"; + username = + if user == null + then host.metadata.mainUser + else user.name; + in { + systemd.services.gc-periodic = { + enable = true; + description = "Periodic nix store cleanup"; + path = [config.nix.package]; + serviceConfig = { + Type = "oneshot"; + ExecStartPre = pkgs.writeShellScript "notify-start" '' + ${notify username "Starting nix store cleanup..."} + ''; + ExecStart = pkgs.writeShellScript "gc-clean" '' + set -e + ${getExe pkgs.nh} clean all --optimise -k ${toString host.metadata.configurationLimit} + ''; + ExecStartPost = pkgs.writeShellScript "notify-done" '' + ${notify username "Nix store cleanup complete"} + ''; + TimeoutStopSec = "5min"; + }; + }; + + systemd.timers.gc-periodic = { + enable = true; + description = "Timer for periodic nix store cleanup via nh"; + wantedBy = ["timers.target"]; + timerConfig = { + OnCalendar = "weekly"; + Persistent = true; + RandomizedDelaySec = "30min"; + }; + }; + }; + }; + + darwin = { + host, + config, + pkgs, + ... + }: { + config = { + launchd.daemons.gc-periodic = { + serviceConfig = { + ProgramArguments = [ + "${pkgs.writeShellScript "gc-clean-darwin" '' + set -e + export PATH="${config.nix.package}/bin:${pkgs.nh}/bin:$PATH" + ${getExe pkgs.nh} clean all --optimise -k ${toString host.metadata.configurationLimit} + ''}" + ]; + StartCalendarInterval = [ + { + Weekday = 1; + Hour = 7; + Minute = 30; + } # Monday 7:30am + ]; + StandardOutPath = "/var/log/gc-periodic.log"; + StandardErrorPath = "/var/log/gc-periodic.log"; + }; + }; + }; + }; + }; +} diff --git a/modules/features/configurations/home.nix b/modules/features/configurations/home.nix new file mode 100644 index 0000000..7134755 --- /dev/null +++ b/modules/features/configurations/home.nix @@ -0,0 +1,93 @@ +{ + inputs, + self, + lib, + config, + ... +}: +with lib; { + anvil.features.homeManager = { + darwin = { + host, + user, + ... + } @ ctx: let + user = + if ctx.user == null + then config.anvil.users.${host.metadata.mainUser} + else ctx.user; + in { + imports = [inputs.home-manager.darwinModules.home-manager]; + + config = { + home-manager.backupFileExtension = "bckp"; + home-manager.users.${user.name} = {...}: { + imports = [inputs.mac-app-util.homeManagerModules.default]; + config = { + programs.home-manager.enable = true; + home = { + username = user.name; + homeDirectory = mkDefault user.homeDir.darwin; + stateVersion = host.stateVersion; + }; + }; + }; + }; + }; + + nixos = { + host, + user, + ... + } @ ctx: let + user = + if ctx.user == null + then config.anvil.users.${host.metadata.mainUser} + else ctx.user; + in { + imports = [inputs.home-manager.nixosModules.default]; + + config = { + home-manager.backupFileExtension = "bckp"; + home-manager.users.${user.name} = {...}: { + config = { + programs.home-manager.enable = true; + home = { + username = user.name; + homeDirectory = mkDefault user.homeDir.nixos; + stateVersion = host.stateVersion; + + file.".XCompose".text = '' + include "%L" + + # Acute accents (mimics macOS Option+e then vowel) + : "á" + : "é" + : "í" + : "ó" + : "ú" + : "Á" + : "É" + : "Í" + : "Ó" + : "Ú" + + # Tilde (mimics macOS Option+n then n) + : "ñ" + : "Ñ" + + # Diaeresis + : "ü" + : "Ü" + + # Inverted punctuation + : "¡" + : "¿" + ''; + }; + }; + }; + }; + }; + }; +} diff --git a/modules/features/configurations/powersave.nix b/modules/features/configurations/powersave.nix new file mode 100644 index 0000000..8625a48 --- /dev/null +++ b/modules/features/configurations/powersave.nix @@ -0,0 +1,63 @@ +{...}: { + # Source: https://github.com/vimjoyer/nixconf/blob/main/nixos/features/powersave.nix + anvil.features.powersave = { + nixos = { + pkgs, + lib, + ... + }: { + boot.kernelParams = ["usbcore.autosuspend=500" "amd_pstate=active"]; + services.power-profiles-daemon.enable = true; + services.thermald.enable = true; + services.upower.enable = true; + powerManagement.enable = true; + powerManagement.powertop.enable = true; + + # hardware.amdgpu.overdrive.enable = true; + services.lact.enable = true; + + systemd.services.lact-monitor = { + enable = true; + description = "Monitor PowerProfiles and update LACT profile"; + after = ["network.target" "lactd.service" "power-profiles-daemon.service"]; + wants = ["lactd.service" "power-profiles-daemon.service"]; + serviceConfig = { + Type = "simple"; + ExecStartPre = lib.getExe (pkgs.writeShellApplication { + name = "lact-initial-set"; + runtimeInputs = [pkgs.lact pkgs.glib pkgs.dbus pkgs.power-profiles-daemon]; + text = '' + profile=$(powerprofilesctl get) + if [[ $profile == "power-saver" ]]; then + lact cli profile set "power-saver" + else + lact cli profile set "default" + fi + ''; + }); + ExecStart = lib.getExe (pkgs.writeShellApplication { + name = "lact-watcher"; + runtimeInputs = [pkgs.libnotify pkgs.lact pkgs.glib pkgs.dbus]; + text = '' + gdbus monitor --system --dest net.hadess.PowerProfiles | + while read -r line; do + if [[ $line =~ ActiveProfile ]]; then + profile=$(echo "$line" | grep -oP "(?<=<').+?(?='>)") + + if [[ $profile == "power-saver" ]]; then + lact cli profile set "power-saver" + else + lact cli profile set "default" + fi + fi + done + ''; + }); + Restart = "always"; + User = "root"; + }; + wantedBy = ["multi-user.target"]; + }; + }; + }; +} diff --git a/modules/features/configurations/theme.nix b/modules/features/configurations/theme.nix new file mode 100644 index 0000000..b2a2ec3 --- /dev/null +++ b/modules/features/configurations/theme.nix @@ -0,0 +1,26 @@ +{lib, ...}: +with lib; { + anvil.features.theme = { + home = {pkgs, ...}: let + cursor_theme_name = "BreezeX-RosePine-Linux"; + in { + config.home = mkIf pkgs.stdenv.hostPlatform.isLinux { + packages = with pkgs; [rose-pine-cursor]; + sessionVariables = { + XCURSOR_THEME = cursor_theme_name; + XCURSOR_SIZE = "25"; + }; + pointerCursor = { + enable = true; + gtk.enable = true; + x11.enable = true; + # package = pkgs.bibata-cursors; + # name = "Bibata-Modern-Classic"; + package = pkgs.rose-pine-cursor; + name = cursor_theme_name; + size = 25; + }; + }; + }; + }; +} diff --git a/modules/features/default.nix b/modules/features/default.nix deleted file mode 100644 index bf1f17f..0000000 --- a/modules/features/default.nix +++ /dev/null @@ -1,96 +0,0 @@ -{ - self, - inputs, - lib, - ... -}: -with lib; { - options = { - flake = inputs.flake-parts.lib.mkSubmoduleOptions { - features = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - }; - }; - - config = rec { - flake.lib.mkHomeFeature = name: module: ({ - pkgs, - config, - ... - } @ inputs: let - cfg = config.preferences.features.${name}; - moduleEvaluated = module (inputs // {inherit cfg;}); - in { - imports = - [ - self.features.${name} - ] - ++ (moduleEvaluated.imports or []); - - options = moduleEvaluated.options or {}; - - config = mkIf cfg.enable ({ - preferences.programs = cfg.programs; - home.packages = cfg.packages; - } - // (moduleEvaluated.config or {})); - }); - - flake.lib.mkDarwinFeature = flake.lib.mkNixosFeature; - flake.lib.mkNixosFeature = name: module: ({ - pkgs, - config, - ... - } @ inputs: let - cfg = config.preferences.features.${name}; - moduleEvaluated = module (inputs // {inherit cfg;}); - in { - imports = - [ - self.features.${name} - ] - ++ (moduleEvaluated.imports or []); - - options = moduleEvaluated.options or {}; - - config = mkIf cfg.enable ({ - preferences.programs = cfg.programs; - environment.systemPackages = cfg.packages; - } - // (moduleEvaluated.config or {})); - }); - - flake.lib.mkFeature = name: module: ({ - pkgs, - config, - ... - } @ inputs: let - cfg = config.preferences.features.${name}; - moduleEvaluated = module (inputs // {inherit cfg;}); - in { - imports = moduleEvaluated.imports or []; - - options.preferences.features.${name} = { - enable = mkEnableOption "Whether to enable the ${name} feature."; - programs = mkOption { - type = types.attrs; - description = "The programs and their configurations to enable with this feature."; - default = {}; - }; - - packages = mkOption { - type = types.listOf types.package; - description = "The list of packages to install with this feature."; - default = []; - }; - - configurations = moduleEvaluated.configurations or {}; - }; - - config = mkIf cfg.enable { - preferences.features.${name} = moduleEvaluated.config or {}; - }; - }); - }; -} diff --git a/modules/features/development.nix b/modules/features/development.nix deleted file mode 100644 index 277d33a..0000000 --- a/modules/features/development.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ - self, - lib, - ... -}: -with lib; let - name = "development"; -in { - flake.darwinModules.features = self.lib.mkDarwinFeature name ({...}: {}); - - flake.homeModules.features = self.lib.mkHomeFeature name ({...}: {}); - - flake.nixosModules.features = self.lib.mkNixosFeature name ({ - cfg, - config, - ... - }: { - config = { - # NOTE: Be aware of: https://github.com/moby/moby/issues/9976 - # users.users.${config.profile.user.username}.extraGroups = [ "docker" ]; - virtualisation.docker = mkIf cfg.configurations.docker.enable { - enable = true; - autoPrune.enable = true; - rootless = { - enable = true; - setSocketVariable = true; - daemon.settings = {}; - }; - }; - programs.java.enable = cfg.configurations.java.enable; - }; - }); - - flake.features.${name} = self.lib.mkFeature name ({ - pkgs, - cfg, - ... - }: { - configurations = { - docker.enable = mkEnableOption "Whether to enable docker."; - go.enable = mkEnableOption "Whether to enable the Go programming language."; - java.enable = mkEnableOption "Whether to enable the Java programming language."; - rust.enable = mkEnableOption "Whether to enable the Rust programming language."; - python.enable = mkEnableOption "Whether to enable the Python programming language."; - node.enable = mkEnableOption "Whether to enable the Web development ecosystem. (Js, Node, ...)."; - }; - config = { - configurations = { - docker.enable = mkDefault true; - go.enable = mkDefault true; - }; - - packages = with pkgs; let - goPakcages = - if cfg.configurations.go.enable - then [ - go - goperf - ] - else []; - rustPackages = - if cfg.configurations.rust.enable - then [ - cargo - rustc - ] - else []; - pythonPackages = - if cfg.configurations.python.enable - then [ - (python3.withPackages (python-pkgs: - with python-pkgs; [ - pandas - requests - ])) - ] - else []; - nodejsPackages = - if cfg.configurations.node.enable - then [ - nodejs - ] - else []; - javaPackages = - if cfg.configurations.java.enable - then [ - jdk21 - gradle - ] - else []; - in - goPakcages - ++ rustPackages - ++ pythonPackages - ++ nodejsPackages - ++ javaPackages; - }; - }); -} diff --git a/modules/features/docker.nix b/modules/features/docker.nix new file mode 100644 index 0000000..841d4e4 --- /dev/null +++ b/modules/features/docker.nix @@ -0,0 +1,20 @@ +{lib, ...}: +with lib; { + anvil.features.docker = { + nixos = {user, ...}: { + # NOTE: Be aware of: https://github.com/moby/moby/issues/9976 + # users.users = mkIf (user != null) { + # ${user.name}.extraGroups = [ "docker" ]; + # }; + virtualisation.docker = { + enable = true; + autoPrune.enable = true; + rootless = { + enable = true; + setSocketVariable = true; + daemon.settings = {}; + }; + }; + }; + }; +} diff --git a/modules/features/gaming.nix b/modules/features/gaming.nix index a01a732..41eca5a 100644 --- a/modules/features/gaming.nix +++ b/modules/features/gaming.nix @@ -1,51 +1,10 @@ -{ - inputs, - self, - lib, - ... -}: -with lib; let - name = "gaming"; -in { - flake.darwinModules.features = self.lib.mkDarwinFeature name ({...}: {}); - - flake.homeModules.features = self.lib.mkHomeFeature name ({...}: {}); - - flake.nixosModules.features = self.lib.mkNixosFeature name ({ - config, - cfg, - ... - }: { - imports = [inputs.jovian.nixosModules.jovian]; - - config = { - jovian = { - hardware.has.amd.gpu = cfg.configurations.gpu.isAMD; - # devices.gpd-win-max-2.enable = true; - steam = { - enable = true; - autoStart = false; # Start Steam in Big Picture mode at boot - user = config.profile.user.username; - # desktopSession = "gamescope-wayland"; - }; - }; - }; - }); - - flake.features.${name} = self.lib.mkFeature name ({pkgs, ...}: { - configurations = { - gpu.isAMD = mkOption { - type = types.bool; - description = "Whether the gpu is AMD or not."; - default = false; - }; - }; - config = { - programs = { - steam.enable = true; - }; - - packages = with pkgs; [ +{...}: { + anvil.features.gaming = { + programs = [ + "steam" + ]; + nixos = {pkgs, ...}: { + environment.systemPackages = with pkgs; [ # Communication discord @@ -59,5 +18,5 @@ in { protonup-ng ]; }; - }); + }; } diff --git a/modules/features/jovian.nix b/modules/features/jovian.nix new file mode 100644 index 0000000..e4cf71a --- /dev/null +++ b/modules/features/jovian.nix @@ -0,0 +1,29 @@ +{ + inputs, + lib, + ... +}: +with lib; { + anvil.features.jovian = { + features = [ + "gaming" + ]; + nixos = { + host, + user, + ... + }: { + imports = [inputs.jovian.nixosModules.jovian]; + + jovian = { + hardware.has.amd.gpu = host.metadata.gpu.isAMD or false; + steam = { + enable = true; + autoStart = false; # Start Steam in Big Picture mode at boot + user = mkIf (user != null) user.name; + # desktopSession = "gamescope-wayland"; + }; + }; + }; + }; +} diff --git a/modules/features/services/lock-before-suspend.nix b/modules/features/services/lock-before-suspend.nix new file mode 100644 index 0000000..32ac9b2 --- /dev/null +++ b/modules/features/services/lock-before-suspend.nix @@ -0,0 +1,52 @@ +{ + config, + lib, + ... +} @ global: +with lib; { + anvil.features.lock-before-suspend = { + nixos = { + pkgs, + user, + ... + }: let + noctalia = global.config.anvil.programs.noctalia.getPackage {inherit pkgs;}; + in { + assertions = [ + { + assertion = user != null; + message = "The lock-before-suspend requires a user, but user is null"; + } + ]; + systemd.services.lock-before-suspend = { + enable = true; + description = "Locks the session before sleep"; + wantedBy = ["sleep.target"]; + before = ["sleep.target"]; + serviceConfig = { + Type = "oneshot"; + User = user.name; + ExecStart = pkgs.writeShellScript "lock-screen" '' + set -e + ${getExe noctalia} msg session lock + + for i in $(seq 1 20); do + locked=$(${getExe noctalia} msg status | ${getExe pkgs.jq} .locked) + if [ "$locked" = "true" ]; then + exit 0 + fi + sleep 0.1 + done + + echo "Timed out waiting for session lock" >&2 + exit 1 + ''; + }; + environment = { + XDG_RUNTIME_DIR = "/run/user/${toString config.users.users.${user.name}.uid}"; + WAYLAND_DISPLAY = "wayland-1"; + }; + }; + }; + }; +} diff --git a/modules/features/services/usb.nix b/modules/features/services/usb.nix new file mode 100644 index 0000000..a843eea --- /dev/null +++ b/modules/features/services/usb.nix @@ -0,0 +1,11 @@ +{lib, ...}: +with lib; { + anvil.features.usb = { + nixos = {...}: { + services.udisks2.enable = true; + }; + home = {pkgs, ...}: { + services.udiskie.enable = mkIf pkgs.stdenv.hostPlatform.isLinux true; + }; + }; +} diff --git a/modules/features/sops.nix b/modules/features/sops.nix new file mode 100644 index 0000000..392e1b5 --- /dev/null +++ b/modules/features/sops.nix @@ -0,0 +1,25 @@ +{inputs, ...}: { + anvil.features.sops = let + commonModule = {pkgs, ...}: let + ageKeyPath = "/var/lib/sops-nix/key.txt"; + in { + environment.variables.SOPS_AGE_KEY_FILE = ageKeyPath; + environment.systemPackages = with pkgs; [age sops]; + sops.age.keyFile = ageKeyPath; + sops.age.generateKey = true; + }; + in { + nixos = {...}: { + imports = [ + inputs.sops-nix.nixosModules.sops + commonModule + ]; + }; + darwin = {...}: { + imports = [ + inputs.sops-nix.darwinModules.sops + commonModule + ]; + }; + }; +} diff --git a/modules/hosts/default.nix b/modules/hosts/default.nix deleted file mode 100644 index 25dc2bb..0000000 --- a/modules/hosts/default.nix +++ /dev/null @@ -1,61 +0,0 @@ -{ - inputs, - self, - lib, - ... -}: -with lib; { - options = { - flake = inputs.flake-parts.lib.mkSubmoduleOptions { - hosts = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - }; - }; - - config = { - flake.nixosModules.configurations = {...}: { - imports = [self.hosts.module]; - }; - - flake.darwinModules.configurations = {...}: { - imports = [self.hosts.module]; - }; - - flake.hosts.module = {config, ...}: { - options.preferences = { - stateVersion = mkOption { - type = types.str; - description = "The state version to be used on `system.stateVersion` and `home.stateVersion` options"; - default = "25.11"; - }; - - boot = { - configurationLimit = mkOption { - type = types.number; - description = "The limit of generations to show."; - default = 3; - }; - }; - }; - - options.information = { - isLaptop = mkEnableOption "Whether the host is a laptop."; - hasBluetooth = mkEnableOption "Whether the host has Bluetooth."; - hasBattery = mkEnableOption "Whether the host has Bluetooth."; - hostname = mkOption { - type = types.str; - description = "The name of the configuration's host."; - }; - }; - - config = { - information = { - isLaptop = mkDefault false; - hasBluetooth = mkDefault true; - hasBattery = mkDefault config.information.isLaptop; - }; - }; - }; - }; -} diff --git a/modules/hosts/gpd.nix b/modules/hosts/gpd.nix index 369c511..47d3f64 100644 --- a/modules/hosts/gpd.nix +++ b/modules/hosts/gpd.nix @@ -1,87 +1,26 @@ { - inputs, self, + lib, ... -}: let - host = "gpd"; -in { - flake.nixosConfigurations.${host} = inputs.nixpkgs.lib.nixosSystem { - modules = [self.nixosModules.${host}]; - }; - - flake.nixosModules.${host} = {...}: { - imports = [ - self.nixosModules.configurations - self.nixosModules."${host}-hardware" +}: +with lib; { + anvil.hosts.gpd = { + systems.nixos = "x86_64-linux"; + users = {host, ...}: [host.metadata.mainUser]; + features = [ + "configurations" + "jovian" ]; - - config = { - # Unccomment to disable fingerprint for sudo and polkit - # security.pam.services = { - # sudo.fprintAuth = false; - # polkit-1.fprintAuth = false; - # }; - - information = { - hostname = "gpd"; - isLaptop = true; - hasBluetooth = true; - hasBattery = true; - }; - - preferences = { - profile = "personal"; - - features = { - gaming = { - enable = true; - configurations.gpu.isAMD = true; - }; - }; - - programs = { - desktop = { - enable = true; - configurations = { - monitors = rec { - HDMI-A-1 = { - enabled = true; - primary = true; - x = 2560; - y = 140; - width = 1920; - height = 1080; - refreshRate = 143.981; - }; - HDMI-A-2 = HDMI-A-1; - - DP-1 = { - enabled = true; - primary = false; - x = 0; - y = 0; - width = 2560; - height = 1440; - refreshRate = 74.932; - }; - DP-2 = DP-1; - DP-3 = DP-1; - - eDP-1 = { - enabled = true; - primary = false; - x = 629; - y = 1440; - width = 2560; - height = 1600; - refreshRate = 60.009; - scale = 2.0; - }; - }; - }; - }; - }; - }; + programs = []; + metadata = rec { + mainUser = "aaronv"; + configurationLimit = 3; + gpu.isAMD = true; + isGPD = true; + nixPath = "/home/${mainUser}/nix"; + }; + nixos = {...}: { + imports = [self.nixosModules."gpd-hardware"]; nixpkgs.overlays = [ (final: prev: { @@ -104,10 +43,46 @@ in { }); }) ]; + + anvil.desktop.preferences.monitors = rec { + HDMI-A-1 = { + enabled = true; + primary = true; + x = 2560; + y = 140; + width = 1920; + height = 1080; + refreshRate = 143.981; + }; + HDMI-A-2 = HDMI-A-1; + + DP-1 = { + enabled = true; + primary = false; + x = 0; + y = 0; + width = 2560; + height = 1440; + refreshRate = 74.932; + }; + DP-2 = DP-1; + DP-3 = DP-1; + + eDP-1 = { + enabled = true; + primary = false; + x = 629; + y = 1440; + width = 2560; + height = 1600; + refreshRate = 60.009; + scale = 2.0; + }; + }; }; }; - flake.nixosModules."${host}-hardware" = { + flake.nixosModules."gpd-hardware" = { config, lib, pkgs, diff --git a/modules/hosts/laptop.nix b/modules/hosts/laptop.nix index 49f96d0..4946ed4 100644 --- a/modules/hosts/laptop.nix +++ b/modules/hosts/laptop.nix @@ -1,77 +1,62 @@ { - inputs, self, + lib, ... -}: let - host = "laptop"; -in { - flake.nixosConfigurations.${host} = inputs.nixpkgs.lib.nixosSystem { - modules = [self.nixosModules.${host}]; - }; - - flake.nixosModules.${host} = {pkgs, ...}: { - imports = [ - self.nixosModules.configurations - self.nixosModules."${host}-hardware" +}: +with lib; { + anvil.hosts.laptop = { + systems.nixos = "x86_64-linux"; + users = {host, ...}: [host.metadata.mainUser]; + features = [ + "configurations" ]; - - config = { - information = { - hostname = "laptop"; - isLaptop = true; - hasBluetooth = true; - hasBattery = true; - }; - - preferences = { - profile = "personal"; - - features = { - gaming.enable = false; + programs = []; + metadata = rec { + mainUser = "aaronv"; + configurationLimit = 3; + nixPath = "/home/${mainUser}/nix"; + }; + nixos = {pkgs, ...}: { + imports = [self.nixosModules."laptop-hardware"]; + anvil.desktop.preferences.modKey = "alt"; + anvil.desktop.preferences.modKeyAlt = "super"; + anvil.desktop.preferences.monitors = rec { + DP-1 = { + enabled = true; + primary = true; + x = 0; + y = 0; + width = 1920; + height = 1080; + refreshRate = 143.981; }; - programs = { - desktop = { - enable = true; - configurations = { - modKey = "alt"; - modKeyAlt = "super"; - monitors = rec { - DP-1 = { - enabled = true; - primary = true; - x = 0; - y = 0; - width = 1920; - height = 1080; - refreshRate = 143.981; - }; - - HDMI-A-2 = rec { - enabled = true; - primary = false; - x = -width; - y = 0; - width = 2560; - height = 1440; - refreshRate = 74.932; - }; + HDMI-A-2 = rec { + enabled = true; + primary = false; + x = -width; + y = 0; + width = 2560; + height = 1440; + refreshRate = 74.932; + }; - eDP-1 = rec { - enabled = true; - primary = false; - x = -HDMI-A-2.x; - y = -height; - width = 1920; - height = 1080; - refreshRate = 59.977; - }; - }; - }; - }; + eDP-1 = rec { + enabled = true; + primary = false; + x = -HDMI-A-2.x; + y = -height; + width = 1920; + height = 1080; + refreshRate = 59.977; }; }; + virtualisation.vmVariant = { + anvil.desktop.preferences.modKey = mkForce "super"; + anvil.desktop.preferences.modKeyAlt = mkForce "alt"; + }; + hardware.graphics = { enable = true; extraPackages = with pkgs; [ @@ -84,7 +69,7 @@ in { }; }; - flake.nixosModules."${host}-hardware" = { + flake.nixosModules."laptop-hardware" = { config, lib, pkgs, diff --git a/modules/hosts/mac.nix b/modules/hosts/mac.nix index 878a620..1b46bdf 100644 --- a/modules/hosts/mac.nix +++ b/modules/hosts/mac.nix @@ -1,37 +1,22 @@ { - inputs, - lib, self, + lib, ... -}: let - host = "mac"; -in - with lib; { - flake.darwinConfigurations.${host} = inputs.nix-darwin.lib.darwinSystem { - system = "aarch64-darwin"; - modules = [self.darwinModules.${host}]; +}: +with lib; { + anvil.hosts.mac = { + systems.darwin = "aarch64-darwin"; + users = {host, ...}: [host.metadata.mainUser]; + features = [ + "configurations" + ]; + programs = []; + metadata = rec { + mainUser = "aaronv-work"; + configurationLimit = 3; + nixPath = "/Users/${mainUser}/nix"; }; - - flake.darwinModules.${host} = {...}: { - imports = [ - self.darwinModules.configurations - ]; - - config = { - information = { - hostname = "mac"; - isLaptop = true; - }; - - preferences = { - profile = "work"; - - programs = { - terminal.enable = true; - kitty.enable = true; - aerospace.enable = true; - }; - }; - }; + darwin = {...}: { }; - } + }; +} diff --git a/modules/hosts/pc.nix b/modules/hosts/pc.nix index 51e5de2..a29dc38 100644 --- a/modules/hosts/pc.nix +++ b/modules/hosts/pc.nix @@ -1,72 +1,47 @@ -{ - inputs, - self, - lib, - ... -}: let - host = "pc"; -in { - flake.nixosConfigurations.${host} = inputs.nixpkgs.lib.nixosSystem { - modules = [self.nixosModules.${host}]; - }; - - flake.nixosModules.${host} = {pkgs, ...}: { - imports = [ - self.nixosModules.configurations - self.nixosModules."${host}-hardware" +{self, ...}: { + anvil.hosts.pc = { + systems.nixos = "x86_64-linux"; + users = {host, ...}: [host.metadata.mainUser]; + features = [ + "configurations" + "gaming" ]; - - config = { - information = { - hostname = "pc"; - isLaptop = false; - hasBluetooth = true; - hasBattery = false; - }; - - preferences = { - profile = "personal"; - - features = { - gaming.enable = true; + programs = []; + metadata = rec { + mainUser = "aaronv"; + configurationLimit = 3; + nixPath = "/home/${mainUser}/nix"; + }; + nixos = {...}: { + imports = [self.nixosModules."pc-hardware"]; + anvil.desktop.preferences.monitors = rec { + DP-1 = { + enabled = true; + primary = true; + x = 0; + y = 0; + width = 1920; + height = 1080; + refreshRate = 143.981; }; + DP-2 = DP-1; + DP-3 = DP-1; - programs = { - desktop = { - enable = true; - configurations = { - monitors = rec { - DP-1 = { - enabled = true; - primary = true; - x = 0; - y = 0; - width = 1920; - height = 1080; - refreshRate = 143.981; - }; - DP-2 = DP-1; - DP-3 = DP-1; - - HDMI-A-1 = rec { - enabled = true; - primary = false; - x = -width; - y = 0; - width = 2560; - height = 1440; - refreshRate = 74.932; - }; - HDMI-A-2 = HDMI-A-1; - }; - }; - }; + HDMI-A-1 = rec { + enabled = true; + primary = false; + x = -width; + y = 0; + width = 2560; + height = 1440; + refreshRate = 74.932; }; + HDMI-A-2 = HDMI-A-1; }; }; }; - flake.nixosModules."${host}-hardware" = { + flake.nixosModules."pc-hardware" = { config, lib, pkgs, diff --git a/modules/lib/lib.nix b/modules/lib/lib.nix deleted file mode 100644 index 57ba548..0000000 --- a/modules/lib/lib.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ - inputs, - lib, - ... -}: -with lib; { - options = { - flake = inputs.flake-parts.lib.mkSubmoduleOptions { - lib = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - }; - }; - - config.flake.lib = { - resourcesPath = ../../resources; - }; -} diff --git a/modules/profiles/default.nix b/modules/profiles/default.nix deleted file mode 100644 index 4e0d49d..0000000 --- a/modules/profiles/default.nix +++ /dev/null @@ -1,122 +0,0 @@ -{ - inputs, - self, - lib, - ... -}: -with lib; { - options = { - flake = inputs.flake-parts.lib.mkSubmoduleOptions { - profile = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - - profiles.generic = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - - profiles.nixos = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - - profiles.home = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - - profiles.darwin = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - }; - }; - - config = rec { - flake.lib.mkHomeProfile = flake.lib.mkNixosProfile; - flake.lib.mkDarwinProfile = flake.lib.mkNixosProfile; - - flake.lib.mkNixosProfile = profile: preferences: ({ - config, - pkgs, - ... - } @ inputs: { - config = mkIf (config.preferences.profile == profile) ({ - preferences = { - programs = config.profile.programs; - features = config.profile.features; - }; - } - // preferences inputs); - }); - - flake.lib.mkProfile = profile: preferences: ({ - config, - pkgs, - ... - }: { - config = mkIf (config.preferences.profile == profile) (preferences {inherit config pkgs;}); - }); - - flake.nixosModules.profile = {...}: { - imports = - [ - self.profile.module - ] - ++ builtins.attrValues self.profiles.nixos; - }; - - flake.homeModules.profile = {...}: { - imports = - [ - self.profile.module - ] - ++ builtins.attrValues self.profiles.home; - }; - - flake.darwinModules.profile = {...}: { - imports = - [ - self.profile.module - ] - ++ builtins.attrValues self.profiles.darwin; - }; - - flake.profile.module = {...}: { - imports = builtins.attrValues self.profiles.generic; - - options.preferences = { - profile = mkOption { - type = types.str; - description = "The name of the profile to use"; - }; - }; - - options.profile = { - user = { - username = mkOption { - type = types.str; - description = "The username of the user"; - }; - fullname = mkOption { - type = types.str; - description = "The full name of the user"; - }; - email = mkOption { - type = types.str; - description = "The email address of the user"; - }; - }; - - programs = mkOption { - type = types.attrs; - description = "The programs and their configurations to enable with this profile."; - default = {}; - }; - - features = mkOption { - type = types.attrs; - description = "The features and their configurations to enable with this profile."; - default = {}; - }; - }; - }; - }; -} diff --git a/modules/profiles/personal.nix b/modules/profiles/personal.nix deleted file mode 100644 index c0a5ea4..0000000 Binary files a/modules/profiles/personal.nix and /dev/null differ diff --git a/modules/profiles/vmtest.nix b/modules/profiles/vmtest.nix deleted file mode 100644 index b39781f..0000000 --- a/modules/profiles/vmtest.nix +++ /dev/null @@ -1,25 +0,0 @@ -{self, ...}: -with self.lib; { - flake.profiles.generic.vmtest = mkProfile "vmtest" ({...}: { - profile = { - user = { - username = "vmtest"; - fullname = "fullname"; - email = "vmtest@gmail.com"; - }; - }; - }); - - flake.profiles.nixos.vmtest = mkProfile "vmtest" ({ - pkgs, - config, - ... - }: { - environment.variables = { - PROFILE = config.profile.user.username; - }; - environment.systemPackages = with pkgs; [ - hello - ]; - }); -} diff --git a/modules/profiles/work.nix b/modules/profiles/work.nix deleted file mode 100644 index db863bc..0000000 Binary files a/modules/profiles/work.nix and /dev/null differ diff --git a/modules/programs/aerospace.nix b/modules/programs/aerospace.nix index b2d3a07..f3a7a0f 100644 --- a/modules/programs/aerospace.nix +++ b/modules/programs/aerospace.nix @@ -3,49 +3,29 @@ lib, ... }: -with lib; let - name = "aerospace"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); +with lib; { + anvil.programs.aerospace = { + getPackage = self.wrappers.aerospace.wrap; + home = {...}: { + programs.aerospace.enable = true; + xdg.configFile."aerospace/aerospace.toml".text = self.dotfiles.aerospace.default {}; + }; + }; - flake.homeModules.programs = self.lib.mkHomeProgram name ({ - cfg, + flake.wrappers.aerospace = { + wlib, pkgs, ... }: { - config = { - programs.aerospace.enable = true; - xdg.configFile."aerospace/aerospace.toml".text = readFile ./dotfiles/aerospace.toml; - }; - }); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: {}); - - flake.programs.${name} = self.lib.mkProgram name ({pkgs, ...}: { - configurations = []; - config = { - package = pkgs.aerospace; - }; - }); + imports = [ + wlib.modules.default + self.declarations.desktop + ]; + package = pkgs.aerospace; + }; - # flake.wrappers.${name} = { config, ... }: { - # imports = [ - # self.wrapperModules._kitty - # (self.lib.mkConfigurationsOption [ self.definitions.programs.terminal ]) - # ]; - # - # config = { - # configuration = '' - # include ${config.configurations.theme.path} - # confirm_os_window_close 0 - # enable_audio_bell false - # font_family JetBrainsMono Nerd Font - # bold_font auto - # italic_font auto - # bold_italic_font auto - # - # shell ${getExe config.configurations.shell} - # ''; - # }; - # }; + perSystem = {pkgs, ...}: { + wrappers.packages.aerospace = + !(pkgs.stdenv.hostPlatform.isAarch64 && pkgs.stdenv.hostPlatform.isDarwin); + }; } diff --git a/modules/programs/atuin.nix b/modules/programs/atuin.nix new file mode 100644 index 0000000..f9261ef --- /dev/null +++ b/modules/programs/atuin.nix @@ -0,0 +1,10 @@ +{self, ...}: { + anvil.programs.atuin = { + getPackage = {pkgs, ...}: self.wrappers.atuin.wrap {inherit pkgs;}; + }; + + flake.wrappers.atuin = {wlib, ...}: { + imports = [wlib.wrapperModules.atuin]; + config.settings = fromTOML (self.dotfiles.atuin.default {}); + }; +} diff --git a/modules/programs/default.nix b/modules/programs/default.nix deleted file mode 100644 index 2ca48ee..0000000 --- a/modules/programs/default.nix +++ /dev/null @@ -1,120 +0,0 @@ -{ - inputs, - self, - lib, - ... -}: -with lib; { - options = { - flake = inputs.flake-parts.lib.mkSubmoduleOptions { - programs = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - - definitions.programs = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - }; - }; - - config = rec { - flake.lib.mkDarwinProgram = flake.lib.mkNixosProgram; - flake.lib.mkNixosProgram = name: module: ({ - pkgs, - config, - ... - } @ inputs: let - cfg = config.preferences.programs.${name}; - moduleEvaluated = module (inputs // {inherit cfg;}); - in { - imports = - [ - self.programs.${name} - ] - ++ (moduleEvaluated.imports or []); - - options = moduleEvaluated.options or {}; - - config = mkIf cfg.enable ({ - environment.systemPackages = mkIf (cfg.package != null) [cfg.package]; - } - // (moduleEvaluated.config or {})); - }); - - flake.lib.mkHomeProgram = name: module: ({ - pkgs, - config, - ... - } @ inputs: let - cfg = config.preferences.programs.${name}; - moduleEvaluated = module (inputs // {inherit cfg;}); - in { - imports = - [ - self.programs.${name} - ] - ++ (moduleEvaluated.imports or []); - - options = moduleEvaluated.options or {}; - - config = mkIf cfg.enable ({ - home.packages = mkIf (cfg.package != null) [cfg.package]; - } - // (moduleEvaluated.config or {})); - }); - - flake.lib.mkProgram = name: module: ({ - pkgs, - config, - ... - } @ inputs: let - cfg = config.preferences.programs.${name}; - moduleEvaluated = module (inputs // {inherit cfg;}); - in { - imports = moduleEvaluated.imports or []; - - options.preferences.programs.${name} = - { - enable = mkEnableOption "Whether to enable the ${name} program."; - package = mkOption { - type = types.nullOr types.package; - description = "The package of the program, it could be a wrapper."; - default = self.wrappers.${name}.wrap { - inherit pkgs; - configurations = cfg.configurations; - }; - }; - configurations = mkOption { - type = types.submodule { - imports = moduleEvaluated.configurations or []; - _module.args = - inputs - // { - config = cfg.configurations; - }; - }; - description = "The configurations of the program."; - default = {}; - }; - } - // (moduleEvaluated.options or {}); - - config = mkIf cfg.enable { - preferences.programs.${name} = moduleEvaluated.config or {}; - }; - }); - - flake.lib.mkConfigurationsOption = configurations: ({pkgs, ...} @ inputs: { - options = { - configurations = mkOption { - type = types.submodule { - imports = configurations; - _module.args = inputs; - }; - description = "The configurations of the program."; - default = {}; - }; - }; - }); - }; -} diff --git a/modules/programs/desktop.nix b/modules/programs/desktop.nix index 2b1b64b..8cd0824 100644 --- a/modules/programs/desktop.nix +++ b/modules/programs/desktop.nix @@ -1,225 +1,146 @@ { - inputs, self, lib, ... -}: +} @ global: with lib; let - name = "desktop"; - desktop = "niri"; - bar = "noctalia"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: { - config = { - dconf = { - enable = true; - settings."org/gnome/desktop/interface".color-scheme = "prefer-dark"; - }; - services.udiskie = { - enable = true; + defaultConfiguration = { + desktop.name = "niri"; + desktop.desktopShell.name = "noctalia"; + desktop.apps = {pkgs, ...}: rec { + terminal = global.config.anvil.programs.terminal.getPackage { + inherit pkgs; + metadata.terminal.name = global.config.anvil.programs.terminal.metadata.terminal.name; }; + browser = global.config.anvil.programs.zen.getPackage {inherit pkgs;}; + desktopShell = global.config.anvil.programs.noctalia.getPackage {inherit pkgs;}; + appLauncher = pkgs.writeShellScriptBin "app-launcher" "${getExe desktopShell} msg panel-toggle launcher"; }; - }); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({ - pkgs, - cfg, - config, - ... - }: { - config = let - bar-shell = self.wrappers.${bar}.wrap {inherit pkgs;}; - in { - services.gvfs.enable = true; - services.udisks2.enable = true; - preferences.programs.terminal.enable = mkDefault true; - preferences.programs.${bar}.enable = mkDefault true; - services.displayManager.gdm.enable = true; - programs.${desktop} = { - enable = true; - package = self.wrappers.${name}.wrap { + }; +in { + anvil.programs.desktop = { + metadata = defaultConfiguration; + getPackage = { + pkgs, + preferences ? {}, + ... + }: + if pkgs.stdenv.hostPlatform.isLinux + then + self.wrappers.desktop.wrap { inherit pkgs; - configurations = cfg.configurations; + imports = [preferences]; + } + else + self.wrappers.desktop-darwin.wrap { + inherit pkgs; + imports = [preferences]; }; - }; - - environment.systemPackages = with pkgs; - [ - # Applications - spotify - - # Essentials - nautilus # File browser - vlc # Videos - shotwell # Images - mission-center - wdisplays - xdg-desktop-portal-gnome - (pkgs.writeShellScriptBin "clipboard-history" "${getExe bar-shell} msg panel-toggle clipboard") - (pkgs.writeShellScriptBin "nixpkgs-search" '' - query=$(echo "" | ${getExe bar-shell} dmenu -p "Search nixpkgs: ") - [ -n "$query" ] && ${pkgs.xdg-utils}/bin/xdg-open "https://search.nixos.org/packages?query=''${query// /+}" - '') - ddcutil - ] - ++ cfg.configurations.packages; - - systemd.services.lock-before-suspend = { + features = [ + "usb" + ]; + programs = {program, ...}: [ + program.metadata.desktop.name + program.metadata.desktop.desktopShell.name + ]; + home = {pkgs, ...}: { + home.packages = [pkgs.fastfetch]; + xdg.mimeApps = mkIf pkgs.stdenv.hostPlatform.isLinux { enable = true; - description = "Locks the session before sleep"; - wantedBy = ["sleep.target"]; - before = ["sleep.target"]; - serviceConfig = { - Type = "oneshot"; - User = config.profile.user.username; - ExecStart = pkgs.writeShellScript "lock-screen" '' - set -e - ${getExe bar-shell} msg session lock - - for i in $(seq 1 20); do - locked=$(${getExe bar-shell} msg status | ${getExe pkgs.jq} .locked) - if [ "$locked" = "true" ]; then - exit 0 - fi - sleep 0.1 - done - - echo "Timed out waiting for session lock" >&2 - exit 1 - ''; - }; - environment = { - XDG_RUNTIME_DIR = "/run/user/${toString config.users.users.${config.profile.user.username}.uid}"; - WAYLAND_DISPLAY = "wayland-1"; - }; + defaultApplications."inode/directory" = "org.gnome.Nautilus.desktop"; }; }; - }); - - flake.programs.${name} = self.lib.mkProgram name ({...}: { - configurations = [self.definitions.programs.${name}]; - }); - - flake.wrappers.${name} = {...}: { - imports = [ - self.wrapperModules.${desktop} - ]; - }; - - flake.definitions.programs.${name} = {pkgs, ...}: { - options = { - modKey = mkOption { - type = types.str; - description = "The mod key to be used by the window manager."; - default = "super"; - }; - - modKeyAlt = mkOption { - type = types.str; - description = "The alternative mod key to be used by the window manager."; - default = "alt"; + nixos = { + user, + program, + pkgs, + config, + ... + }: let + apps = program.metadata.desktop.apps {inherit pkgs;}; + package = program.getPackage { + inherit pkgs; + preferences = config.anvil.desktop.preferences; }; - - terminal = mkOption { - type = types.package; - description = "The wrapped and configured terminal package."; - }; - - browser = mkOption { - type = types.package; - description = "The wrapped and configured browser package."; - }; - - desktopShell = mkOption { - type = types.package; - description = "The wrapped and configured desktop shell package."; + in { + imports = [ + (self.lib.installPackages user [package]) + ]; + + options = { + anvil.desktop.preferences = mkOption { + type = types.submodule { + _module.args.pkgs = pkgs; + imports = [ + self.declarations.desktop + ]; + }; + }; }; - appLauncher = mkOption { - type = types.package; - description = "The wrapped and configured app launcher package."; - }; + config = { + xdg.portal = { + enable = true; + extraPortals = [pkgs.xdg-desktop-portal-gtk]; + config.common.default = "*"; + }; - packages = mkOption { - type = types.listOf types.package; - description = "An list of packages to install."; - }; + anvil.desktop.preferences.terminal = mkForce apps.terminal; + anvil.desktop.preferences.browser = mkForce apps.browser; + anvil.desktop.preferences.desktopShell = mkForce apps.desktopShell; + anvil.desktop.preferences.appLauncher = mkForce apps.appLauncher; - fontsConfig = mkOption { - type = types.package; - description = "The package with the font configurations. Export FONTCONFIG_FILE=\${fontsConfig} to apply the fonts."; - default = pkgs.makeFontsConf { - fontDirectories = with pkgs; [ - nerd-fonts.jetbrains-mono - ]; + programs.${program.metadata.desktop.name} = { + enable = true; + package = package; }; - }; - monitors = mkOption { - type = types.attrsOf (types.submodule { - options = { - primary = mkOption { - type = types.bool; - default = false; - }; - width = mkOption { - type = types.int; - example = 1920; - }; - height = mkOption { - type = types.int; - example = 1080; - }; - refreshRate = mkOption { - type = types.float; - default = 60; - }; - x = mkOption { - type = types.int; - default = 0; - }; - y = mkOption { - type = types.int; - default = 0; - }; - scale = mkOption { - type = types.float; - default = 1.0; - }; - enabled = mkOption { - type = types.bool; - default = true; - }; - }; - }); - default = {}; + services.gvfs.enable = true; + services.displayManager.gdm.enable = true; + environment.systemPackages = with pkgs; + [ + # Dependencies + pavucontrol + playerctl + brightnessctl + + # Applications + spotify + mission-center + + # Essentials + nautilus # File browser + vlc # Videos + shotwell # Images + wdisplays + xdg-desktop-portal-gnome + (pkgs.writeShellScriptBin "clipboard-history" "${getExe apps.desktopShell} msg panel-toggle clipboard") + (pkgs.writeShellScriptBin "nixpkgs-search" '' + query=$(echo "" | ${getExe apps.desktopShell} dmenu -p "Search nixpkgs: ") + [ -n "$query" ] && ${pkgs.xdg-utils}/bin/xdg-open "https://search.nixos.org/packages?query=''${query// /+}" + '') + ddcutil + ] + ++ (attrValues apps); }; }; + }; - config = let - bar-shell = self.wrappers.${bar}.wrap {inherit pkgs;}; - in rec { - terminal = mkDefault (self.wrappers.terminal.wrap {inherit pkgs;}); - browser = mkDefault inputs.zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default; - desktopShell = mkDefault bar-shell; - appLauncher = mkDefault (pkgs.writeShellScriptBin "app-launcher" "${getExe bar-shell} msg panel-toggle launcher"); - packages = with pkgs; - mkDefault [ - # Wrappers - terminal - browser - desktopShell - appLauncher + flake.wrappers.desktop = {...}: { + imports = [ + self.wrapperModules.niri + ]; + }; - alacritty + flake.wrappers.desktop-darwin = {...}: { + imports = [ + self.wrapperModules.aerospace + ]; + }; - # Dependencies - pavucontrol - playerctl - brightnessctl - ]; - }; + perSystem = {pkgs, ...}: { + wrappers.packages.desktop = pkgs.stdenv.hostPlatform.isDarwin; + wrappers.packages.desktop-darwin = + !(pkgs.stdenv.hostPlatform.isAarch64 && pkgs.stdenv.hostPlatform.isDarwin); }; } diff --git a/modules/programs/dotfiles/aerospace.toml b/modules/programs/dotfiles/aerospace.toml deleted file mode 100644 index 5b92da5..0000000 --- a/modules/programs/dotfiles/aerospace.toml +++ /dev/null @@ -1,150 +0,0 @@ -after-startup-command = [] -start-at-login = true - -# Normalizations. See: https://nikitabobko.github.io/AeroSpace/guide#normalization -enable-normalization-flatten-containers = true -enable-normalization-opposite-orientation-for-nested-containers = true - -# See: https://nikitabobko.github.io/AeroSpace/guide#layouts -# The 'accordion-padding' specifies the size of accordion padding -# You can set 0 to disable the padding feature -accordion-padding = 30 - -# Possible values: tiles|accordion -default-root-container-layout = 'accordion' - -# Possible values: horizontal|vertical|auto -# 'auto' means: wide monitor (anything wider than high) gets horizontal orientation, -# tall monitor (anything higher than wide) gets vertical orientation -default-root-container-orientation = 'auto' - -# Mouse follows focus when focused monitor changes -# Drop it from your config, if you don't like this behavior -# See https://nikitabobko.github.io/AeroSpace/guide#on-focus-changed-callbacks -# See https://nikitabobko.github.io/AeroSpace/commands#move-mouse -# Fallback value (if you omit the key): on-focused-monitor-changed = [] -on-focused-monitor-changed = ['move-mouse monitor-lazy-center'] - -# You can effectively turn off macOS "Hide application" (cmd-h) feature by toggling this flag -# Useful if you don't use this macOS feature, but accidentally hit cmd-h or cmd-alt-h key -# Also see: https://nikitabobko.github.io/AeroSpace/goodies#disable-hide-app -automatically-unhide-macos-hidden-apps = false - -# Possible values: (qwerty|dvorak|colemak) -# See https://nikitabobko.github.io/AeroSpace/guide#key-mapping -[key-mapping] - preset = 'qwerty' - -# [[on-window-detected]] -# if.app-id = 'com.microsoft.teams2' -# run = ['layout floating', 'move-node-to-workspace O'] -# -# [[on-window-detected]] -# if.app-id = 'com.microsoft.Outlook' -# run = ['layout floating', 'move-node-to-workspace O'] - - - -# Gaps between windows (inner-*) and between monitor edges (outer-*). -# Possible values: -# - Constant: gaps.outer.top = 8 -# - Per monitor: gaps.outer.top = [{ monitor.main = 16 }, { monitor."some-pattern" = 32 }, 24] -# In this example, 24 is a default value when there is no match. -# Monitor pattern is the same as for 'workspace-to-monitor-force-assignment'. -# See: -# https://nikitabobko.github.io/AeroSpace/guide#assign-workspaces-to-monitors -[gaps] - inner.horizontal = 5 - inner.vertical = 5 - outer.left = 5 - outer.bottom = 5 - outer.top = 5 - outer.right = 5 - -# 'main' binding mode declaration -# See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes -# 'main' binding mode must be always presented -# Fallback value (if you omit the key): mode.main.binding = {} -[mode.main.binding] - # See: https://nikitabobko.github.io/AeroSpace/commands#focus - alt-h = 'focus left' - alt-j = 'focus down' - alt-k = 'focus up' - alt-l = 'focus right' - - # See: https://nikitabobko.github.io/AeroSpace/commands#move - alt-shift-h = 'move left' - alt-shift-j = 'move down' - alt-shift-k = 'move up' - alt-shift-l = 'move right' - - # See: https://nikitabobko.github.io/AeroSpace/commands#resize - alt-minus = 'resize smart -50' - alt-equal = 'resize smart +50' - - # See: https://nikitabobko.github.io/AeroSpace/commands#workspace - alt-1 = 'workspace 1' - alt-2 = 'workspace 2' - alt-3 = 'workspace 3' - alt-4 = 'workspace 4' - alt-5 = 'workspace 5' - alt-6 = 'workspace 6' - alt-7 = 'workspace 7' - alt-8 = 'workspace 8' - alt-9 = 'workspace 9' - alt-u = 'workspace U' - alt-i = 'workspace I' - alt-o = 'workspace O' - alt-p = 'workspace P' - alt-t = 'workspace T' - - # See: https://nikitabobko.github.io/AeroSpace/commands#move-node-to-workspace - alt-shift-1 = 'move-node-to-workspace 1' - alt-shift-2 = 'move-node-to-workspace 2' - alt-shift-3 = 'move-node-to-workspace 3' - alt-shift-4 = 'move-node-to-workspace 4' - alt-shift-5 = 'move-node-to-workspace 5' - alt-shift-6 = 'move-node-to-workspace 6' - alt-shift-7 = 'move-node-to-workspace 7' - alt-shift-8 = 'move-node-to-workspace 8' - alt-shift-9 = 'move-node-to-workspace 9' - alt-shift-u = 'move-node-to-workspace U' - alt-shift-i = 'move-node-to-workspace I' - alt-shift-o = 'move-node-to-workspace O' - alt-shift-p = 'move-node-to-workspace P' - alt-shift-t = 'move-node-to-workspace T' - - # See: https://nikitabobko.github.io/AeroSpace/commands#workspace-back-and-forth - alt-tab = 'workspace-back-and-forth' - # See: https://nikitabobko.github.io/AeroSpace/commands#move-workspace-to-monitor - alt-period = 'move-workspace-to-monitor --wrap-around prev' - alt-comma = 'move-workspace-to-monitor --wrap-around next' - - # See: https://nikitabobko.github.io/AeroSpace/commands#mode - alt-shift-semicolon = 'mode service' - - alt-x = 'close' - alt-d = ['exec-and-forget open -n /System/Applications/Apps.app/'] - - alt-backspace = 'layout tiles accordion' - - -# 'service' binding mode declaration. -# See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes -[mode.service.binding] - esc = ['reload-config', 'mode main'] - r = ['flatten-workspace-tree', 'mode main'] # reset layout - f = ['layout floating tiling', 'mode main'] # Toggle between floating and tiling layout - backspace = ['close-all-windows-but-current', 'mode main'] - - # sticky is not yet supported https://github.com/nikitabobko/AeroSpace/issues/2 - #s = ['layout sticky tiling', 'mode main'] - - alt-shift-h = ['join-with left', 'mode main'] - alt-shift-j = ['join-with down', 'mode main'] - alt-shift-k = ['join-with up', 'mode main'] - alt-shift-l = ['join-with right', 'mode main'] - - down = 'volume down' - up = 'volume up' - shift-down = ['volume set 0', 'mode main'] diff --git a/modules/programs/editor.nix b/modules/programs/editor.nix new file mode 100644 index 0000000..7bcff29 --- /dev/null +++ b/modules/programs/editor.nix @@ -0,0 +1,53 @@ +{ + self, + config, + lib, + ... +}: let + defaultConfiguration = { + editor = "nvim"; + isTerminalBased = true; + }; + commonModule = { + user, + program, + pkgs, + ... + }: + with program; + with lib; let + package = getPackage {inherit pkgs metadata;}; + in { + imports = [ + (self.lib.installPackages user [package]) + ]; + environment.variables = { + EDITOR = "${getExe' package program.metadata.editor}"; + }; + }; +in { + anvil.programs.editor = { + metadata = defaultConfiguration; + getPackage = { + metadata, + pkgs, + ... + }: + config.anvil.programs.${metadata.editor}.getPackage {inherit pkgs;}; + programs = {program, ...}: [program.metadata.editor]; + nixos = commonModule; + darwin = commonModule; + }; + + flake.wrappers.editor = { + wlib, + pkgs, + ... + }: { + imports = [wlib.modules.default]; + config.package = config.anvil.programs.editor.getPackage { + inherit pkgs; + metadata = defaultConfiguration; + }; + }; +} diff --git a/modules/formatter.nix b/modules/programs/formatter.nix similarity index 100% rename from modules/formatter.nix rename to modules/programs/formatter.nix diff --git a/modules/programs/git.nix b/modules/programs/git.nix new file mode 100644 index 0000000..f318a16 --- /dev/null +++ b/modules/programs/git.nix @@ -0,0 +1,74 @@ +{ + self, + lib, + ... +}: +with lib; let + commonModule = { + user, + program, + config, + pkgs, + ... + }: let + package = program.getPackage {inherit pkgs config;}; + in { + environment.systemPackages = with pkgs; [ + package + lazygit + gh + ]; + + sops.templates."gitconfig-personal" = mkIf (user != null) { + content = '' + [user] + name = ${user.name} + email = ${user.metadata.email} + ''; + owner = user.name; # so your user can actually read the rendered file + }; + }; +in { + anvil.programs.git = { + features = ["sops"]; + getPackage = { + pkgs, + config, + ... + }: + self.wrappers.git.wrap { + inherit pkgs; + settings.include = {path = config.sops.templates."gitconfig-personal".path;}; + }; + + nixos = commonModule; + darwin = commonModule; + }; + + flake.wrappers.git = { + wlib, + pkgs, + ... + }: { + imports = [ + wlib.wrapperModules.git + ]; + + settings = { + init.defaultBranch = "main"; + + core = { + autocrlf = false; + }; + + credential."https://github.com".helper = ["" "!${pkgs.gh}/bin/gh auth git-credential"]; + credential."https://gist.github.com".helper = ["" "!${pkgs.gh}/bin/gh auth git-credential"]; + + pull.rebase = true; + push.autoSetupRemote = true; + + # subsection example -> becomes url."https://github.com/" { insteadOf = "gh:"; } + url."https://github.com/".insteadOf = "gh:"; + }; + }; +} diff --git a/modules/programs/gnome.nix b/modules/programs/gnome.nix new file mode 100644 index 0000000..39376cc --- /dev/null +++ b/modules/programs/gnome.nix @@ -0,0 +1,44 @@ +{ + self, + lib, + ... +}: +with lib; { + anvil.programs.gnome = { + getPackage = {pkgs, ...}: + pkgs.gnome-shell; + + nixos = { + user, + program, + pkgs, + ... + }: let + package = program.getPackage {inherit pkgs;}; + in { + imports = [ + (self.lib.installPackages user [package]) + ]; + services.xserver.enable = true; + services.displayManager.gdm.enable = true; + services.desktopManager.gnome.enable = true; + services.xserver.xkb.layout = "us"; + }; + }; + + flake.wrappers.gnome = { + wlib, + pkgs, + ... + }: { + imports = [ + wlib.modules.default + self.declarations.desktop + ]; + config.package = pkgs.gnome-shell; + }; + + perSystem = {pkgs, ...}: { + wrappers.packages.gnome = pkgs.stdenv.hostPlatform.isDarwin; + }; +} diff --git a/modules/programs/kitty.nix b/modules/programs/kitty.nix new file mode 100644 index 0000000..bcf84c9 --- /dev/null +++ b/modules/programs/kitty.nix @@ -0,0 +1,45 @@ +{ + self, + lib, + ... +}: +with lib; { + anvil.programs.kitty = rec { + getPackage = self.wrappers.kitty.wrap; + nixos = { + user, + program, + pkgs, + ... + }: let + package = program.getPackage {inherit pkgs;}; + in { + imports = [ + (self.lib.installPackages user [package]) + ]; + }; + darwin = nixos; + }; + + flake.wrappers.kitty = { + wlib, + pkgs, + ... + }: { + imports = [ + wlib.wrapperModules.kitty + ]; + + config = { + settings = { + include = "${pkgs.vimPlugins.tokyonight-nvim}/extras/kitty/tokyonight_moon.conf"; + confirm_os_window_close = 0; + enable_audio_bell = false; + font_family = "JetBrainsMono Nerd Font"; + bold_font = "auto"; + italic_font = "auto"; + bold_italic_font = "auto"; + }; + }; + }; +} diff --git a/modules/programs/niri.nix b/modules/programs/niri.nix new file mode 100644 index 0000000..c496dac --- /dev/null +++ b/modules/programs/niri.nix @@ -0,0 +1,51 @@ +{ + self, + lib, + config, + ... +} @ global: +with lib; let +in { + anvil.programs.niri = { + getPackage = self.wrappers.niri.wrap; + nixos = { + user, + program, + pkgs, + ... + }: let + package = program.getPackage {inherit pkgs;}; + in { + }; + }; + + flake.wrappers.niri = { + wlib, + pkgs, + config, + ... + }: { + imports = [ + wlib.wrapperModules.niri + self.declarations.desktop + ]; + + passthru.providedSessions = ["niri"]; + runtimePkgs = with pkgs; [ + xwayland-satellite + jq + ]; + + env.FONTCONFIG_FILE = "${config.fontsConfig}"; + + terminal = mkDefault (self.wrappers.terminal.wrap {inherit pkgs;}); + browser = mkDefault (global.config.anvil.programs.zen.getPackage {inherit pkgs;}); + desktopShell = mkDefault (global.config.anvil.programs.noctalia.getPackage {inherit pkgs;}); + appLauncher = mkDefault (pkgs.writeShellScriptBin "app-launcher" "${getExe config.desktopShell} msg panel-toggle launcher"); + "config.kdl".content = self.dotfiles.niri.default {inherit config;}; + }; + + perSystem = {pkgs, ...}: { + wrappers.packages.niri = pkgs.stdenv.hostPlatform.isDarwin; + }; +} diff --git a/modules/programs/wrappers/noctalia.nix b/modules/programs/noctalia.nix similarity index 56% rename from modules/programs/wrappers/noctalia.nix rename to modules/programs/noctalia.nix index 6a18018..24779b1 100644 --- a/modules/programs/wrappers/noctalia.nix +++ b/modules/programs/noctalia.nix @@ -2,39 +2,29 @@ inputs, self, ... -}: let - name = "noctalia"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: { - config = { - # TODO: Look if this configuration can be applied trough the wrapper using Noctalia v5 - xdg.configFile."noctalia/config.toml".text = self.wrapperHelpers.noctalia.config.default {}; - }; - }); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: { - config = { +}: { + anvil.programs.noctalia = { + getPackage = self.wrappers.noctalia.wrap; + nixos = {...}: { environment.variables = { __NV_PRIME_RENDER_OFFLOAD = 0; __GLX_VENDOR_LIBRARY_NAME = "mesa"; }; }; - }); - - flake.programs.${name} = self.lib.mkProgram name ({...}: {}); + home = {...}: { + # TODO: Look if this configuration can be applied trough the wrapper using Noctalia v5 + xdg.configFile."noctalia/config.toml".text = self.dotfiles.noctalia.default {}; + }; + }; - flake.wrappers.${name} = { + flake.wrappers.noctalia = { wlib, pkgs, ... }: { imports = [ - (self.lib.mkConfigurationsOption []) wlib.wrapperModules.noctalia-shell ]; - config = { package = inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default; runtimePkgs = with pkgs; [ @@ -45,4 +35,8 @@ in { ]; }; }; + + perSystem = {pkgs, ...}: { + wrappers.packages.noctalia = pkgs.stdenv.hostPlatform.isDarwin; + }; } diff --git a/modules/programs/nvim.nix b/modules/programs/nvim.nix new file mode 100644 index 0000000..bded75e --- /dev/null +++ b/modules/programs/nvim.nix @@ -0,0 +1,42 @@ +{ + inputs, + self, + lib, + ... +}: +with lib; { + anvil.programs.nvim = rec { + getPackage = {pkgs, ...}: self.wrappers.nvim.wrap {inherit pkgs;}; + nixos = { + user, + program, + pkgs, + ... + }: let + package = program.getPackage {inherit pkgs;}; + in { + imports = [ + (self.lib.installPackages user [package]) + ]; + }; + darwin = nixos; + }; + + flake.wrappers.nvim = { + wlib, + pkgs, + ... + }: { + imports = [wlib.modules.default]; + config.package = inputs.nvim.packages.${pkgs.stdenv.hostPlatform.system}.default; + }; + + flake.wrappers.nvim-unwrapped = { + wlib, + pkgs, + ... + }: { + imports = [wlib.modules.default]; + config.package = inputs.nvim.packages.${pkgs.stdenv.hostPlatform.system}.default; + }; +} diff --git a/modules/programs/oh-my-posh.nix b/modules/programs/oh-my-posh.nix new file mode 100644 index 0000000..e202f69 --- /dev/null +++ b/modules/programs/oh-my-posh.nix @@ -0,0 +1,61 @@ +{ + self, + lib, + ... +}: +with lib; { + anvil.programs.oh-my-posh = rec { + getPackage = { + pkgs, + tty ? false, + ... + }: + if tty + then self.wrappers.oh-my-posh-tty.wrap {inherit pkgs;} + else self.wrappers.oh-my-posh.wrap {inherit pkgs;}; + nixos = { + user, + program, + pkgs, + ... + }: let + package = program.getPackage {inherit pkgs;}; + in { + imports = [ + (self.lib.installPackages user [package]) + ]; + }; + darwin = nixos; + }; + + flake.wrappers.oh-my-posh = { + wlib, + pkgs, + config, + ... + }: { + imports = [ + wlib.wrapperModules.oh-my-posh + self.modules.generic.colors + ]; + config = let + colors = config.preferences.theme.colors; + in { + runtimePkgs = with pkgs; [ + nerd-fonts.jetbrains-mono + ]; + configFile = mkDefault (pkgs.writeText "config.json" (self.dotfiles.oh-my-posh.default {inherit colors;})); + }; + }; + + flake.wrappers.oh-my-posh-tty = { + pkgs, + config, + ... + }: let + colors = config.preferences.theme.colors; + in { + imports = [self.wrapperModules.oh-my-posh]; + configFile = pkgs.writeText "config.json" (self.dotfiles.oh-my-posh.tty {inherit colors;}); + }; +} diff --git a/modules/programs/shell.nix b/modules/programs/shell.nix index d1821a8..bb1bb2c 100644 --- a/modules/programs/shell.nix +++ b/modules/programs/shell.nix @@ -1,214 +1,98 @@ { - inputs, self, + config, lib, ... -}: +} @ global: with lib; let - name = "shell"; - shell = "zsh"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({ - config, - cfg, - ... - }: let - shellPackage = cfg.package; - in { - config = { - programs.${shell}.enable = true; - environment.pathsToLink = ["/share/${shell}"]; - - # users.defaultUserShell = shellPackage; - users.users.${config.profile.user.username}.shell = shellPackage; - - environment.variables = rec { - GIT_AUTHOR_NAME = config.profile.user.username; - GIT_AUTHOR_EMAIL = config.profile.user.email; - GIT_COMMITER_NAME = GIT_AUTHOR_NAME; - GIT_COMMITER_EMAIL = GIT_AUTHOR_EMAIL; - NH_FLAKE = "/Users/${config.profile.user.username}/nix"; - }; - - environment.shellAliases = let - homePath = "/Users/${config.profile.user.username}/nix"; - in { - # ntest = "nh os test ${homePath} -H ${config.information.hostname}"; - nswitch = "nh darwin switch ${homePath} -H ${config.information.hostname}"; - # nbuild-vm = "nh os build-vm ${homePath} -H ${config.information.hostname}"; - nclean = "nh clean all --optimise -k ${toString config.preferences.boot.configurationLimit}"; - }; - }; - }); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: {}); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({ - config, - cfg, - pkgs, - ... - }: let - shellPackage = cfg.package; - in { - config = { - programs.${shell}.enable = true; - environment.pathsToLink = ["/share/${shell}"]; - - users.defaultUserShell = shellPackage; - users.users.${config.profile.user.username}.shell = shellPackage; - environment.shells = [shellPackage]; - - environment.systemPackages = with pkgs; - [ - wl-clipboard - ] - ++ cfg.configurations.packages; - - environment.variables = rec { - GIT_AUTHOR_NAME = config.profile.user.username; - GIT_AUTHOR_EMAIL = config.profile.user.email; - GIT_COMMITER_NAME = GIT_AUTHOR_NAME; - GIT_COMMITER_EMAIL = GIT_AUTHOR_EMAIL; - NH_FLAKE = "/home/${config.profile.user.username}/nix"; - CD_FZF_EXTRA_PATHS = "~/personal/development:3 ~/personal/repos:2"; - }; - - environment.shellAliases = let - homePath = "/home/${config.profile.user.username}/nix"; - in { - ntest = "nh os test ${homePath} -H ${config.information.hostname}"; - nswitch = "nh os switch ${homePath} -H ${config.information.hostname}"; - nbuild-vm = "nh os build-vm ${homePath} -H ${config.information.hostname}"; - nclean = "nh clean all --optimise -k ${toString config.preferences.boot.configurationLimit}"; - }; - }; - }); - - flake.programs.${name} = self.lib.mkProgram name ({ - pkgs, - cfg, - ... - }: { - configurations = [self.definitions.programs.${name}]; - config = { - package = self.wrappers.${name}.wrap { - inherit pkgs; - configurations = - { - multiplexer = let - shellPath = getExe cfg.package; - in - mkDefault (self.wrappers.tmux.wrap { - inherit pkgs; - shell = shellPath; - }); - packages = [multiplexer]; - } - // cfg.configurations; - }; - }; - }); - - flake.wrappers.${name} = { + defaultConfiguration = { + shell.name = "zsh"; + shell.multiplexer.name = "tmux"; + shell.prompt.name = "oh-my-posh"; + shell.editor.name = global.config.anvil.programs.editor.metadata.editor; + shell.extraActivationScripts = []; + }; + commonModule = { + host, + program, + user, pkgs, config, ... - }: { + } @ args: { imports = [ - self.wrapperModules.${shell} + (self.lib.forUser user { + ${user.name} = { + shell = with program; getPackage args; + }; + }) ]; - - config.configurations = let - shellPath = getExe config.package; - in rec { - envVariables = { - SHELL = "${shellPath}"; - }; - multiplexer = mkDefault (self.wrappers.tmux.wrap { - inherit pkgs; - shell = shellPath; - }); - packages = [multiplexer]; - }; + fonts.packages = [pkgs.nerd-fonts.jetbrains-mono]; }; - - flake.definitions.programs.${name} = {pkgs, ...}: { - options = { - shellAliases = mkOption { - type = types.attrsOf (types.nullOr types.str); - description = "An attrSet with shell aliases."; - default = { - cat = "bat"; - lg = "lazygit"; - eza = "eza --icons auto --git --group-directories-last"; - ls = "eza"; - find = "fd"; - cd = ". cdfzf"; - nshell = "NIXPKGS_ALLOW_UNFREE=1 nix-shell --command zsh -p"; - }; - }; - - envVariables = mkOption { - type = types.attrsOf (types.nullOr types.str); - description = "An attrSet with environment variables."; - default = { - EDITOR = "nvim"; - # SHELL = "${getExe shell}"; - TERM = "tmux-256color"; +in { + anvil.programs.shell = { + metadata = defaultConfiguration; + getPackage = { + host, + pkgs, + program, + config, + ... + }: + with program.metadata; + global.config.anvil.programs.${shell.name}.getPackage rec { + imports = [ + (self.dotfiles.shell.getConfiguration {inherit defaultConfiguration;}) + ]; + + inherit pkgs; + prompt.name = shell.prompt.name; + prompt.getPackage = mkForce global.config.anvil.programs.${prompt.name}.getPackage; + + multiplexer.name = shell.multiplexer.name; + multiplexer.getPackage = mkForce global.config.anvil.programs.${multiplexer.name}.getPackage; + + metadata = mkForce { + wrappers = { + atuin = global.config.anvil.programs.atuin.getPackage {inherit pkgs;}; + editor = global.config.anvil.programs.editor.getPackage { + inherit pkgs; + metadata.editor = shell.editor.name; + }; + git = global.config.anvil.programs.git.getPackage {inherit pkgs config;}; + }; + }; + activationScripts = shell.extraActivationScripts; + + envVariables = { + NH_FLAKE = host.metadata.nixPath; + }; + + shellAliases = let + nixFlakePath = host.metadata.nixPath; + in { + ntest = "nh os test ${nixFlakePath} -H ${host.name}"; + nboot = "nh os boot ${nixFlakePath} -H ${host.name}"; + nswitch = "nh os switch ${nixFlakePath} -H ${host.name}"; + nbuild-vm = "nh os build-vm ${nixFlakePath} -H ${host.name}"; + nclean = "nh clean all --optimise -k ${toString host.metadata.configurationLimit}"; + nshell = "nix-shell --command ${program.metadata.shell.name} -p"; + }; }; - }; - - packages = mkOption { - type = types.listOf types.package; - description = "An list of packages to install."; - }; - - shellPrompt = mkOption { - type = types.package; - description = "The shell prompt package."; - default = self.wrappers.oh-my-posh.wrap {inherit pkgs;}; - }; - - multiplexer = mkOption { - type = types.package; - description = "The wrapped and configured terminal multiplexer."; - }; - }; - - config = { - packages = with pkgs; [ - # Dependencies - bat - chafa - eza - fd - file - fzf - gcc - gh - git - git-crypt - imgcat - jq - lazygit - nh - ripgrep - sesh - television - zoxide - unixtools.watch - - # Wrapped - inputs.nvim.packages.${pkgs.stdenv.hostPlatform.system}.neovim + programs = {program, ...}: [ + "git" + program.metadata.shell.multiplexer.name + program.metadata.shell.prompt.name + ]; + nixos = commonModule; + darwin = commonModule; + }; - # Scripts - (writeShellScriptBin "hydrate-paths" (readFile ./scripts/hydrate-paths.sh)) - (writeShellScriptBin "custom-fzf-preview" (readFile ./scripts/custom-fzf-preview.sh)) - (writeShellScriptBin "cdfzf" (readFile ./scripts/cdfzf.sh)) - (writeShellScriptBin "toggle-tmux-popup" (readFile ./scripts/toogle-tmux-popup.sh)) - (writeShellScriptBin "sessions" (readFile ./scripts/sessions.sh)) + flake.wrappers.shell = {...}: + with defaultConfiguration; { + imports = [ + self.wrapperModules.${shell.name} + (self.dotfiles.shell.getConfiguration {inherit defaultConfiguration;}) ]; }; - }; } diff --git a/modules/programs/steam.nix b/modules/programs/steam.nix index c0681ca..81ccea0 100644 --- a/modules/programs/steam.nix +++ b/modules/programs/steam.nix @@ -1,15 +1,18 @@ -{ - self, - lib, - ... -}: -with lib; let - name = "steam"; -in { - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: {}); +{inputs, ...}: { + anvil.programs.steam = { + nixos = {pkgs, ...}: { + nixpkgs.overlays = [ + (final: prev: { + xwayland-satellite = prev.xwayland-satellite.overrideAttrs (old: { + version = "0.8.1"; + src = inputs.xwayland-satellite-stable; + cargoDeps = final.rustPlatform.importCargoLock { + lockFile = "${inputs.xwayland-satellite-stable}/Cargo.lock"; + }; + }); + }) + ]; - flake.nixosModules.programs = self.lib.mkNixosProgram name ({pkgs, ...}: { - config = { environment.sessionVariables = { STEAM_EXTRA_COMPAT_TOOLS_PATHS = "$HOME/.steam/root/compatibilitytools.d"; }; @@ -38,12 +41,5 @@ in { }; }; }; - }); - - flake.programs.${name} = self.lib.mkProgram name ({...}: { - configurations = [self.definitions.programs.terminal]; - config = { - package = null; - }; - }); + }; } diff --git a/modules/programs/terminal.nix b/modules/programs/terminal.nix index ef5260e..0afdb25 100644 --- a/modules/programs/terminal.nix +++ b/modules/programs/terminal.nix @@ -1,62 +1,32 @@ { self, + config, lib, ... }: with lib; let - name = "terminal"; - terminal = "kitty"; + defaultConfiguration = { + terminal.name = "kitty"; + }; in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: { - config = { - preferences.programs.shell.enable = mkDefault true; - }; - }); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: {}); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: { - config = { - preferences.programs.shell.enable = mkDefault true; - }; - }); - - flake.programs.${name} = self.lib.mkProgram name ({ - pkgs, - cfg, - ... - }: { - configurations = [self.definitions.programs.${name}]; - }); - - flake.wrappers.${name} = {...}: { - imports = [self.wrapperModules.${terminal}]; + anvil.programs.terminal = { + metadata = defaultConfiguration; + programs = {program, ...}: [ + program.metadata.terminal.name + "shell" + ]; + getPackage = { + pkgs, + metadata, + ... + }: + config.anvil.programs.${metadata.terminal.name}.getPackage {inherit pkgs;}; }; - flake.definitions.programs.${name} = {pkgs, ...}: { - options = { - shell = mkOption { - type = types.package; - description = "The wrapped and configured shell package."; - default = self.wrappers.shell.wrap {inherit pkgs;}; - }; - - theme = let - themePackage = pkgs.vimPlugins.tokyonight-nvim; - in { - package = mkOption { - type = types.package; - description = "The package of the theme, if any."; - default = themePackage; - }; - - path = mkOption { - type = types.str; - description = "A path to the theme file, if any."; - default = "${themePackage}/extras/kitty/tokyonight_moon.conf"; - # default = "${package}/extras/ghostty/tokyonight_moon"; - }; - }; + flake.wrappers.terminal = {...}: + with defaultConfiguration; { + imports = [ + self.wrapperModules.${terminal.name} + ]; }; - }; } diff --git a/modules/programs/tmux.nix b/modules/programs/tmux.nix new file mode 100644 index 0000000..6b8816a --- /dev/null +++ b/modules/programs/tmux.nix @@ -0,0 +1,44 @@ +{ + self, + lib, + ... +}: +with lib; { + anvil.programs.tmux = rec { + getPackage = self.wrappers.tmux.wrap; + nixos = { + user, + program, + pkgs, + ... + }: let + package = program.getPackage {inherit pkgs;}; + scriptsPkgs = [ + package + (pkgs.writeShellScriptBin "sessions" (self.dotfiles.tmux.scripts.sessions {})) + (pkgs.writeShellScriptBin "toggle-tmux-popup" (self.dotfiles.tmux.scripts.toggle-tmux-popup {})) + ]; + in { + imports = [ + (self.lib.installPackages user scriptsPkgs) + ]; + }; + darwin = nixos; + }; + flake.wrappers.tmux = { + wlib, + pkgs, + config, + ... + }: { + imports = [ + wlib.wrapperModules.tmux + self.modules.generic.colors + ]; + + config = let + colors = config.preferences.theme.colors; + in + self.dotfiles.tmux.default {inherit pkgs colors;}; + }; +} diff --git a/modules/programs/wrappers/ghostty.nix b/modules/programs/wrappers/ghostty.nix deleted file mode 100644 index d61a8cc..0000000 --- a/modules/programs/wrappers/ghostty.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ - self, - lib, - ... -}: -with lib; let - name = "ghostty"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: {}); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: {}); - - flake.programs.${name} = self.lib.mkProgram name ({...}: { - configurations = [self.definitions.terminal]; - }); - - flake.wrappers.${name} = {config, ...}: { - imports = [ - self.wrapperModules._ghostty - (self.lib.mkConfigurationsOption [self.definitions.programs.terminal]) - ]; - - config = { - configuration = '' - theme=${config.configurations.theme.path} - command=${getExe config.configurations.shell} - ''; - }; - }; -} diff --git a/modules/programs/wrappers/helpers/helpers.nix b/modules/programs/wrappers/helpers/helpers.nix deleted file mode 100644 index c53e7a8..0000000 --- a/modules/programs/wrappers/helpers/helpers.nix +++ /dev/null @@ -1,90 +0,0 @@ -{ - inputs, - self, - lib, - ... -}: -with lib; let - hexColor = - lib.types.strMatching "^#[0-9a-fA-F]{6}$" - // { - description = "6-digit hex color (including '#')"; - }; - - base16Slots = [ - "base00" - "base01" - "base02" - "base03" - "base04" - "base05" - "base06" - "base07" - "base08" - "base09" - "base0A" - "base0B" - "base0C" - "base0D" - "base0E" - "base0F" - ]; -in { - options = { - flake = inputs.flake-parts.lib.mkSubmoduleOptions { - wrapperHelpers = inputs.nixpkgs.lib.mkOption { - default = {}; - }; - }; - }; - - config = { - # flake.wrapperHelpers.options.configurations = module: ({ pkgs, config, ...}@inputs: - # let - # moduleEvaluated = module (inputs // { config = config.configurations; }); - # in { - # options.configurations = moduleEvaluated.options; - # config.configurations = moduleEvaluated.config; - # }); - - flake.wrapperHelpers.options.configurations = module: ({ - pkgs, - config, - ... - } @ inputs: { - options.configurations = mkOption { - type = types.submodule { - imports = [module]; - _module.args = inputs // {config = config.configurations;}; - }; - description = "The configurations of the program."; - default = {}; - }; - }); - - flake.wrapperHelpers.modules.theme = {pkgs, ...}: { - options = { - colors = mkOption { - type = lib.types.submodule { - options = lib.genAttrs base16Slots ( - slot: - lib.mkOption { - type = hexColor; - example = "1a1b26"; - description = "Base16 slot ${slot}."; - } - ); - }; - description = "A complete Base16 color scheme (base00–base0F as 6-digit hex strings with '#')."; - default = self.wrapperHelpers.theme.colors {inherit pkgs;}; - }; - }; - }; - - flake.wrapperHelpers.theme.colors = {pkgs, ...}: let - yamlToAttrs = file: builtins.fromJSON (builtins.readFile (pkgs.runCommand "yaml-to-json" {buildInputs = [pkgs.yq-go];} ''yq -o=json '.' ${file} > $out'')); - theme = yamlToAttrs "${pkgs.base16-schemes}/share/themes/tokyo-night-moon.yaml"; - in - theme.palette; - }; -} diff --git a/modules/programs/wrappers/helpers/noctalia.nix b/modules/programs/wrappers/helpers/noctalia.nix deleted file mode 100644 index 4db8153..0000000 --- a/modules/programs/wrappers/helpers/noctalia.nix +++ /dev/null @@ -1,579 +0,0 @@ -{self, ...}: { - flake.wrapperHelpers.noctalia = { - config.default = {...}: - let - wallpapersPath = "${self.lib.resourcesPath}/wallpapers"; - imagessPath = "${self.lib.resourcesPath}/images"; - in - '' -[audio] -enable_sounds = true - -[backdrop] -blur_intensity = 0.4999999888241291 -enabled = true -tint_intensity = 0.0 - -[bar] -order = [ "default" ] - - [bar.default] - background_opacity = 0.0 - capsule = true - capsule_opacity = 0.75 - capsule_padding = 10.0 - capsule_radius = "auto" - capsule_thickness = 0.89999998360872269 - center = [ "privacy", "media", "recorder_2" ] - end = [ "group:g3", "group:g2", "group:g1", "group:g4" ] - margin_edge = 5 - margin_ends = 10 - shadow = false - start = [ "control-center", "workspaces" ] - thickness = 25 - - [[bar.default.capsule_group]] - fill = "surface_variant" - id = "g3" - members = [ "network", "bluetooth" ] - opacity = 0.75 - padding = 10.0 - - [[bar.default.capsule_group]] - fill = "surface_variant" - id = "g2" - members = [ "volume", "brightness", "battery" ] - opacity = 0.75 - padding = 10.0 - - [[bar.default.capsule_group]] - fill = "surface_variant" - id = "g4" - members = [ "notifications", "session" ] - opacity = 0.75 - padding = 10.0 - - [[bar.default.capsule_group]] - fill = "surface_variant" - id = "g1" - members = [ "clock", "date" ] - opacity = 0.75 - padding = 10.0 - -[battery] -warning_threshold = 15 - - [battery.device."/org/freedesktop/UPower/devices/headset_dev_80_99_E7_F0_E1_15"] - warning_threshold = 30 - -[brightness] -enable_ddcutil = true -sync_all_monitors = true - -[calendar] -enabled = true - - [calendar.account.personal_google] - color = "primary" - name = "Personal Calendar" - type = "google" - -[control_center] -hidden_tabs = [] - - [[control_center.shortcuts]] - type = "caffeine" - - [[control_center.shortcuts]] - type = "nightlight" - - [[control_center.shortcuts]] - type = "notification" - - [[control_center.shortcuts]] - type = "power_profile" - - [[control_center.shortcuts]] - type = "clipboard" - - [[control_center.shortcuts]] - type = "noctalia/screen_recorder:toggle" - -[dock] -active_monitor_only = true -active_scale = 1.1000000163912773 -auto_hide = true -background_opacity = 0.99999997764825821 -enabled = false -icon_size = 30 -launcher_icon = "layout-dashboard-filled" -launcher_position = "start" -magnification_scale = 1.3000000044703484 -main_axis_padding = 10 -reserve_space = false -shadow = false - -[idle] -behavior_order = [ "lock", "screen-off", "lock-and-suspend" ] -pre_action_fade_seconds = 10 - - [idle.behavior.lock] - action = "lock" - enabled = true - timeout = 610.0 - - [idle.behavior.lock-and-suspend] - action = "lock_and_suspend" - enabled = true - timeout = 900.0 - - [idle.behavior.screen-off] - action = "screen_off" - enabled = true - timeout = 600.0 - -[location] -auto_locate = true - -[lockscreen] -blur_intensity = 0.64999998547136784 -blurred_desktop = true -tint_intensity = 0.19999999552965164 - -[lockscreen_widgets] -enabled = true -schema_version = 2 -widget_order = [ - "lockscreen-login-box@eDP-1", - "lockscreen-login-box@HDMI-A-2", - "lockscreen-login-box@DP-3", - "lockscreen-login-box@HDMI-A-1", - "lockscreen-login-box@DP-1", - "lockscreen-login-box@winit", - "lockscreen-login-box@eDP-1", - "lockscreen-widget-0000000000000006", - "lockscreen-widget-0000000000000003", - "lockscreen-widget-0000000000000007", - "lockscreen-widget-0000000000000008" -] - - [lockscreen_widgets.grid] - cell_size = 16 - major_interval = 4 - visible = true - - [lockscreen_widgets.widget."lockscreen-login-box@DP-1"] - box_height = 70.0 - box_width = 400.0 - cx = 960.0 - cy = 961.0 - output = "DP-1" - rotation = 0.0 - type = "login_box" - - [lockscreen_widgets.widget."lockscreen-login-box@DP-1".settings] - background_color = "surface_variant" - background_opacity = 0.88 - background_radius = 12.0 - input_opacity = 1.0 - input_radius = 6.0 - show_caps_lock = true - show_keyboard_layout = true - show_login_button = true - show_password_hint = true - - [lockscreen_widgets.widget."lockscreen-login-box@DP-2"] - box_height = 70.0 - box_width = 400.0 - cx = 1280.0 - cy = 1321.0 - output = "DP-2" - rotation = 0.0 - type = "login_box" - - [lockscreen_widgets.widget."lockscreen-login-box@DP-2".settings] - background_color = "surface_variant" - background_opacity = 0.88 - background_radius = 12.0 - input_opacity = 1.0 - input_radius = 6.0 - show_caps_lock = true - show_keyboard_layout = true - show_login_button = true - show_password_hint = true - - [lockscreen_widgets.widget."lockscreen-login-box@DP-3"] - box_height = 70.0 - box_width = 400.0 - cx = 960.0 - cy = 961.0 - output = "DP-3" - rotation = 0.0 - type = "login_box" - - [lockscreen_widgets.widget."lockscreen-login-box@DP-3".settings] - background_color = "surface_variant" - background_opacity = 0.88 - background_radius = 12.0 - input_opacity = 1.0 - input_radius = 6.0 - show_caps_lock = true - show_keyboard_layout = true - show_login_button = true - show_password_hint = true - - [lockscreen_widgets.widget."lockscreen-login-box@HDMI-A-1"] - box_height = 70.0 - box_width = 400.0 - cx = 1280.0 - cy = 1321.0 - output = "HDMI-A-1" - rotation = 0.0 - type = "login_box" - - [lockscreen_widgets.widget."lockscreen-login-box@HDMI-A-1".settings] - background_color = "surface_variant" - background_opacity = 0.88 - background_radius = 12.0 - input_opacity = 1.0 - input_radius = 6.0 - show_caps_lock = true - show_keyboard_layout = true - show_login_button = true - show_password_hint = true - - [lockscreen_widgets.widget."lockscreen-login-box@HDMI-A-2"] - box_height = 70.0 - box_width = 400.0 - cx = 1280.0 - cy = 1321.0 - output = "HDMI-A-2" - rotation = 0.0 - type = "login_box" - - [lockscreen_widgets.widget."lockscreen-login-box@HDMI-A-2".settings] - background_color = "surface_variant" - background_opacity = 0.88 - background_radius = 12.0 - input_opacity = 1.0 - input_radius = 6.0 - show_caps_lock = true - show_keyboard_layout = true - show_login_button = true - show_password_hint = true - - [lockscreen_widgets.widget."lockscreen-login-box@eDP-1"] - box_height = 70.0 - box_width = 400.0 - cx = 960.0 - cy = 961.0 - output = "eDP-1" - rotation = 0.0 - type = "login_box" - - [lockscreen_widgets.widget."lockscreen-login-box@eDP-1".settings] - background_color = "surface_variant" - background_opacity = 0.88 - background_radius = 12.0 - input_opacity = 1.0 - input_radius = 6.0 - show_caps_lock = true - show_keyboard_layout = true - show_login_button = true - show_password_hint = true - - [lockscreen_widgets.widget."lockscreen-login-box@winit"] - box_height = 70.0 - box_width = 400.0 - cx = 466.0 - cy = 913.0 - output = "winit" - rotation = 0.0 - type = "login_box" - - [lockscreen_widgets.widget."lockscreen-login-box@winit".settings] - background_color = "surface_variant" - background_opacity = 0.88 - background_radius = 12.0 - input_opacity = 1.0 - input_radius = 6.0 - show_caps_lock = true - show_keyboard_layout = true - show_login_button = true - show_password_hint = true - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000001] - box_height = 0.0 - box_width = 0.0 - cx = 960.0 - cy = 156.0 - output = "DP-3" - rotation = 0.0 - type = "clock" - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000001.settings] - background = false - center_text = true - shadow = false - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000002] - box_height = 0.0 - box_width = 0.0 - cx = 960.0 - cy = 802.0 - output = "DP-3" - rotation = 0.0 - type = "media_player" - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000002.settings] - background = false - hide_when_no_media = true - shadow = false - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000003] - box_height = 128.0 - box_width = 416.0 - cx = 960.0 - cy = 796.0 - output = "eDP-1" - rotation = 0.0 - type = "media_player" - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000003.settings] - background = false - background_opacity = 0.78000000000000003 - color = "on_surface" - hide_when_no_media = true - layout = "horizontal" - shadow = false - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000004] - box_height = 0.0 - box_width = 0.0 - cx = 640.0 - cy = 538.0 - output = "eDP-1" - rotation = 0.0 - type = "media_player" - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000004.settings] - background = false - hide_when_no_media = true - shadow = false - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000006] - box_height = 0.0 - box_width = 0.0 - cx = 960.0 - cy = 188.0 - output = "eDP-1" - rotation = 0.0 - type = "clock" - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000006.settings] - background = false - center_text = true - clock_style = "digital" - shadow = false - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000007] - box_height = 0.0 - box_width = 0.0 - cx = 960.0 - cy = 172.5 - output = "DP-1" - rotation = 0.0 - type = "clock" - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000007.settings] - background = false - shadow = false - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000008] - box_height = 0.0 - box_width = 0.0 - cx = 960.0 - cy = 812.0 - output = "DP-1" - rotation = 0.0 - type = "media_player" - - [lockscreen_widgets.widget.lockscreen-widget-0000000000000008.settings] - background = false - hide_when_no_media = true - shadow = false - -[nightlight] -enabled = true -temperature_night = 3800 - -[osd] -background_opacity = 0.74999998323619366 -position = "top_right" -position_vertical = "top_right" - -[plugin_settings."noctalia/screen_recorder"] -color_range = "full" -hide_inactive = true -quality = "ultra" -replay_enabled = true -resolution = "original" - -[plugin_settings."yocraft/web-launcher"] -icon_provider = "direct" -links = [ - "GitHub|https://github.com", - "GitLab|https://gitlab.com", - "Codeberg|https://codeberg.org", - "Reddit|https://reddit.com", - "YouTube|https://youtube.com", - "Gmail|https://mail.google.com", - "Whatsapp|https://web.whatsapp.com", - "Teams|https://teams.live.com/v2" -] -notify = false - -[plugins] -enabled = [ "noctalia/screen_recorder", "yocraft/web-launcher", "apex077/eyecare" ] - -[shell] -avatar_path = "${imagessPath}/avatar.jpg" -font_family = "JetBrainsMono Nerd Font Mono" -launch_apps_as_systemd_services = true -niri_overview_type_to_launch_enabled = true -polkit_agent = true -screen_time_enabled = true -settings_show_advanced = true -show_location = false -telemetry_enabled = true - - [shell.launcher] - app_grid = true - compact = true - session_search = true - - [shell.launcher.dmenu.entry.nixpkgs] - command = "echo Nixpkgs" - exec = "nixpkgs-search" - global = false - glyph = "package" - prefix = "nix" - - [shell.panel] - control_center_placement = "floating" - list_item_background = true - open_near_click_control_center = true - open_near_click_session = true - session_placement = "floating" - session_position = "auto" - wallpaper_placement = "floating" - - [shell.screen_corners] - enabled = true - size = 25 - - [[shell.session.actions]] - action = "lock" - countdown_seconds = 0.0 - enabled = true - shortcut = "1" - variant = "default" - - [[shell.session.actions]] - action = "logout" - countdown_seconds = 0.0 - enabled = true - shortcut = "2" - variant = "default" - - [[shell.session.actions]] - action = "lock_and_suspend" - countdown_seconds = 0.0 - enabled = true - glyph = "zzz" - label = "Suspend" - shortcut = "3" - variant = "default" - - [[shell.session.actions]] - action = "reboot" - countdown_seconds = 0.0 - enabled = true - shortcut = "4" - variant = "default" - - [[shell.session.actions]] - action = "shutdown" - countdown_seconds = 0.0 - enabled = true - shortcut = "5" - variant = "destructive" - -[theme] -builtin = "Tokyo-Night" -community_palette = "Tokyo Night Storm" -mode = "dark" -pure_black_dark = true -source = "builtin" -wallpaper_scheme = "m3-tonal-spot" - - [theme.templates] - builtin_ids = [ "btop" ] - community_ids = [ "zen-browser" ] - -[wallpaper] -directory = "${wallpapersPath}" -transition_on_startup = true - - [wallpaper.automation] - enabled = true - interval_seconds = 900 - - [wallpaper.default] - path = "${wallpapersPath}/wallhaven.jpg" - - [wallpaper.last] - path = "${wallpapersPath}/wallhaven.jpg" - - [wallpaper.monitors.DP-1] - path = "${wallpapersPath}/wallhaven.jpg" - - [wallpaper.monitors.HDMI-A-1] - path = "${wallpapersPath}/wallhaven.jpg" - - [wallpaper.monitors.HDMI-A-2] - path = "${wallpapersPath}/wallhaven.jpg" - - [wallpaper.monitors.eDP-1] - path = "${wallpapersPath}/wallhaven.jpg" - -[widget.control-center] -anchor = true -capsule = true -glyph = "brand-dribbble-filled" - -[widget.media] -hide_when_no_media = true -title_scroll = "always" - -[widget.network] -show_label = false - -[widget.privacy] -active_color = "error" -hide_inactive = true - -[widget.recorder] -type = "noctalia/screen_recorder:recorder" - -[widget.recorder_2] -type = "noctalia/screen_recorder:recorder" - -[widget.workspaces] -anchor = true -display = "none" -hide_when_empty = true -pill_scale = 0.75 - ''; - }; -} diff --git a/modules/programs/wrappers/helpers/oh-my-posh.nix b/modules/programs/wrappers/helpers/oh-my-posh.nix deleted file mode 100644 index afd0a6d..0000000 --- a/modules/programs/wrappers/helpers/oh-my-posh.nix +++ /dev/null @@ -1,336 +0,0 @@ -{...}: { - flake.wrapperHelpers.oh-my-posh = { - prompts.default = {colors, ...}: '' - { - "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json", - "final_space": true, - "console_title_template": "{{ .Shell }} in {{ .Folder }}", - "version": 4, - "blocks": [ - { - "type": "prompt", - "alignment": "left", - "overflow": "hide", - "segments": [ - { - "type": "path", - "style": "plain", - "background": "transparent", - "foreground": "${colors.base0D}", - "template": " {{ .Path }} ", - "options": { - "style": "folder" - } - }, - { - "type": "git", - "style": "plain", - "foreground": "${colors.base07}", - "background": "transparent", - "github_icon": " ", - "gitlab_icon": " ", - "bitbucket_icon": " ", - "template": "{{ .UpstreamIcon }} {{ if or (.Working.Changed) (.Staging.Changed) }} {{ end }}{{ .HEAD }}{{ if gt .Behind 0 }}⇣{{ end }}{{ if gt .Ahead 0 }}⇡{{ end }}", - "properties": { - "branch_icon": "", - "fetch_status": true, - "fetch_upstream_icon": true, - "mapped_branches": { - "feature/*": "feat/" - } - } - } - ] - }, - { - "type": "prompt", - "alignment": "right", - "overflow": "hide", - "segments": [ - { - "type": "executiontime", - "style": "plain", - "foreground_templates": [ - "{{if gt .Code 0}}${colors.base08}{{else}}${colors.base0B}{{end}}" - ], - "template": " {{ .FormattedMs }}", - "options": { - "threshold": 1000, - "style": "austin" - } - } - ] - }, - { - "type": "prompt", - "alignment": "left", - "newline": true, - "segments": [ - { - "type": "os", - "style": "plain", - "foreground_templates": [ - "{{if gt .Code 0}}${colors.base08}{{end}}", - "{{if le .Code 0}}${colors.base0C}{{end}}" - ], - "background": "transparent", - "template": "{{ if .WSL }}WSL at {{ end }}{{.Icon}} " - }, - { - "type": "text", - "style": "plain", - "foreground_templates": [ - "{{if gt .Code 0}}${colors.base08}{{end}}", - "{{if eq .Code 0}}${colors.base0D}{{end}}" - ], - "background": "transparent", - "template": "" - } - ] - } - ], - "transient_prompt": { - "foreground": "${colors.base0D}", - "background": "transparent", - "template": " " - }, - "secondary_prompt": { - "foreground": "${colors.base0D}", - "background": "transparent", - "template": " " - } - } - ''; - - prompts.robots = {colors, ...}: '' - { - "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json", - "final_space": true, - "console_title_template": "{{ .Shell }} in {{ .Folder }}", - "version": 4, - "blocks": [ - { - "type": "prompt", - "alignment": "left", - "overflow": "hide", - "segments": [ - { - "type": "os", - "style": "plain", - "foreground_templates": [ - "{{if gt .Code 0}}${colors.base08}{{end}}", - "{{if le .Code 0}}${colors.base0C}{{end}}" - ], - "background": "transparent", - "template": "{{ if .WSL }}WSL at {{ end }}{{.Icon}} " - }, - { - "type": "path", - "style": "plain", - "background": "transparent", - "foreground": "${colors.base0D}", - "template": "  {{ .Path }} ", - "options": { - "style": "folder" - } - }, - { - "type": "git", - "style": "plain", - "foreground": "${colors.base07}", - "background": "transparent", - "github_icon": " ", - "gitlab_icon": " ", - "bitbucket_icon": " ", - "template": "{{ .UpstreamIcon }} at ", - "properties": { - "fetch_upstream_icon": true - } - }, - { - "type": "git", - "style": "powerline", - "powerline_symbol": "", - "leading_powerline_symbol": "", - "foreground": "transparent", - "background": "${colors.base07}", - "template": "{{ .HEAD }}{{ if gt .Behind 0 }}⇣{{ end }}{{ if gt .Ahead 0 }}⇡{{ end }}", - "properties": { - "branch_icon": "", - "fetch_status": true, - "mapped_branches": { - "main": " main", - "main/*": " ", - "develop": " develop", - "develop/*": " ", - "feature/*": " ", - "feat/*": " ", - "bug/*": " ", - "poc/*": "󰙨 " - } - } - } - ] - }, - { - "type": "prompt", - "alignment": "right", - "overflow": "hide", - "segments": [ - { - "type": "executiontime", - "style": "plain", - "foreground_templates": [ - "{{if gt .Code 0}}${colors.base08}{{else}}${colors.base0B}{{end}}" - ], - "template": " {{ .FormattedMs }}", - "options": { - "threshold": 1000, - "style": "austin" - } - } - ] - }, - { - "type": "prompt", - "alignment": "left", - "newline": true, - "segments": [ - { - "type": "text", - "style": "plain", - "foreground_templates": [ - "{{if gt .Code 0}}${colors.base08}{{end}}", - "{{if eq .Code 0}}transparent{{end}}" - ], - "foreground": "${colors.base0C}", - "template": "{{ if gt .Code 0}}󱚝 {{else}}󰚩 {{end}}" - } - ] - } - ], - "transient_prompt": { - "foreground": "${colors.base0D}", - "background": "transparent", - "template": "󱚡 " - }, - "secondary_prompt": { - "foreground": "${colors.base0D}", - "background": "transparent", - "template": "󱙺 " - } - } - ''; - - prompts.custom = {colors, ...}: '' - { - "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json", - "final_space": true, - "console_title_template": "{{ .Shell }} in {{ .Folder }}", - "version": 4, - "blocks": [ - { - "type": "prompt", - "alignment": "left", - "overflow": "hide", - "segments": [ - - { - "type": "path", - "style": "plain", - "background": "transparent", - "foreground": "${colors.base0D}", - "template": "  {{ .Path }} ", - "options": { - "style": "folder" - } - }, - { - "type": "git", - "style": "plain", - "foreground": "${colors.base07}", - "background": "transparent", - "github_icon": " ", - "gitlab_icon": " ", - "bitbucket_icon": " ", - "template": "{{ .UpstreamIcon }} at ", - "properties": { - "fetch_upstream_icon": true - } - }, - { - "type": "git", - "style": "powerline", - "powerline_symbol": "", - "leading_powerline_symbol": "", - "foreground": "transparent", - "background": "${colors.base07}", - "template": "{{ .HEAD }}{{ if gt .Behind 0 }}⇣{{ end }}{{ if gt .Ahead 0 }}⇡{{ end }}", - "properties": { - "branch_icon": "", - "fetch_status": true, - "mapped_branches": { - "main": " main", - "main/*": " ", - "develop": " develop", - "develop/*": " ", - "feature/*": " ", - "feat/*": " ", - "bug/*": " ", - "poc/*": "󰙨 " - } - } - } - ] - }, - { - "type": "prompt", - "alignment": "right", - "overflow": "hide", - "segments": [ - { - "type": "executiontime", - "style": "plain", - "foreground_templates": [ - "{{if gt .Code 0}}${colors.base08}{{else}}${colors.base0B}{{end}}" - ], - "template": " {{ .FormattedMs }}", - "options": { - "threshold": 1000, - "style": "austin" - } - } - ] - }, - { - "type": "prompt", - "alignment": "left", - "newline": true, - "segments": [ - { - "type": "os", - "style": "plain", - "foreground_templates": [ - "{{if gt .Code 0}}${colors.base08}{{end}}", - "{{if le .Code 0}}${colors.base0C}{{end}}" - ], - "background": "transparent", - "template": " {{.Icon}} " - } - ] - } - ], - "transient_prompt": { - "foreground": "${colors.base0D}", - "background": "transparent", - "template": " 󱞩 " - }, - "secondary_prompt": { - "foreground": "${colors.base0D}", - "background": "transparent", - "template": " 󱞩 " - } - } - ''; - }; -} diff --git a/modules/programs/wrappers/kitty.nix b/modules/programs/wrappers/kitty.nix deleted file mode 100644 index 9227372..0000000 --- a/modules/programs/wrappers/kitty.nix +++ /dev/null @@ -1,57 +0,0 @@ -{ - self, - lib, - ... -}: -with lib; let - name = "kitty"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({ - cfg, - pkgs, - ... - }: { - config = { - xdg.configFile."kitty/kitty.conf".text = '' - include ${cfg.configurations.theme.path} - confirm_os_window_close 0 - enable_audio_bell false - font_family JetBrainsMono Nerd Font - bold_font auto - italic_font auto - bold_italic_font auto - - shell ${getExe cfg.configurations.shell} - ''; - }; - }); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: {}); - - flake.programs.${name} = self.lib.mkProgram name ({...}: { - configurations = [self.definitions.programs.terminal]; - }); - - flake.wrappers.${name} = {config, ...}: { - imports = [ - self.wrapperModules._kitty - (self.lib.mkConfigurationsOption [self.definitions.programs.terminal]) - ]; - - config = { - configuration = '' - include ${config.configurations.theme.path} - confirm_os_window_close 0 - enable_audio_bell false - font_family JetBrainsMono Nerd Font - bold_font auto - italic_font auto - bold_italic_font auto - - shell ${getExe config.configurations.shell} - ''; - }; - }; -} diff --git a/modules/programs/wrappers/niri.nix b/modules/programs/wrappers/niri.nix deleted file mode 100644 index 63133bf..0000000 --- a/modules/programs/wrappers/niri.nix +++ /dev/null @@ -1,465 +0,0 @@ -{ - self, - lib, - ... -}: -with lib; let - name = "niri"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: {}); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: {}); - - flake.programs.${name} = self.lib.mkProgram name ({...}: { - configurations = [self.definitions.programs.desktop]; - }); - - flake.wrappers.niri = { - wlib, - pkgs, - config, - ... - }: { - imports = [ - (self.lib.mkConfigurationsOption [self.definitions.programs.desktop]) - wlib.wrapperModules.niri - ]; - - config = { - passthru.providedSessions = ["niri"]; - runtimePkgs = with pkgs; - [ - xwayland-satellite - jq - ] - ++ config.configurations.packages; - - env.FONTCONFIG_FILE = "${config.configurations.fontsConfig}"; - - "config.kdl".content = let - terminal = getExe config.configurations.terminal; - appLauncher = getExe config.configurations.appLauncher; - browser = getExe config.configurations.browser; - host = "aaronv"; - monitorConfigurations = concatStringsSep "\n\n" (mapAttrsToList - ( - name: monitor: let - mode = "${toString monitor.width}x${toString monitor.height}@${toString monitor.refreshRate}"; - in '' - output "${name}" { - ${ - if monitor.enabled - then "" - else "off" - } - mode "${mode}" - position x=${toString monitor.x} y=${toString monitor.y} - scale ${toString monitor.scale} - variable-refresh-rate on-demand=true - ${ - if monitor.primary - then "focus-at-startup" - else "" - } - - hot-corners { - bottom-right - } - } - '' - ) - config.configurations.monitors); - in '' - // ==================== | Launch apps | ==================== - spawn-at-startup "noctalia" - // spawn-at-startup "polkit-gnome-authentication-agent-1" // NOTE: Using the built-in noctalia polkit-agent - spawn-at-startup "xwayland-satellite" - spawn-at-startup "${getExe config.configurations.desktopShell}" - - - - // ==================== | Miscellaneous | ==================== - screenshot-path "~/Pictures/Screenshots/Screenshot_%Y-%m-%d_%H-%M-%S.png" - prefer-no-csd - hotkey-overlay { - skip-at-startup - } - - environment { - DISPLAY ":0" - ELECTRON_OZONE_PLATFORM_HINT "auto" - } - - debug { - // Allows notification actions and window activation from Noctalia. - honor-xdg-activation-with-invalid-serial - } - - - - // ==================== | Input | ==================== - cursor { - // xcursor-theme "" - // xcursor-size - - hide-when-typing - hide-after-inactive-ms 1000 - } - - input { - mod-key "${config.configurations.modKey}" - mod-key-nested "${config.configurations.modKeyAlt}" - warp-mouse-to-focus - focus-follows-mouse max-scroll-amount="5%" - - keyboard { - xkb { - layout "us" - variant "" - options "compose:ralt" - } - numlock - } - - touchpad { - tap - natural-scroll - accel-speed 0.2 - scroll-factor 0.9 - } - - mouse { - accel-speed -0.7 - } - } - - - - // ==================== | Layout | ==================== - layout { - gaps 5 - center-focused-column "on-overflow" - always-center-single-column - default-column-width { proportion 0.5; } - - preset-column-widths { - proportion 0.33333 - proportion 0.5 - proportion 0.66667 - } - - preset-window-heights { - proportion 0.33333 - proportion 0.5 - proportion 0.66667 - } - - focus-ring { - off - width 2 - active-color "#7fc8ff" - inactive-color "#505050" - } - - border { - // off - width 4 - active-color "#7aa2f7" - inactive-color "#505050" - urgent-color "#9b0000" - } - - struts { - left 13 - right 13 - } - - tab-indicator { - gap 4 - length total-proportion=0.5 - position "left" - place-within-column - hide-when-single-tab - } - } - - - - // ==================== | Window Rules | ==================== - window-rule { - open-maximized true - geometry-corner-radius 3 - clip-to-geometry true - - draw-border-with-background false - opacity 0.75 - variable-refresh-rate true - - background-effect { - blur true - xray true - } - } - - // Remove transparency from windows with videos - window-rule { - match title=r#"(?i)youtube"# - opacity 1.0 - background-effect { - blur false - xray false - } - } - - // Block out password managers from screencasts. - window-rule { - match app-id=r#"^org\.keepassxc\.KeePassXC$"# - match app-id=r#"^org\.gnome\.World\.Secrets$"# - match title=r#"(?i)bit(-)?warden"# - - block-out-from "screencast" - } - - // Indicate screencasted windows with red colors. - window-rule { - match is-window-cast-target=true - - focus-ring { - active-color "#f38ba8" - inactive-color "#7d0d2d" - } - - border { - inactive-color "#7d0d2d" - } - - shadow { - color "#7d0d2d70" - } - - tab-indicator { - active-color "#f38ba8" - inactive-color "#7d0d2d" - } - } - - // Steam notifications - window-rule { - match app-id="steam" title=r#"^notificationtoasts_\d+_desktop$"# - default-floating-position x=10 y=10 relative-to="bottom-right" - } - - // Steam games on fullscreen - window-rule { - match app-id=r#"^steam_app_.*$"# - - open-fullscreen true - open-on-workspace "gaming" - } - - - - // ==================== | Layer Rules | ==================== - // Noctalia backgroun on overview mode - layer-rule { - match namespace="^noctalia-backdrop" - place-within-backdrop true - } - - layer-rule { - match namespace="^noctalia-(bar-[^\"]+|notification|dock|panel|attached-panel|osd)$" - - background-effect { - xray false - blur false - } - - popups { - opacity 1.0 - // geometry-corner-radius 15 - - background-effect { - xray false - blur false - } - } - } - - blur { - passes 3 // more passes = stronger blur (default: 3) - offset 3.0 // sample distance per pass (default: 3.0) - noise 0.03 // grain overlay (default: 0.02) - saturation 1.5 // color saturation boost (default: 1.5) - } - - animations { - // off - workspace-switch { - off - } - } - - - - // ==================== | Workspaces | ==================== - spawn-at-startup "${terminal}" - workspace "terminal" - window-rule { - match at-startup=true app-id=r#"^${terminal}$"# - open-on-workspace "terminal" - open-maximized true - } - - workspace "browser" - window-rule { - match at-startup=true app-id=r#"^${browser}$"# - open-on-workspace "browser" - open-maximized true - } - - workspace "multimedia" - window-rule { - match at-startup=true app-id=r#"^spotify$"# - open-on-workspace "multimedia" - open-maximized true - } - - workspace "gaming" - window-rule { - match at-startup=true app-id=r#"^steam$"# - open-on-workspace "gaming" - open-maximized true - } - - workspace "chat" - window-rule { - match at-startup=true app-id=r#"^discord$"# - open-on-workspace "chat" - open-maximized true - } - - workspace "temporal" - - - // ==================== | Monitors | ==================== - ${monitorConfigurations} - - - - // ==================== | Bindings | ==================== - binds { - // Powers off the monitors. To turn them back on, do any input like - // moving the mouse or pressing any other key. - Ctrl+Shift+P { power-off-monitors; } - - Mod+Shift+E { quit; } - Mod+Shift+Slash { show-hotkey-overlay; } - Mod+Space repeat=false hotkey-overlay-title="Open a Terminal" { spawn "${terminal}"; } - Mod+X repeat=false hotkey-overlay-title="Closes the focused window" { close-window; } - Mod+D hotkey-overlay-title="Run the Application Launcher: ${appLauncher}" { spawn "${appLauncher}"; } - Mod+V hotkey-overlay-title="Open the clipboard history app" { spawn "clipboard-history"; } - - - XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.05+ -l 1.0"; } // "-l 1.0" limits the volume to 100%. - XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.05-"; } - XF86AudioMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; } - XF86AudioMicMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; } - - XF86AudioPlay allow-when-locked=true { spawn-sh "playerctl play-pause"; } - XF86AudioStop allow-when-locked=true { spawn-sh "playerctl stop"; } - XF86AudioPrev allow-when-locked=true { spawn-sh "playerctl previous"; } - XF86AudioNext allow-when-locked=true { spawn-sh "playerctl next"; } - - XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "+5%"; } - XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "5%-"; } - - Mod+Left { focus-column-left; } - Mod+Down { focus-window-down; } - Mod+Up { focus-window-up; } - Mod+Right { focus-column-right; } - Mod+H { focus-column-left; } - Mod+J { focus-window-down; } - Mod+K { focus-window-up; } - Mod+L { focus-column-right; } - - Mod+Shift+Left { move-column-left; } - Mod+Shift+Down { move-window-down; } - Mod+Shift+Up { move-window-up; } - Mod+Shift+Right { move-column-right; } - Mod+Shift+H { move-column-left; } - Mod+Shift+J { move-window-down; } - Mod+Shift+K { move-window-up; } - Mod+Shift+L { move-column-right; } - - Mod+Ctrl+H { consume-or-expel-window-left; } - Mod+Ctrl+L { consume-or-expel-window-right; } - - Mod+1 { focus-workspace 1; } - Mod+2 { focus-workspace 2; } - Mod+3 { focus-workspace 3; } - Mod+4 { focus-workspace 4; } - Mod+5 { focus-workspace 5; } - Mod+6 { focus-workspace 6; } - Mod+7 { focus-workspace 7; } - Mod+8 { focus-workspace 8; } - Mod+9 { focus-workspace 9; } - - Mod+Shift+1 { move-column-to-workspace 1; } - Mod+Shift+2 { move-column-to-workspace 2; } - Mod+Shift+3 { move-column-to-workspace 3; } - Mod+Shift+4 { move-column-to-workspace 4; } - Mod+Shift+5 { move-column-to-workspace 5; } - Mod+Shift+6 { move-column-to-workspace 6; } - Mod+Shift+7 { move-column-to-workspace 7; } - Mod+Shift+8 { move-column-to-workspace 8; } - Mod+Shift+9 { move-column-to-workspace 9; } - - Mod+Minus { set-window-width "-10%"; } - Mod+Equal { set-window-width "+10%"; } - Mod+Shift+Minus { set-window-height "-10%"; } - Mod+Shift+Equal { set-window-height "+10%"; } - - Mod+U { focus-workspace "terminal"; } - Mod+I { focus-workspace "browser"; } - Mod+O { focus-workspace "chat"; } - Mod+P { focus-workspace "multimedia"; } - Mod+G { focus-workspace "gaming"; } - Mod+T { focus-workspace "temporal"; } - - Mod+Shift+U { move-column-to-workspace "terminal"; } - Mod+Shift+I { move-column-to-workspace "browser"; } - Mod+Shift+O { move-column-to-workspace "chat"; } - Mod+Shift+P { move-column-to-workspace "multimedia"; } - Mod+Shift+G { move-column-to-workspace "gaming"; } - Mod+Shift+T { move-column-to-workspace "temporal"; } - - Mod+Comma { move-workspace-to-monitor-previous; } - Mod+Period { move-workspace-to-monitor-next; } - - Mod+Tab { toggle-column-tabbed-display; } - - Mod+F { maximize-column; } - Mod+Shift+F { fullscreen-window; } - // Mod+Ctrl+F { toggle-window-floating; } - Mod+Ctrl+F { - spawn-sh "if [ \"$(niri msg -j focused-window | jq -r .is_floating)\" = \"false\" ]; then niri msg action toggle-window-floating && niri msg action set-window-width -- 60% && niri msg action set-window-height -- 60%; else niri msg action toggle-window-floating; fi" - } - Mod+S { switch-preset-column-width; } - Mod+C { center-visible-columns; } - - Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } - - Ctrl+Shift+3 { screenshot-screen; } - Ctrl+Shift+5 { screenshot-window; } - Ctrl+Shift+4 { screenshot; } - - Mod+Ctrl+Shift+W { set-dynamic-cast-window; } - Mod+Ctrl+Shift+M { set-dynamic-cast-monitor; } - Mod+Ctrl+Shift+C { clear-dynamic-cast-target; } - } - ''; - }; - }; -} diff --git a/modules/programs/wrappers/oh-my-posh.nix b/modules/programs/wrappers/oh-my-posh.nix deleted file mode 100644 index 8d650e1..0000000 --- a/modules/programs/wrappers/oh-my-posh.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ - self, - lib, - ... -}: -with lib; let - name = "oh-my-posh"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: {}); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: {}); - - flake.programs.${name} = self.lib.mkProgram name ({...}: {}); - - flake.wrappers.${name} = { - pkgs, - config, - ... - }: { - imports = [ - self.wrapperModules._oh-my-posh - (self.lib.mkConfigurationsOption [self.wrapperHelpers.modules.theme]) - ]; - config = let - colors = config.configurations.colors; - in { - runtimePkgs = with pkgs; [ - nerd-fonts.jetbrains-mono - ]; - configuration = self.wrapperHelpers.oh-my-posh.prompts.custom {inherit colors;}; - }; - }; -} diff --git a/modules/programs/wrappers/tmux.nix b/modules/programs/wrappers/tmux.nix deleted file mode 100644 index 98d6f70..0000000 --- a/modules/programs/wrappers/tmux.nix +++ /dev/null @@ -1,90 +0,0 @@ -{ - self, - lib, - ... -}: -with lib; let - name = "tmux"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: {}); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: {}); - - flake.programs.${name} = self.lib.mkProgram name ({...}: { - configurations = [self.definitions.${name}]; - }); - - flake.wrappers.${name} = { - wlib, - pkgs, - config, - ... - }: { - imports = [ - wlib.wrapperModules.tmux - (self.lib.mkConfigurationsOption [self.wrapperHelpers.modules.theme]) - ]; - - config = let - colors = config.configurations.colors; - in { - prefix = "C-space"; - modeKeys = "vi"; - vimVisualKeys = true; - plugins = with pkgs; [ - tmuxPlugins.sensible - tmuxPlugins.resurrect - tmuxPlugins.yank - ]; - terminal = "tmux-256color"; - terminalOverrides = ",xterm-256color:Tc"; - configBefore = '' - set -g renumber-windows on # keep numbering sequential - set -g focus-events on # Enable focus events for vim autoread - - # Better pane splitting (and keep current path) - bind | split-window -h -c "#{pane_current_path}" - bind - split-window -v -c "#{pane_current_path}" - bind c new-window -c "#{pane_current_path}" - - # Vim-style pane navigation - bind h select-pane -L - bind j select-pane -D - bind k select-pane -U - bind l select-pane -R - - # Vim-style pane resizing - bind -r H resize-pane -L 5 - bind -r J resize-pane -D 5 - bind -r K resize-pane -U 5 - bind -r L resize-pane -R 5 - - # Theme: status - set -g status-style bg=${colors.base00},fg=${colors.base03},bright - set -g status-left " " - set -g status-right "#[fg=orange,bright]#S " - - # Theme: status (windows) - set -g window-status-format "●" - set -g window-status-current-format "●" - - set -g window-status-current-style "#{?window_zoomed_flag,fg=yellow,fg=${colors.base0D}\#,nobold}" - set -g window-status-bell-style "fg=red,nobold" - - bind-key x kill-pane # skip "kill-pane 1? (y/n)" prompt - # NOTE: Commented as it didn't worked well with the {name}' sessions for the floating panes - # set -g detach-on-destroy off # don't exit from tmux when closing a session - - bind-key -r f run-shell "sessions" - bind-key -r l run-shell "toggle-tmux-popup" - bind-key -r g run-shell 'tmux popup -E -d "#{pane_current_path}" -w "90%" -h "90%" -T "LazyGit" "lazygit"' - - set -gq allow-passthrough on - set -g visual-activity off - set-option -g focus-events on - ''; - }; - }; -} diff --git a/modules/programs/wrappers/zsh.nix b/modules/programs/wrappers/zsh.nix deleted file mode 100644 index 233ee24..0000000 --- a/modules/programs/wrappers/zsh.nix +++ /dev/null @@ -1,248 +0,0 @@ -{ - self, - lib, - ... -}: -with lib; let - name = "zsh"; -in { - flake.darwinModules.programs = self.lib.mkDarwinProgram name ({...}: {}); - - flake.homeModules.programs = self.lib.mkHomeProgram name ({...}: {}); - - flake.nixosModules.programs = self.lib.mkNixosProgram name ({...}: {}); - - flake.programs.${name} = self.lib.mkProgram name ({...}: { - configurations = [self.definitions.programs.shell]; - }); - - flake.wrappers.${name} = { - wlib, - pkgs, - config, - ... - }: { - imports = [ - wlib.wrapperModules.zsh - (self.lib.mkConfigurationsOption [self.definitions.programs.shell]) - ]; - - config = with pkgs; { - env = config.configurations.envVariables; - zshAliases = config.configurations.shellAliases; - - runtimePkgs = - [ - #wrapped - config.configurations.shellPrompt - ] - ++ config.configurations.packages; - - zshrc.content = '' - autoload -Uz compinit - if [[ -x $(command -v fzf) ]]; then eval "$(fzf --zsh)"; fi - - typeset -i updated_at=$(date +'%j' -r $HOME/.zcompdump 2>/dev/null || stat -f '%Sm' -t '%j' $HOME/.zcompdump 2>/dev/null) - typeset -i today=$(date +'%j') - - if [[ $updated_at -eq $today ]]; then - compinit -C -i - else - compinit -i - fi - - zmodload -i zsh/complist - - - # ============================== - # Environment Varialbes - # ============================== - - # History configurations - HISTFILE=$HOME/.zsh_history - HISTSIZE=100000 - HISTDUP=erase - SAVEHIST=$HISTSIZE - - # Autosuggest configurations - ZSH_AUTOSUGGEST_STRATEGY=(history completion) - ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20 - - # Stop zsh autocorrect from suggesting undesired completions - CORRECT_IGNORE_FILE=".*" - CORRECT_IGNORE="_*" - - - # ============================== - # ZSH Options - # ============================== - - setopt auto_cd - setopt correct_all - setopt interactive_comments - - # History configurations - setopt hist_expire_dups_first - setopt hist_find_no_dups - setopt hist_ignore_space - setopt hist_ignore_all_dups - setopt hist_reduce_blanks - setopt hist_save_no_dups - setopt hist_verify - setopt inc_append_history - setopt share_history - - # Autosuggest configurations - setopt auto_list - setopt auto_menu - setopt always_to_end - - - zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}' - zstyle ':completion:*' list-colors "''${(s.:.)LS_COLORS}" - zstyle ':completion:*' menu no - zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls --color $realpath' - zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'ls --color $realpath' - zstyle ':fzf-tab:*' use-fzf-default-opts yes - - # ============================== - # vi Mode - # ============================== - - bindkey -v - bindkey -M viins 'jk' vi-cmd-mode - - # Cursor shape: block in normal, beam in insert - function zle-keymap-select { - if [[ $KEYMAP == vicmd ]]; then - echo -ne '\e[1 q' # block cursor - else - echo -ne '\e[5 q' # beam cursor - fi - } - zle -N zle-keymap-select - - function zle-line-init { - echo -ne '\e[5 q' # beam cursor on new prompt - } - zle -N zle-line-init - - - # ============================== - # Keybindings - # ============================== - - bindkey ' ' magic-space - - # History keybindings - bindkey '^[[A' history-substring-search-up - bindkey '^[[B' history-substring-search-down - - # Autosuggest keybindings - bindkey '^y' autosuggest-accept - - # Edit command buffer - autoload -Uz edit-command-line - zle -N edit-command-line - bindkey '^ e' edit-command-line - - - # ============================== - # Hooks - # ============================== - autoload -Uz add-zsh-hook - - # Reference: https://gist.github.com/elliottminns/09a598082d77f795c88e93f7f73dba61 - - function auto_venv() { - # If already in a virtualenv, do nothing - if [[ -n "$VIRTUAL_ENV" && "$PWD" != *"''${VIRTUAL_ENV:h}"* ]]; then - deactivate - return - fi - - [[ -n "$VIRTUAL_ENV" ]] && return - - local dir="$PWD" - while [[ "$dir" != "/" ]]; do - if [[ -f "$dir/.venv/bin/activate" ]]; then - source "$dir/.venv/bin/activate" - return - fi - dir="''${dir:h}" - done - } - - function auto_nix() { - # If we're already in a nix develop shell, do nothing - [[ -n "$IN_NIX_SHELL" ]] && return - - # Walk up to find a flake - local dir="$PWD" - while [[ "$dir" != "/" ]]; do - if [[ -f "$dir/flake.nix" ]]; then - # If this project already has .envrc, just allow it (you can remove this if you prefer) - if [[ ! -f "$dir/.envrc" ]]; then - # Create .envrc that loads the dev env (fast, no interactive shell) - cat > "$dir/.envrc" <<'EOF' - # autogenerated: load flake dev environment - eval "$(nix print-dev-env)" - EOF - command direnv allow "$dir" >/dev/null 2>&1 - fi - - command direnv reload >/dev/null 2>&1 - return - fi - dir="''${dir:h}" - done - } - - function auto_nvm() { - [[ -f .nvmrc ]] && nvm use - } - - function auto_ls() { - BLUE='\033[0;34m' - NOCOLOR='\033[0m' - count=$(fd -d 1 --max-results 26 | wc -l) - if [ $count -le 25 ]; then - echo " ''${BLUE} ''${NOCOLOR}files at ''${BLUE}$(pwd)''${NOCOLOR}:" - ls - else - echo " ''${BLUE} ''${NOCOLOR}there are more than 25 files at ''${BLUE}$(pwd)''${NOCOLOR}" - fi - } - - add-zsh-hook chpwd auto_venv - add-zsh-hook chpwd auto_nix - add-zsh-hook chpwd auto_nvm - add-zsh-hook chpwd auto_ls - - # ============================== - # Plugins - # ============================== - # KEYTIMEOUT=1 - # ZVM_LINE_INIT_MODE=$ZVM_MODE_INSERT - # ZVM_VI_INSERT_ESCAPE_BINDKEY=jk - # source ${zsh-vi-mode}/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh - - source ${zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh - source ${zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh - source ${zsh-history-substring-search}/share/zsh-history-substring-search/zsh-history-substring-search.zsh - source ${zsh-fzf-tab}/share/fzf-tab/fzf-tab.plugin.zsh - - if [ "$TERM_PROGRAM" != "Apple_Terminal" ]; then - eval "$(${getExe' config.configurations.shellPrompt "oh-my-posh"} init zsh)" - fi - - if [[ "$TMUX" == "" ]]; then - if [[ "$(tmux ls 2>/dev/null)" == "" ]]; then - tmux new -s kyoten - fi - sesh connect kyoten - fi - ''; - }; - }; -} diff --git a/modules/programs/zen.nix b/modules/programs/zen.nix new file mode 100644 index 0000000..98d1f80 --- /dev/null +++ b/modules/programs/zen.nix @@ -0,0 +1,5 @@ +{inputs, ...}: { + anvil.programs.zen = { + getPackage = {pkgs, ...}: inputs.zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default; + }; +} diff --git a/modules/programs/zsh.nix b/modules/programs/zsh.nix new file mode 100644 index 0000000..d95332f --- /dev/null +++ b/modules/programs/zsh.nix @@ -0,0 +1,62 @@ +{ + self, + lib, + ... +}: +with lib; let + commonModule = { + program, + pkgs, + ... + }: let + package = with program.metadata; program.getPackage {inherit pkgs configuration;}; + in { + programs.zsh.enable = true; + environment.pathsToLink = ["/share/zsh"]; + environment.systemPackages = [package]; + }; +in { + anvil.programs.zsh = { + getPackage = self.wrappers.zsh.wrap; + # getPackage = { + # pkgs, + # configuration, + # ... + # }: + # self.wrappers.zsh.wrap ({inherit pkgs;} // configuration); + nixos = commonModule; + darwin = commonModule; + }; + + flake.wrappers.zsh = { + wlib, + pkgs, + config, + ... + }: { + imports = [ + wlib.wrapperModules.zsh + self.declarations.shell + ]; + + config = with pkgs; { + env = config.envVariables; + zshAliases = config.shellAliases; + runtimePkgs = + [ + zsh-defer + zsh-autosuggestions + zsh-fast-syntax-highlighting + zsh-history-substring-search + zsh-fzf-tab + zsh-completions + ] + ++ config.packages; + + zshrc.content = with config; + self.dotfiles.zsh.default { + inherit pkgs activationScripts prompt multiplexer; + }; + }; + }; +} diff --git a/modules/secrets/personal.nix b/modules/secrets/personal.nix new file mode 100644 index 0000000..e92c86e --- /dev/null +++ b/modules/secrets/personal.nix @@ -0,0 +1,38 @@ +{ + inputs, + self, + lib, + ... +}: +with lib; { + anvil.features.personal-secrets = let + mkIfUser = user: mkIf (user != null); + commonModule = {user, ...}: { + sops = { + defaultSopsFile = ./personal.yaml; + secrets = { + "email" = {owner = mkIfUser user user.name;}; + "password" = {owner = mkIfUser user user.name;}; + }; + }; + }; + in { + features = ["sops"]; + nixos = {user, ...}: let + ctx = {inherit user;}; + in { + imports = [ + inputs.sops-nix.nixosModules.sops + (self.lib.withContext ctx commonModule) + ]; + }; + darwin = {user, ...}: let + ctx = {inherit user;}; + in { + imports = [ + inputs.sops-nix.darwinModules.sops + (self.lib.withContext ctx commonModule) + ]; + }; + }; +} diff --git a/modules/secrets/personal.yaml b/modules/secrets/personal.yaml new file mode 100644 index 0000000..d286511 --- /dev/null +++ b/modules/secrets/personal.yaml @@ -0,0 +1,44 @@ +email: ENC[AES256_GCM,data:xXyeGJy8GwjFTbUxIEwELP1l9y8TCCXJkg==,iv:s7dWI9MublcPcTg2Sf5VJRZchkdEfeWpOmsJiimYj1o=,tag:QBOP6MyJ9hW+KQXIpDjXNg==,type:str] +password: ENC[AES256_GCM,data:oZaD88a/PkHt,iv:pV+VMa5CHi94LST3v3Fh8N45T03utHk1eyYidsXFB1c=,tag:GUElAsn9GqTBgqKDBs8JZg==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyUFlTaWxHQ2xxQ0thcGZs + WTVWdThpS3pUOG5nUGtHY0hDRW0yWkZhUVVjCjJWRlRuaWtFT0VzUjVzM3pVT1dt + ZU56VjFHR2tnMjl2Y21DS0c3N1RwbkEKLS0tIHIrTVdxdnByVzNWc0lZK3VqOTNT + cTVrYTQvNjdjaXo4MDFRNXVoaTlUb2MKTiFk+ZPxLovJtIqZAbEyYOf4h37l7dQr + 3hYHSnWhD12WGkfHv4CGMOzElFbrt0kwferXTI2regqZ4rpMgDblLg== + -----END AGE ENCRYPTED FILE----- + recipient: age13vyme78jmvjv499t7dzl2ju4epy90792nje0mvyh6ar93zae75kqyzsr2j + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZY3U2d0JITHRqYklybzZZ + aXRVUUV5L0d3aEdEZ00xVmdQQWVlZlpTbWpzCklyNDgzUCtFSXNZajNpVEtxeitP + TDFLRnVrZ3p4cDA2OHVuRWZWeTQ3c3cKLS0tIERzYlZBazhVN3JIejVUVHZVNUVH + M3Z0c0VtaFFyRjRhN2xTdU9hVXdTN0UKVff5WmSZ3Cp/mjHGtiCf4zX18W4KItha + Ap6b332tqMPLgoVLsfzGJ2rnEd3tnrWeCbdMLwVKhqvm7uswIwmjDA== + -----END AGE ENCRYPTED FILE----- + recipient: age146xlkyvdxgjqjt3fnawtvqgzuk0fwgjsj9gf3c0z3q5n02r49vgsz3nk4s + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEMFNlWStxUVgvdFBYa0pJ + UklqYzMvNExkY1NpcVQwZVZ3dHIxalVuZHdNCmFuS0Vxc3FrbVQ3NndnS0V2bC9W + bTJzTncxbHR3U0R3dGJXRGI4T3J0dDgKLS0tIFNXUStHRUszTmMyNDgvNm1XeDRp + c1RxOGc4eUtLaXdXTEFERkVNVmF3MXMKcEKatCPUdSYb3M9FquCLiigyC5/UnoT4 + BgGThlITGErqLCST/Sb+Pi1RYXi5tfoDGsn02z0vtn35wuYmoeimfg== + -----END AGE ENCRYPTED FILE----- + recipient: age1sjlg4s9jq2qlevlkhylguul7ztxr6cassnj7xle7patzlgmy5syqan5vpz + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkMmludUhtcmlqT1pTck1p + YjB2QmZ4WXBPNzltMXIxZjM2Z1Z6VUJQemxJClpnT0o4NDk1ci9JWFdxK0hDZFFH + SFdoWEoyTVpHTnNrWGVjTGNMQmVKUVEKLS0tIEl5Q2J1K3RvZnk2R3cwUlFleGh3 + RTJUZGRkeEV2THExV1dpQ0NCdnk2MlkK7L8onrhVsndh5RzC1kIcn+AHhCd/5G1P + PFlNSGpjvOMm7q9BumL80GfTUf+dSA85FAmquG6W31KZBWMTLoa2Jw== + -----END AGE ENCRYPTED FILE----- + recipient: age1mjqu5xzvtgcpvy5tg9cnv7hk8vd9vmmgxmk8xtj3wudj2qf7ugcq53weqr + lastmodified: "2026-09-02T04:47:27Z" + mac: ENC[AES256_GCM,data:OuF+Aox2oanQW5r4Fw7bJEDcgQgP3qwVHRnc4FkFTLQfvcdZPShwVRRIbj9BPdFWsSk9eowxi2cDAfrCn/WdB4rPweNkjnU9wXgtsp4rAKpj69BzagBq6d6PN0/V9pVdw2dTQgZcKOAm0ykPOTqChcv7R/vaONIdC70cwC97a9w=,iv:QTxyv01qpE3l3tTNGyFzD4OM33otK9K+NYfC4fGb0aU=,tag:iaBy3O74CqgZrNljtvRVYQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/modules/secrets/work.nix b/modules/secrets/work.nix new file mode 100644 index 0000000..6907952 --- /dev/null +++ b/modules/secrets/work.nix @@ -0,0 +1,37 @@ +{ + inputs, + self, + lib, + ... +}: +with lib; { + anvil.features.work-secrets = let + mkIfUser = user: mkIf (user != null); + commonModule = {user, ...}: { + sops = { + defaultSopsFile = ./personal.yaml; + secrets = { + "email" = {owner = mkIfUser user user.name;}; + }; + }; + }; + in { + features = ["sops"]; + nixos = {user, ...}: let + ctx = {inherit user;}; + in { + imports = [ + inputs.sops-nix.nixosModules.sops + (self.lib.withContext ctx commonModule) + ]; + }; + darwin = {user, ...}: let + ctx = {inherit user;}; + in { + imports = [ + inputs.sops-nix.darwinModules.sops + (self.lib.withContext ctx commonModule) + ]; + }; + }; +} diff --git a/modules/secrets/work.yaml b/modules/secrets/work.yaml new file mode 100644 index 0000000..38f40d1 --- /dev/null +++ b/modules/secrets/work.yaml @@ -0,0 +1,25 @@ +email: ENC[AES256_GCM,data:Ok5nTpMydtJG1yeguz3A4oGDw/1rhhVjylF35A==,iv:d6J9iTdWQKpSKZ1r0juLkcpwb5i2y/za1/WKYfLNT40=,tag:d6hk1FwfIYO3jxltEDeIIA==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArMVQwcXdVaWhWc2dZTnZy + RFlWS09oQ0dSd0YzamJjM2REcVRHdTVjc1dRCjhXVkVrTm91azRFM0tWcWRMa0gy + TU0xcDdRY0trWG1lVkgva2hHWHZ2TGcKLS0tIHBUendvTHZXNU14K1Rsd25hcERR + N0YvenZSYTVPL2R1V0FXU0NCYlJWeGMKV/zD8gcT/ubN29r8cAn1VRiFLtmlIqY6 + D+B+D5Rteei6ENkO2RGsW7Bq9V/iwQBZM1MZJnzuWwnQU7/CUBsnBQ== + -----END AGE ENCRYPTED FILE----- + recipient: age13vyme78jmvjv499t7dzl2ju4epy90792nje0mvyh6ar93zae75kqyzsr2j + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUQldvSEJ1dlJKcUs3cU1p + ajVWZS9NNUQ5d1RCcngrK25JbTdTLzFMakZzCnBseFBobC8vbG9YbUF2NHVXK3pT + dytzZ29yd3FRSW5iMEZVREUzTlJUZ1EKLS0tIGUvRkpiQXJZL1h3M3BjR05UUHpj + VXlrWXZQdGo5OVhYRlJCS3NDQlVMa0kK5v37XPGb8jJz0qtCuMYcNcX8jG4bnuA5 + zySL6CHNwY5RJGHkQU+hGnUlrJ+OEkyZTBgMKnxlMy2qvdmNkZtw2Q== + -----END AGE ENCRYPTED FILE----- + recipient: age146xlkyvdxgjqjt3fnawtvqgzuk0fwgjsj9gf3c0z3q5n02r49vgsz3nk4s + lastmodified: "2026-09-19T22:14:36Z" + mac: ENC[AES256_GCM,data:rCSYYn6xb77sTZXw0SgXw5yXJAAJHRsjQmHWub07QMS2dlaFzp4wQZ7BmCf0eAcmyasuXTBboF8jR81nFOVrzxl9qel5fwxhodZJcYlerOdfIamplmTFeOYXtVgLHlBdyspwi0xme18JCa4eUQAOAipw8JNcXWX9+FsVAkGSeWw=,iv:eAXxuXc1xksDl9iJqPiz6HKbYoeftq9U7wCbk81+rYk=,tag:wdFdMMLQ81k/vzBWnrdNmQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/modules/users/aaronv-work.nix b/modules/users/aaronv-work.nix new file mode 100644 index 0000000..d694d2d --- /dev/null +++ b/modules/users/aaronv-work.nix @@ -0,0 +1,33 @@ +{...}: { + anvil.users.aaronv-work = { + name = "aaronv"; + description = "Aaron Vargas"; + metadata = {}; + programs = [ + "editor" + "terminal" + "desktop" + ]; + features = [ + "homeManager" + # "work-secrets" + ]; + homeDir.nixos = "/home/aaronv"; + homeDir.darwin = "/Users/aaronv"; + darwin = {user, ...}: { + users.users.${user.name} = { + description = user.description; + # nix-darwin requires a uid; 501 is the macOS first-user uid. + uid = 501; + home = user.homeDir.darwin; + createHome = true; + }; + users.groups.${user.name} = {}; + # nix-darwin only creates the account on activation when registered. + users.knownUsers = [user.name]; + }; + home = {user, ...}: { + home.username = user.name; + }; + }; +} diff --git a/modules/users/aaronv.nix b/modules/users/aaronv.nix new file mode 100644 index 0000000..435468d --- /dev/null +++ b/modules/users/aaronv.nix @@ -0,0 +1,64 @@ +{lib, ...}: +with lib; { + anvil.users.aaronv = { + name = "aaronv"; + description = "Aaron Vargas"; + metadata = { + email = "41397746+aaron70@users.noreply.github.com"; + }; + programs = [ + "editor" + "terminal" + "desktop" + ]; + features = [ + "homeManager" + "personal-secrets" + ]; + homeDir.nixos = "/home/aaronv"; + homeDir.darwin = "/Users/aaronv"; + nixos = { + user, + config, + pkgs, + ... + }: { + users.users.${user.name} = { + description = user.description; + uid = 1000; + isNormalUser = true; + extraGroups = ["networkmanager" "wheel" "audio"]; + group = user.name; + home = user.homeDir.nixos; + hashedPasswordFile = config.sops.secrets."password".path; + packages = with pkgs; [ + go_1_27 + goperf + ]; + }; + users.groups.${user.name} = {}; + + virtualisation.vmVariant = { + users.users.${user.name} = { + hashedPasswordFile = mkForce null; + initialPassword = "anvil"; + }; + }; + }; + darwin = {user, ...}: { + users.users.${user.name} = { + description = user.description; + # nix-darwin requires a uid; 501 is the macOS first-user uid. + uid = 501; + home = user.homeDir.darwin; + createHome = true; + }; + users.groups.${user.name} = {}; + # nix-darwin only creates the account on activation when registered. + users.knownUsers = [user.name]; + }; + home = {user, ...}: { + home.username = user.name; + }; + }; +} diff --git a/modules/wrapperModules/ghostty.nix b/modules/wrapperModules/ghostty.nix deleted file mode 100644 index 627cfac..0000000 --- a/modules/wrapperModules/ghostty.nix +++ /dev/null @@ -1,28 +0,0 @@ -{lib, ...}: -with lib; { - flake.wrappers._ghostty = { - config, - wlib, - pkgs, - ... - }: { - imports = [wlib.modules.default]; - - options = { - configuration = mkOption { - type = types.str; - description = "The Ghostty configuration file's contents."; - default = ""; - }; - }; - - config = { - package = - if pkgs.stdenv.isDarwin - then pkgs.ghostty-bin - else pkgs.ghostty; - flagSeparator = "="; - flags."--config-file" = pkgs.writeText "config.ghostty" config.configuration; - }; - }; -} diff --git a/modules/wrapperModules/kitty.nix b/modules/wrapperModules/kitty.nix deleted file mode 100644 index caca13e..0000000 --- a/modules/wrapperModules/kitty.nix +++ /dev/null @@ -1,25 +0,0 @@ -{lib, ...}: -with lib; { - flake.wrappers._kitty = { - config, - wlib, - pkgs, - ... - }: { - imports = [wlib.modules.default]; - - options = { - configuration = mkOption { - type = types.str; - description = "The Kitty configuration file's contents."; - default = ""; - }; - }; - - config = { - package = pkgs.kitty; - # flagSeparator="="; - flags."--config" = pkgs.writeText "kitty.conf" config.configuration; - }; - }; -} diff --git a/modules/wrapperModules/oh-my-posh.nix b/modules/wrapperModules/oh-my-posh.nix deleted file mode 100644 index 6188987..0000000 --- a/modules/wrapperModules/oh-my-posh.nix +++ /dev/null @@ -1,24 +0,0 @@ -{lib, ...}: -with lib; { - flake.wrappers._oh-my-posh = { - config, - wlib, - pkgs, - ... - }: { - imports = [wlib.modules.default]; - - options = { - configuration = mkOption { - type = types.str; - description = "The JSON configuration file's contents."; - default = ""; - }; - }; - - config = { - package = pkgs.oh-my-posh; - flags."--config" = pkgs.writeText "config.json" config.configuration; - }; - }; -} diff --git a/resources/themes/tokyo-night-moon.json b/resources/themes/tokyo-night-moon.json new file mode 100644 index 0000000..98aeaad --- /dev/null +++ b/resources/themes/tokyo-night-moon.json @@ -0,0 +1,24 @@ +{ + "system": "base16", + "name": "Tokyo Night Moon", + "author": "Ólafur Bjarki Bogason", + "variant": "dark", + "palette": { + "base00": "#222436", + "base01": "#1e2030", + "base02": "#2d3f76", + "base03": "#3b4261", + "base04": "#636da6", + "base05": "#828bb8", + "base06": "#aeb4d1", + "base07": "#c8d3f5", + "base08": "#ff757f", + "base09": "#ffc777", + "base0A": "#ffdf77", + "base0B": "#c3e88d", + "base0C": "#86e1fc", + "base0D": "#82aaff", + "base0E": "#fca7ea", + "base0F": "#c53b53" + } +} \ No newline at end of file