Compare commits
19 Commits
63ca392537
...
d38e3ed616
| Author | SHA1 | Date | |
|---|---|---|---|
| d38e3ed616 | |||
| 6356e07364 | |||
| 4dcf0e8cdd | |||
| 0616e3db30 | |||
| 761d02ddda | |||
| 1c15c55605 | |||
| a0dcb258c9 | |||
| 19792c9390 | |||
| ac1c04d157 | |||
| d1548644f5 | |||
| 7b41584d5c | |||
| faf2242539 | |||
| 27069e324f | |||
| 829f209300 | |||
| 06bc420948 | |||
| b806359fd6 | |||
| 0c4f555dec | |||
| 19dfb32cf6 | |||
| 79b325676d |
@@ -0,0 +1,19 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{nix,yaml,yml,json,md,sh,toml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# Markdown uses trailing whitespace for hard line breaks.
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
+1
-5
@@ -1,10 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": ["config:recommended", ":dependencyDashboard", ":semanticCommits"],
|
||||||
"config:recommended",
|
|
||||||
":dependencyDashboard",
|
|
||||||
":semanticCommits"
|
|
||||||
],
|
|
||||||
"nix": {
|
"nix": {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ single flake.
|
|||||||
Defined in the host table in [`flake.nix`](./flake.nix):
|
Defined in the host table in [`flake.nix`](./flake.nix):
|
||||||
|
|
||||||
| Configuration | System | Machine |
|
| Configuration | System | Machine |
|
||||||
| ------------------- | --------------- | ---------------------------------------- |
|
| --------------------- | ---------------- | --------------------------------------------------------------------------- |
|
||||||
| `lyrathorpe-mbp` | `aarch64-linux` | MacBook Pro (Apple Silicon, Asahi) |
|
| `lyrathorpe-mbp` | `aarch64-linux` | MacBook Pro (Apple Silicon, Asahi) |
|
||||||
| `lyrathorpe-t400` | `x86_64-linux` | ThinkPad T400 — [install notes](./system/machine/T400/README.md) |
|
| `lyrathorpe-t400` | `x86_64-linux` | ThinkPad T400 — [install notes](./system/machine/T400/README.md) |
|
||||||
| `lyrathorpe-macpro31` | `x86_64-linux` | Mac Pro 3,1, desktop — [install notes](./system/machine/MacPro31/README.md) |
|
| `lyrathorpe-macpro31` | `x86_64-linux` | Mac Pro 3,1, desktop — [install notes](./system/machine/MacPro31/README.md) |
|
||||||
@@ -28,9 +28,11 @@ sudo nixos-rebuild switch --flake .#<configuration>
|
|||||||
darwin-rebuild switch --flake .#lyrathorpe-mac
|
darwin-rebuild switch --flake .#lyrathorpe-mac
|
||||||
```
|
```
|
||||||
|
|
||||||
## Keybindings
|
## Shell environment & keybindings
|
||||||
|
|
||||||
All Sway / tmux / foot / zsh keyboard shortcuts are documented in
|
- Interactive shell features (zsh, tmux, git, ssh, CLI tools, auto-tmux):
|
||||||
|
[`lyrathorpe/home/README.md`](./lyrathorpe/home/README.md).
|
||||||
|
- All Sway / tmux / foot / zsh keyboard shortcuts:
|
||||||
[`lyrathorpe/home/KEYBINDINGS.md`](./lyrathorpe/home/KEYBINDINGS.md).
|
[`lyrathorpe/home/KEYBINDINGS.md`](./lyrathorpe/home/KEYBINDINGS.md).
|
||||||
|
|
||||||
## Login / greeter
|
## Login / greeter
|
||||||
@@ -46,14 +48,29 @@ WSL work box) keep plain TTY login. The target account needs a password
|
|||||||
## MacBook (Asahi) firmware
|
## MacBook (Asahi) firmware
|
||||||
|
|
||||||
The MBP host references `system/modules/firmware/` for Apple peripheral
|
The MBP host references `system/modules/firmware/` for Apple peripheral
|
||||||
firmware (Wi-Fi/Bluetooth). Those blobs are **not** redistributable, so the
|
firmware (Wi-Fi/Bluetooth). These blobs are **committed** (tracked) even though
|
||||||
directory is gitignored and a clean checkout will not build `lyrathorpe-mbp`
|
`.gitignore` lists the directory: the flake is `git+file`, so it only sees
|
||||||
until it is populated out-of-band.
|
tracked files — untracking them breaks `lyrathorpe-mbp` evaluation (and the CI
|
||||||
|
host-eval) because the config can't find the firmware. They are not
|
||||||
|
redistributable; the repo is private.
|
||||||
|
|
||||||
Copy the firmware extracted during the Asahi install (from
|
To refresh them, copy the firmware extracted during the Asahi install (from
|
||||||
`/etc/nixos/firmware` on the freshly-installed machine, or re-extract per the
|
`/etc/nixos/firmware`, or re-extract per the
|
||||||
[Asahi NixOS docs](https://github.com/tpwrules/nixos-apple-silicon)) into
|
[Asahi NixOS docs](https://github.com/tpwrules/nixos-apple-silicon)) into
|
||||||
`system/modules/firmware/` before rebuilding that host.
|
`system/modules/firmware/` and commit with `git add -f`.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
A dev shell and a formatting/lint gate are wired through the flake:
|
||||||
|
|
||||||
|
- `nix develop` — shell with `deadnix`, `statix`, `treefmt`, and the git
|
||||||
|
`pre-commit` hooks (installed automatically on first entry).
|
||||||
|
- `nix fmt` — formats the tree via `treefmt` (nixfmt + shfmt + prettier;
|
||||||
|
generated files and `flake.lock` are excluded).
|
||||||
|
- `nix flake check` — runs formatting, `deadnix`, `statix`, the pre-commit
|
||||||
|
hooks, and evaluates every host. `.editorconfig` carries the base style;
|
||||||
|
`statix.toml` disables the two house-style lints (`repeated_keys`,
|
||||||
|
`empty_pattern`).
|
||||||
|
|
||||||
## CI
|
## CI
|
||||||
|
|
||||||
|
|||||||
Generated
+106
-4
@@ -40,6 +40,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767039857,
|
||||||
|
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761640442,
|
"lastModified": 1761640442,
|
||||||
"narHash": "sha256-AtrEP6Jmdvrqiv4x2xa5mrtaIp3OEe8uBYCDZDS+hu8=",
|
"narHash": "sha256-AtrEP6Jmdvrqiv4x2xa5mrtaIp3OEe8uBYCDZDS+hu8=",
|
||||||
@@ -54,7 +70,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat_2": {
|
"flake-compat_3": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767039857,
|
"lastModified": 1767039857,
|
||||||
@@ -90,6 +106,49 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"git-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1778507602,
|
||||||
|
"narHash": "sha256-kTwur1wV+01SdqskVMSo6JMEpg71ps3HpbFY2GsflKs=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"rev": "61ab0e80d9c7ab14c256b5b453d8b3fb0189ba0a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"git-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709087332,
|
||||||
|
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -150,9 +209,29 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix-index-database": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1780816331,
|
||||||
|
"narHash": "sha256-0BYqs8yKWkOz2Q7+SP18N5E5gmDKSo6LSxIVIa0wWes=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-index-database",
|
||||||
|
"rev": "1a2ea89c917781e88508d9fd2b507f2d2a0e173c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-index-database",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixos-apple-silicon": {
|
"nixos-apple-silicon": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat_2",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
@@ -173,7 +252,7 @@
|
|||||||
},
|
},
|
||||||
"nixos-wsl": {
|
"nixos-wsl": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat_2",
|
"flake-compat": "flake-compat_3",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
@@ -228,13 +307,36 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"firefox-addons": "firefox-addons",
|
"firefox-addons": "firefox-addons",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
|
"git-hooks": "git-hooks",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"nix-darwin": "nix-darwin",
|
"nix-darwin": "nix-darwin",
|
||||||
"nix-homebrew": "nix-homebrew",
|
"nix-homebrew": "nix-homebrew",
|
||||||
|
"nix-index-database": "nix-index-database",
|
||||||
"nixos-apple-silicon": "nixos-apple-silicon",
|
"nixos-apple-silicon": "nixos-apple-silicon",
|
||||||
"nixos-wsl": "nixos-wsl",
|
"nixos-wsl": "nixos-wsl",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"nixpkgs-unstable": "nixpkgs-unstable"
|
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1780220602,
|
||||||
|
"narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "db947814a175b7ca6ded66e21383d938df01c227",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -28,6 +28,24 @@
|
|||||||
url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
|
url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
# Prebuilt nix-index database so "command not found -> which package
|
||||||
|
# provides it" works immediately (no manual `nix-index` run). See shell.nix.
|
||||||
|
nix-index-database = {
|
||||||
|
url = "github:nix-community/nix-index-database";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
# treefmt-nix: one multi-language formatter driving `nix fmt` and the
|
||||||
|
# formatting flake check (nixfmt + shfmt + prettier).
|
||||||
|
treefmt-nix = {
|
||||||
|
url = "github:numtide/treefmt-nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
# git-hooks.nix: declarative pre-commit hooks (nixfmt/deadnix/statix),
|
||||||
|
# installed into the repo via the devShell.
|
||||||
|
git-hooks = {
|
||||||
|
url = "github:cachix/git-hooks.nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
@@ -47,12 +65,14 @@
|
|||||||
let
|
let
|
||||||
# claude-code tracks nixpkgs-unstable regardless of the pinned nixpkgs.
|
# claude-code tracks nixpkgs-unstable regardless of the pinned nixpkgs.
|
||||||
overlays = [
|
overlays = [
|
||||||
(final: prev: {
|
(_final: prev: {
|
||||||
claude-code =
|
inherit
|
||||||
(import nixpkgs-unstable {
|
(import nixpkgs-unstable {
|
||||||
inherit (prev.stdenv.hostPlatform) system;
|
inherit (prev.stdenv.hostPlatform) system;
|
||||||
config.allowUnfree = true;
|
config.allowUnfree = true;
|
||||||
}).claude-code;
|
})
|
||||||
|
claude-code
|
||||||
|
;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -239,7 +259,7 @@
|
|||||||
];
|
];
|
||||||
homeModules = [
|
homeModules = [
|
||||||
./lyrathorpe/home
|
./lyrathorpe/home
|
||||||
./system/modules/work/default.nix
|
./lyrathorpe/home/work.nix
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -262,6 +282,13 @@
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
# flake-parts modules: treefmt-nix wires `nix fmt` + a formatting check;
|
||||||
|
# git-hooks.nix wires the pre-commit check + devShell installation script.
|
||||||
|
imports = [
|
||||||
|
inputs.treefmt-nix.flakeModule
|
||||||
|
inputs.git-hooks.flakeModule
|
||||||
|
];
|
||||||
|
|
||||||
systems = [
|
systems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
"aarch64-linux"
|
"aarch64-linux"
|
||||||
@@ -273,26 +300,68 @@
|
|||||||
# nixpkgs instance for that system. Outputs here become per-system
|
# nixpkgs instance for that system. Outputs here become per-system
|
||||||
# attrsets automatically (e.g. devShells.<system>.default).
|
# attrsets automatically (e.g. devShells.<system>.default).
|
||||||
perSystem =
|
perSystem =
|
||||||
{ pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{
|
{
|
||||||
# `nix fmt` formatter for the repo.
|
# treefmt drives `nix fmt` and the formatting check below. nixfmt
|
||||||
formatter = pkgs.nixfmt;
|
# stays the .nix formatter (the tree is already nixfmt-formatted);
|
||||||
|
# shfmt covers shell and prettier covers markdown/yaml/json.
|
||||||
|
treefmt = {
|
||||||
|
projectRootFile = "flake.nix";
|
||||||
|
programs.nixfmt.enable = true;
|
||||||
|
programs.shfmt.enable = true;
|
||||||
|
programs.prettier.enable = true;
|
||||||
|
# Generated hardware-configuration.nix files are not hand-edited.
|
||||||
|
settings.global.excludes = [
|
||||||
|
"*/hardware-configuration.nix" # generated by nixos-generate-config
|
||||||
|
"flake.lock" # generated by `nix flake lock`
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Pre-commit hooks: format + lint gate run on commit. The same hooks
|
||||||
|
# are exposed as a flake check (pre-commit.check.enable defaults true).
|
||||||
|
pre-commit.settings = {
|
||||||
|
# Generated by nixos-generate-config; don't lint/reformat (treefmt
|
||||||
|
# excludes them too).
|
||||||
|
excludes = [ "hardware-configuration\\.nix$" ];
|
||||||
|
hooks = {
|
||||||
|
nixfmt-rfc-style.enable = true;
|
||||||
|
deadnix = {
|
||||||
|
enable = true;
|
||||||
|
# Unused module args ({config,lib,pkgs,...}) are normal; only
|
||||||
|
# flag genuinely dead bindings.
|
||||||
|
settings.noLambdaPatternNames = true;
|
||||||
|
};
|
||||||
|
statix.enable = true; # reads statix.toml (repeated_keys/empty_pattern disabled)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# treefmt-nix exposes its own `checks.treefmt`; alias it to
|
||||||
|
# `formatting` so the existing CI gate (.#checks.*.formatting) keeps
|
||||||
|
# working without churn.
|
||||||
|
checks.formatting = config.treefmt.build.check inputs.self;
|
||||||
|
|
||||||
|
# deadnix / statix lints as standalone flake checks so `nix flake
|
||||||
|
# check` flags dead code and antipatterns independently of pre-commit.
|
||||||
|
checks.deadnix = pkgs.runCommandLocal "check-deadnix" { nativeBuildInputs = [ pkgs.deadnix ]; } ''
|
||||||
|
deadnix --fail --no-lambda-pattern-names ${./.} && touch $out
|
||||||
|
'';
|
||||||
|
checks.statix = pkgs.runCommandLocal "check-statix" { nativeBuildInputs = [ pkgs.statix ]; } ''
|
||||||
|
statix check -c ${./.} ${./.} && touch $out
|
||||||
|
'';
|
||||||
|
|
||||||
# `nix develop` shell with the tooling needed to hack on this flake.
|
# `nix develop` shell with the tooling needed to hack on this flake.
|
||||||
|
# shellHook installs the git pre-commit hooks into the working tree.
|
||||||
devShells.default = pkgs.mkShellNoCC {
|
devShells.default = pkgs.mkShellNoCC {
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
nixfmt
|
nixfmt
|
||||||
nil
|
nil
|
||||||
git
|
git
|
||||||
|
deadnix
|
||||||
|
statix
|
||||||
|
treefmt
|
||||||
];
|
];
|
||||||
|
shellHook = config.pre-commit.installationScript;
|
||||||
};
|
};
|
||||||
|
|
||||||
checks.formatting =
|
|
||||||
pkgs.runCommandLocal "check-formatting" { nativeBuildInputs = [ pkgs.nixfmt ]; }
|
|
||||||
''
|
|
||||||
# Generated hardware-configuration.nix files are excluded.
|
|
||||||
nixfmt --check $(find ${./.} -name '*.nix' -not -name 'hardware-configuration.nix') && touch $out
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Realise the host tables: each entry becomes a {nixos,darwin}Configuration.
|
# Realise the host tables: each entry becomes a {nixos,darwin}Configuration.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Everything here is managed declaratively through Nix — edit the listed file an
|
|||||||
rebuild, never the generated dotfiles.
|
rebuild, never the generated dotfiles.
|
||||||
|
|
||||||
| Area | Defined in |
|
| Area | Defined in |
|
||||||
| --- | --- |
|
| ----------------- | --------------------------------------------------------------------------------------------------------------------- |
|
||||||
| Sway (compositor) | [`sway.nix`](./sway.nix) `config.keybindings` + `config.modes`, plus the home-manager Sway module's built-in defaults |
|
| Sway (compositor) | [`sway.nix`](./sway.nix) `config.keybindings` + `config.modes`, plus the home-manager Sway module's built-in defaults |
|
||||||
| tmux | [`shell.nix`](./shell.nix) `programs.tmux` |
|
| tmux | [`shell.nix`](./shell.nix) `programs.tmux` |
|
||||||
| zsh line editor | [`shell.nix`](./shell.nix) `programs.zsh.historySubstringSearch` |
|
| zsh line editor | [`shell.nix`](./shell.nix) `programs.zsh.historySubstringSearch` |
|
||||||
@@ -27,7 +27,7 @@ rebuild, never the generated dotfiles.
|
|||||||
### Applications & session
|
### Applications & session
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ------------------- | ------------------------------------------------------- |
|
||||||
| `Super`+`Return` | Open a terminal (foot) |
|
| `Super`+`Return` | Open a terminal (foot) |
|
||||||
| `Super`+`Space` | App launcher (sway-launcher-desktop in a floating foot) |
|
| `Super`+`Space` | App launcher (sway-launcher-desktop in a floating foot) |
|
||||||
| `Super`+`d` | App launcher (same as above; module default) |
|
| `Super`+`d` | App launcher (same as above; module default) |
|
||||||
@@ -41,7 +41,7 @@ rebuild, never the generated dotfiles.
|
|||||||
### Focus
|
### Focus
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ----------------------- | ---------------------------------------- |
|
||||||
| `Super`+`←`/`↓`/`↑`/`→` | Move focus by direction |
|
| `Super`+`←`/`↓`/`↑`/`→` | Move focus by direction |
|
||||||
| `Super`+`h`/`j`/`k` | Move focus left / down / up (vim-style) |
|
| `Super`+`h`/`j`/`k` | Move focus left / down / up (vim-style) |
|
||||||
| `Super`+`a` | Focus the parent container |
|
| `Super`+`a` | Focus the parent container |
|
||||||
@@ -53,7 +53,7 @@ rebuild, never the generated dotfiles.
|
|||||||
### Moving windows
|
### Moving windows
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ------------------------------- | ---------------------------------------- |
|
||||||
| `Super`+`Shift`+`←`/`↓`/`↑`/`→` | Move the window by direction |
|
| `Super`+`Shift`+`←`/`↓`/`↑`/`→` | Move the window by direction |
|
||||||
| `Super`+`Shift`+`h`/`j`/`k`/`l` | Move the window left / down / up / right |
|
| `Super`+`Shift`+`h`/`j`/`k`/`l` | Move the window left / down / up / right |
|
||||||
| `Super`+`Shift`+`Space` | Toggle the window floating |
|
| `Super`+`Shift`+`Space` | Toggle the window floating |
|
||||||
@@ -63,7 +63,7 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
|
|||||||
### Layout
|
### Layout
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ----------- | -------------------------------------------------------------------------------------- |
|
||||||
| `Super`+`b` | Split horizontally |
|
| `Super`+`b` | Split horizontally |
|
||||||
| `Super`+`v` | Split vertically |
|
| `Super`+`v` | Split vertically |
|
||||||
| `Super`+`s` | Stacking layout |
|
| `Super`+`s` | Stacking layout |
|
||||||
@@ -77,7 +77,7 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
|
|||||||
### Workspaces
|
### Workspaces
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ----------------------- | --------------------------------- |
|
||||||
| `Super`+`1`…`0` | Switch to workspace 1…10 |
|
| `Super`+`1`…`0` | Switch to workspace 1…10 |
|
||||||
| `Super`+`Shift`+`1`…`0` | Move the window to workspace 1…10 |
|
| `Super`+`Shift`+`1`…`0` | Move the window to workspace 1…10 |
|
||||||
| `Super`+`z` | Previous workspace |
|
| `Super`+`z` | Previous workspace |
|
||||||
@@ -86,14 +86,14 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
|
|||||||
### Scratchpad
|
### Scratchpad
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ------------------- | --------------------------------- |
|
||||||
| `Super`+`Shift`+`-` | Move the window to the scratchpad |
|
| `Super`+`Shift`+`-` | Move the window to the scratchpad |
|
||||||
| `Super`+`-` | Show / cycle the scratchpad |
|
| `Super`+`-` | Show / cycle the scratchpad |
|
||||||
|
|
||||||
### Modes (submenus)
|
### Modes (submenus)
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ------------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||||
| `Super`+`r` | **Resize mode**: arrow keys resize; `Return`/`Esc` exit |
|
| `Super`+`r` | **Resize mode**: arrow keys resize; `Return`/`Esc` exit |
|
||||||
| `Super`+`y` | **Layout mode** (see Layout above) |
|
| `Super`+`y` | **Layout mode** (see Layout above) |
|
||||||
| `Super`+`Shift`+`x` | **Power menu**: `l` lock · `e` log out · `s` sleep · `r` reboot · `Shift`+`s` shutdown · `Return`/`Esc` exit |
|
| `Super`+`Shift`+`x` | **Power menu**: `l` lock · `e` log out · `s` sleep · `r` reboot · `Shift`+`s` shutdown · `Return`/`Esc` exit |
|
||||||
@@ -101,14 +101,14 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
|
|||||||
### Screenshots
|
### Screenshots
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| --------------- | ---------------------------------------- |
|
||||||
| `Print` | Select a region → swappy (annotate/save) |
|
| `Print` | Select a region → swappy (annotate/save) |
|
||||||
| `Shift`+`Print` | Focused window → swappy |
|
| `Shift`+`Print` | Focused window → swappy |
|
||||||
|
|
||||||
### Audio & media
|
### Audio & media
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ----------------------------------------------- | ---------------------- |
|
||||||
| `XF86AudioRaiseVolume` / `XF86AudioLowerVolume` | Volume ±5% (wpctl) |
|
| `XF86AudioRaiseVolume` / `XF86AudioLowerVolume` | Volume ±5% (wpctl) |
|
||||||
| `XF86AudioMute` | Toggle output mute |
|
| `XF86AudioMute` | Toggle output mute |
|
||||||
| `XF86AudioMicMute` | Toggle microphone mute |
|
| `XF86AudioMicMute` | Toggle microphone mute |
|
||||||
@@ -118,7 +118,7 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
|
|||||||
### Brightness — laptops only
|
### Brightness — laptops only
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| ----------------------------------------------- | ----------------------------- |
|
||||||
| `XF86MonBrightnessUp` / `XF86MonBrightnessDown` | Backlight ±5% (brightnessctl) |
|
| `XF86MonBrightnessUp` / `XF86MonBrightnessDown` | Backlight ±5% (brightnessctl) |
|
||||||
|
|
||||||
Present only on portable hosts (T400, MBP); desktops have no internal backlight.
|
Present only on portable hosts (T400, MBP); desktops have no internal backlight.
|
||||||
@@ -130,19 +130,24 @@ Present only on portable hosts (T400, MBP); desktops have no internal backlight.
|
|||||||
Prefix is **`Ctrl`+`b`** (default). Copy mode uses **vi** keys.
|
Prefix is **`Ctrl`+`b`** (default). Copy mode uses **vi** keys.
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| --------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||||
| `Ctrl`+`b` then `v` | Split into left/right panes |
|
| `Ctrl`+`b` then `v` | Split into left/right panes |
|
||||||
| `Ctrl`+`b` then `s` | Split into top/bottom panes |
|
| `Ctrl`+`b` then `s` | Split into top/bottom panes |
|
||||||
|
| `Ctrl`+`h`/`j`/`k`/`l` | Move between panes — and into/out of vim splits — seamlessly (vim-tmux-navigator, no prefix) |
|
||||||
| `Alt`+`←`/`→`/`↑`/`↓` | Switch pane by direction (no prefix needed) |
|
| `Alt`+`←`/`→`/`↑`/`↓` | Switch pane by direction (no prefix needed) |
|
||||||
| `Ctrl`+`b` then `[` | Enter copy mode (then vi motions; `Space`/`Enter` to select/copy) |
|
| `Ctrl`+`b` then `[` | Enter copy mode (then vi motions; `Space`/`Enter` to select/copy) |
|
||||||
| `Ctrl`+`b` then `z` | Zoom / unzoom the focused pane |
|
| `Ctrl`+`b` then `z` | Zoom / unzoom the focused pane |
|
||||||
| `Ctrl`+`b` then `c` | New window |
|
| `Ctrl`+`b` then `c` | New window |
|
||||||
| `Ctrl`+`b` then `n` / `p` | Next / previous window |
|
| `Ctrl`+`b` then `n` / `p` | Next / previous window |
|
||||||
| `Ctrl`+`b` then `d` | Detach |
|
| `Ctrl`+`b` then `d` | Detach |
|
||||||
|
| `Ctrl`+`b` then `Ctrl`+`s` / `Ctrl`+`r` | Save / restore the session (resurrect; continuum also auto-saves and restores on start) |
|
||||||
| Mouse | Enabled — click to focus, drag borders, scroll, select |
|
| Mouse | Enabled — click to focus, drag borders, scroll, select |
|
||||||
|
|
||||||
> The stock split keys `%` and `"` are unbound; use `v` / `s` above. `Ctrl`+`b`
|
> The stock split keys `%` and `"` are unbound; use `v` / `s` above. `Ctrl`+`b`
|
||||||
> then `s` is therefore a split, not the session tree.
|
> then `s` is therefore a split, not the session tree.
|
||||||
|
>
|
||||||
|
> Sessions persist across reboots (resurrect + continuum). Terminals auto-start
|
||||||
|
> tmux; `NO_TMUX=1 <terminal>` opens a bare shell instead.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -151,7 +156,7 @@ Prefix is **`Ctrl`+`b`** (default). Copy mode uses **vi** keys.
|
|||||||
Only colours are themed; these are foot's default key bindings.
|
Only colours are themed; these are foot's default key bindings.
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| --------------------------------------- | ----------------------------- |
|
||||||
| `Ctrl`+`Shift`+`c` / `Ctrl`+`Shift`+`v` | Copy / paste (clipboard) |
|
| `Ctrl`+`Shift`+`c` / `Ctrl`+`Shift`+`v` | Copy / paste (clipboard) |
|
||||||
| `Shift`+`Insert` | Paste primary selection |
|
| `Shift`+`Insert` | Paste primary selection |
|
||||||
| `Ctrl`+`Shift`+`r` | Search scrollback |
|
| `Ctrl`+`Shift`+`r` | Search scrollback |
|
||||||
@@ -165,7 +170,7 @@ Only colours are themed; these are foot's default key bindings.
|
|||||||
## zsh
|
## zsh
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| --------- | -------------------------------------------------------------------------------------------------- |
|
||||||
| `↑` / `↓` | History **substring** search — type a fragment first, then the arrows cycle matching past commands |
|
| `↑` / `↓` | History **substring** search — type a fragment first, then the arrows cycle matching past commands |
|
||||||
|
|
||||||
Bound for both CSI and SS3 cursor sequences, so it works in foot, iTerm2 and
|
Bound for both CSI and SS3 cursor sequences, so it works in foot, iTerm2 and
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
# Interactive shell environment
|
||||||
|
|
||||||
|
Everything the shell, terminal multiplexer, git and ssh do beyond their defaults,
|
||||||
|
and where each is defined. All of it is managed declaratively through
|
||||||
|
home-manager — edit the listed file and rebuild, never the generated dotfiles.
|
||||||
|
|
||||||
|
Keyboard shortcuts have their own reference: [`KEYBINDINGS.md`](./KEYBINDINGS.md).
|
||||||
|
|
||||||
|
| Area | Defined in |
|
||||||
|
| ------------------------------------- | ----------------------------------------------------- |
|
||||||
|
| zsh, CLI tools, tmux, ssh, auto-tmux | [`shell.nix`](./shell.nix) |
|
||||||
|
| git (+ delta, commitizen) | [`git.nix`](./git.nix) |
|
||||||
|
| vim | [`editor.nix`](./editor.nix) |
|
||||||
|
| GUI apps, GTK/Firefox theming, cursor | [`desktop.nix`](./desktop.nix) (graphical hosts only) |
|
||||||
|
|
||||||
|
Shared by every host via [`default.nix`](./default.nix); the work box also layers
|
||||||
|
[`../../system/modules/work/default.nix`](../../system/modules/work/default.nix)
|
||||||
|
on top (work email, its own ssh config, extra packages).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## zsh
|
||||||
|
|
||||||
|
| Feature | Notes |
|
||||||
|
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| oh-my-zsh | plugins `git`, `man`, `sudo` (Esc-Esc to prepend sudo), `colored-man-pages`, `extract`; theme `robbyrussell` |
|
||||||
|
| Autosuggestion | fish-style history suggestions as you type (→ to accept) |
|
||||||
|
| Syntax highlighting | commands coloured by validity as you type |
|
||||||
|
| Completion | menu completion; the dump is rebuilt on every activation (see Maintenance) |
|
||||||
|
| History | 100k in-memory/on-disk, deduped, space-prefixed commands ignored, timestamped, **shared live across sessions** |
|
||||||
|
| History substring search | type a fragment, then ↑/↓ cycles matching past commands — works in foot, iTerm2 and the Linux TTY (both CSI and SS3 arrow encodings bound) |
|
||||||
|
| Prompt | hostname is prefixed when over SSH |
|
||||||
|
|
||||||
|
**Aliases:** `ls`/`ll`/`la`/`lt` → `eza` (icons + git), `cls` → `clear`. git aliases live in git.nix (below).
|
||||||
|
|
||||||
|
## CLI tools
|
||||||
|
|
||||||
|
| Tool | What it gives you |
|
||||||
|
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `fzf` | `Ctrl-R` fuzzy history, `Ctrl-T` file picker, `Alt-C` fuzzy cd (Catppuccin-themed) |
|
||||||
|
| `zoxide` | `z <fragment>` jumps to frecent directories |
|
||||||
|
| `direnv` + `nix-direnv` | per-project environments auto-loaded on `cd` (cached Nix dev shells) |
|
||||||
|
| `eza` | modern `ls` (drives the ls aliases) |
|
||||||
|
| `bat` | syntax-highlighting pager (Catppuccin Mocha theme); behaves like `cat` when piped; also the `MANPAGER` |
|
||||||
|
| `ripgrep` / `fd` | fast search (`rg`) and find (`fd`); also back `fzf` |
|
||||||
|
| `jq` / `btop` | JSON processor; resource monitor |
|
||||||
|
| `gh` / `tea` | GitHub and Gitea (`code.emmathe.dev`) CLIs; `gh` uses SSH |
|
||||||
|
| `nix-index` | `command-not-found`: an unknown command tells you which Nix package provides it (prebuilt DB, no manual indexing) |
|
||||||
|
| `comma` (`,`) | run an uninstalled program once: `, cowsay hi` |
|
||||||
|
| `nh` | nicer `nixos-rebuild`/`home-manager` with diffs; `$NH_FLAKE` set to the repo. No scheduled GC (it could reap paths a running generation still references) — collect garbage manually with `nh clean all` / `nix-collect-garbage -d` |
|
||||||
|
|
||||||
|
**Theming:** `fzf`, `bat` and `git`'s `delta` pager are all Catppuccin Mocha,
|
||||||
|
driven from the shared `../catppuccin-mocha.nix` palette / the catppuccin/bat
|
||||||
|
theme.
|
||||||
|
|
||||||
|
**Env & defaults:** `xdg.enable` on; `PAGER`/`MANPAGER` (bat)/`VISUAL` set in
|
||||||
|
`default.nix`; `xdg.mimeApps` maps web→Firefox, directories→nemo (`desktop.nix`).
|
||||||
|
|
||||||
|
## tmux
|
||||||
|
|
||||||
|
**Auto-start:** opening any interactive terminal — foot, iTerm2, the WSL shell, the
|
||||||
|
Linux console — drops you straight into a tmux session named `main` (attach if it
|
||||||
|
exists, else create). Panes run a plain non-login zsh. It deliberately does **not**
|
||||||
|
fire for SSH sessions, VS Code's integrated terminal, already-inside-tmux, or
|
||||||
|
non-interactive shells. Escape hatch: `NO_TMUX=1 <terminal>` opens a bare shell.
|
||||||
|
|
||||||
|
| Setting | Value |
|
||||||
|
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| Mode keys | vi |
|
||||||
|
| Mouse | on |
|
||||||
|
| Scrollback | 500000 lines |
|
||||||
|
| `escape-time` | 10ms (the 500ms default lagged vim's ESC) |
|
||||||
|
| `focus-events` | on (vim autoread) |
|
||||||
|
| `base-index` / `pane-base-index` | 1 |
|
||||||
|
| Splits | `prefix s` vertical, `prefix v` horizontal (stock `%`/`"` unbound) |
|
||||||
|
| Pane nav | `Alt`+arrows (no prefix) |
|
||||||
|
| Terminal | `default-terminal tmux-256color`; truecolor advertised per outer terminal (`foot*`, `xterm-256color`/iTerm2) via `terminal-features … RGB` |
|
||||||
|
| Clipboard | `set-clipboard on`; foot `terminal-features` advertise truecolor/sync/OSC52/title/cursor |
|
||||||
|
|
||||||
|
**Plugins:** `sensible`, `vim-tmux-navigator` (Ctrl-h/j/k/l across vim ↔ tmux),
|
||||||
|
`yank`, `catppuccin` (Mocha statusline), `resurrect` + `continuum`
|
||||||
|
(sessions auto-save and restore across reboots). The statusline draws Nerd-Font
|
||||||
|
glyphs — see Fonts.
|
||||||
|
|
||||||
|
## Fonts
|
||||||
|
|
||||||
|
**JetBrainsMono Nerd Font** is installed on every host (in `common-nixos.nix`,
|
||||||
|
because tmux runs everywhere; the Mac installs it to `/Library/Fonts` via the
|
||||||
|
Darwin config). foot uses it as its main font automatically. iTerm2's font is a
|
||||||
|
GUI setting — set it to _JetBrainsMono Nerd Font_ (Settings → Profiles → Text →
|
||||||
|
Font) so the tmux statusline glyphs render instead of `?`.
|
||||||
|
|
||||||
|
## git
|
||||||
|
|
||||||
|
Pager is **delta**. **commitizen** is installed on every host; `cz` defaults to
|
||||||
|
Conventional Commits.
|
||||||
|
|
||||||
|
| Aliases | |
|
||||||
|
| ------------------------ | ----------------------------------------------------------------- |
|
||||||
|
| `st` `co` `sw` `br` `ci` | status / checkout / switch / branch / commit |
|
||||||
|
| `last` `unstage` | last commit / unstage |
|
||||||
|
| `lg` | graph log, all branches |
|
||||||
|
| `cz` `cc` | `git cz <sub>` (e.g. `git cz c`) and `git cc` → commitizen prompt |
|
||||||
|
|
||||||
|
| Behaviour | |
|
||||||
|
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| Pulls | rebase, with autostash + autosquash |
|
||||||
|
| Fetch | prune deleted remote branches |
|
||||||
|
| Conflicts | `zdiff3` (shows the common ancestor) |
|
||||||
|
| Diffs | histogram algorithm, colour-moved |
|
||||||
|
| `rerere` | remembers + replays conflict resolutions |
|
||||||
|
| Commit editor | full diff shown (`commit.verbose`) |
|
||||||
|
| Misc | branches sorted by date, `column.ui = auto`, `help.autocorrect = prompt`, `push.autoSetupRemote` |
|
||||||
|
| Global ignores | `result`, `result-*`, `.direnv`, `*.swp`, `.DS_Store` |
|
||||||
|
| Signing | SSH commit + tag signing (`mkDefault`, so a host without the key in its agent can disable it). Personal email `iam@emmathe.dev`; the work box overrides email + signing. |
|
||||||
|
|
||||||
|
## ssh
|
||||||
|
|
||||||
|
| Feature | Notes |
|
||||||
|
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| ssh-agent | runs on Linux (launchd on macOS); keys added on **first use** so the passphrase is typed once per login session — this also feeds git commit signing |
|
||||||
|
| macOS | `UseKeychain` caches the passphrase in the login keychain (guarded by `IgnoreUnknown`, so a non-Apple `ssh` skips it instead of erroring) |
|
||||||
|
| Gitea remote | `code.emmathe.dev` → `HostName 10.187.1.76` (DNS-override), `Port 30009`, user `git`, dedicated key, `identitiesOnly` |
|
||||||
|
| Defaults | the module's deprecated default block is opted out; equivalents kept under `settings."*"` |
|
||||||
|
|
||||||
|
The **work box keeps its own `~/.ssh/config`** (home-manager's `programs.ssh` is
|
||||||
|
forced off there) but still runs the agent.
|
||||||
|
|
||||||
|
## Maintenance behaviours
|
||||||
|
|
||||||
|
- **zcompdump reset** — `~/.zcompdump*` is removed on every activation, so a stale
|
||||||
|
dump (pointing at `/nix/store` paths a rebuild or a manual GC removed) can't
|
||||||
|
break completion with `_git: function definition file not found`.
|
||||||
|
- **GC** — no scheduled timer; collect garbage deliberately (`nh clean all` /
|
||||||
|
`nix-collect-garbage -d`) when no important session is running.
|
||||||
|
|
||||||
|
## Per-host differences
|
||||||
|
|
||||||
|
| | Personal Linux (sway) | macOS | Work WSL (EDaaS) |
|
||||||
|
| --------------------------- | --------------------- | ----------------- | --------------------------- |
|
||||||
|
| Auto-tmux | yes (foot/TTY) | yes (iTerm2) | yes (WSL shell) |
|
||||||
|
| git email | `iam@emmathe.dev` | `iam@emmathe.dev` | `…@citrix.com` (work) |
|
||||||
|
| ssh config managed | yes | yes | no (keeps corporate config) |
|
||||||
|
| ssh-agent | yes | launchd | yes (work module) |
|
||||||
|
| GUI / theming (desktop.nix) | yes | no | no |
|
||||||
@@ -9,5 +9,26 @@
|
|||||||
./editor.nix
|
./editor.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Manage the XDG base-directory layout and ~/.config files. Tools above
|
||||||
|
# (bat themes, gh config, ...) write under xdg.configHome; enabling this
|
||||||
|
# makes the paths explicit and consistent across hosts. No regression: the
|
||||||
|
# defaults match the conventional ~/.config, ~/.cache, ~/.local/share.
|
||||||
|
xdg.enable = true;
|
||||||
|
|
||||||
|
# Editor itself comes from vim.defaultEditor (sets $EDITOR). Round out the
|
||||||
|
# rest of the standard env. desktop.nix adds its own Wayland session vars;
|
||||||
|
# home-manager merges the two attrsets, so these do not clash.
|
||||||
|
home.sessionVariables = {
|
||||||
|
VISUAL = "vim";
|
||||||
|
PAGER = "less -FRX"; # -F quit-if-one-screen, -R raw colour, -X no clear
|
||||||
|
# Render man pages through bat (themed): col strips backspace overstrike,
|
||||||
|
# bat -l man -p highlights without its own pager decorations.
|
||||||
|
MANPAGER = "sh -c 'col -bx | bat -l man -p'";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Pinned to the release first installed on these hosts, NOT the current
|
||||||
|
# nixpkgs (26.05). stateVersion freezes stateful defaults (file locations,
|
||||||
|
# service data formats) to that release; bumping it silently migrates that
|
||||||
|
# state and can break it. Leave it -- it is intentional, not stale.
|
||||||
home.stateVersion = "25.05";
|
home.stateVersion = "25.05";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,30 @@
|
|||||||
XDG_CURRENT_DESKTOP = "sway";
|
XDG_CURRENT_DESKTOP = "sway";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Default apps for the desktop (writes ~/.config/mimeapps.list). Firefox owns
|
||||||
|
# the web; nemo owns directories/file URIs; images, PDFs and plain text open
|
||||||
|
# in Firefox too -- no dedicated GUI viewer/editor is installed and vim is
|
||||||
|
# terminal-only (no usable GUI .desktop for double-click handoff). Kept
|
||||||
|
# minimal -- only the handlers actually present on these hosts.
|
||||||
|
xdg.mimeApps = {
|
||||||
|
enable = true;
|
||||||
|
defaultApplications = {
|
||||||
|
"text/html" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/http" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/https" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/about" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/unknown" = "firefox.desktop";
|
||||||
|
"inode/directory" = "nemo.desktop";
|
||||||
|
"image/png" = "firefox.desktop";
|
||||||
|
"image/jpeg" = "firefox.desktop";
|
||||||
|
"image/gif" = "firefox.desktop";
|
||||||
|
"image/webp" = "firefox.desktop";
|
||||||
|
"image/svg+xml" = "firefox.desktop";
|
||||||
|
"application/pdf" = "firefox.desktop";
|
||||||
|
"text/plain" = "firefox.desktop";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# Theme GTK apps (nemo, etc.) to match the Catppuccin Mocha desktop. Under
|
# Theme GTK apps (nemo, etc.) to match the Catppuccin Mocha desktop. Under
|
||||||
# Sway there is no XSettings daemon, so GTK reads these from the generated
|
# Sway there is no XSettings daemon, so GTK reads these from the generated
|
||||||
# ~/.config/gtk-{3,4}.0/settings.ini directly. The Mocha theme is dark by
|
# ~/.config/gtk-{3,4}.0/settings.ini directly. The Mocha theme is dark by
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
vim-fugitive
|
vim-fugitive
|
||||||
vim-indent-guides
|
vim-indent-guides
|
||||||
catppuccin-vim
|
catppuccin-vim
|
||||||
|
vim-tmux-navigator # Ctrl-h/j/k/l moves between vim splits and tmux panes
|
||||||
];
|
];
|
||||||
settings = {
|
settings = {
|
||||||
expandtab = false;
|
expandtab = false;
|
||||||
|
|||||||
+73
-5
@@ -1,6 +1,11 @@
|
|||||||
# Version control: git + delta pager + commitizen. The work host layers
|
# Version control: git + delta pager + commitizen. The work host layers
|
||||||
# commit signing and an email override on top (see work/default.nix).
|
# commit signing and an email override on top (see work/default.nix).
|
||||||
{ pkgs, fullName, ... }:
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
fullName,
|
||||||
|
...
|
||||||
|
}:
|
||||||
{
|
{
|
||||||
home.packages = [
|
home.packages = [
|
||||||
pkgs.commitizen
|
pkgs.commitizen
|
||||||
@@ -11,13 +16,76 @@
|
|||||||
package = pkgs.gitFull;
|
package = pkgs.gitFull;
|
||||||
settings = {
|
settings = {
|
||||||
user.name = fullName;
|
user.name = fullName;
|
||||||
push = {
|
# Personal identity. mkDefault so the work module overrides it on the work
|
||||||
autoSetupRemote = true;
|
# host (and to merge cleanly with that plain definition there).
|
||||||
|
user.email = lib.mkDefault "iam@emmathe.dev";
|
||||||
|
push.autoSetupRemote = true;
|
||||||
|
init.defaultBranch = "main";
|
||||||
|
|
||||||
|
# Rebase-centric pulls (matches the "always a branch, linear history"
|
||||||
|
# workflow); stash/restore and reorder fixups automatically.
|
||||||
|
pull.rebase = true;
|
||||||
|
rebase = {
|
||||||
|
autoStash = true;
|
||||||
|
autoSquash = true;
|
||||||
};
|
};
|
||||||
init = {
|
|
||||||
defaultBranch = "main";
|
fetch.prune = true; # drop deleted remote-tracking branches
|
||||||
|
merge.conflictStyle = "zdiff3"; # show the common ancestor in conflicts
|
||||||
|
diff = {
|
||||||
|
algorithm = "histogram";
|
||||||
|
colorMoved = "default";
|
||||||
};
|
};
|
||||||
|
rerere.enabled = true; # remember + replay conflict resolutions
|
||||||
|
|
||||||
|
# delta pager config (programs.delta is enabled below, with git
|
||||||
|
# integration; these keys land under [delta] in the git config).
|
||||||
|
# syntax-theme reuses the Catppuccin Mocha tmTheme vendored for bat in
|
||||||
|
# shell.nix -- delta reads bat's theme directory.
|
||||||
|
delta = {
|
||||||
|
syntax-theme = "Catppuccin Mocha";
|
||||||
|
navigate = true; # n/N to jump between diff hunks
|
||||||
|
line-numbers = true;
|
||||||
|
side-by-side = true;
|
||||||
};
|
};
|
||||||
|
commit.verbose = true; # full diff in the commit-message editor
|
||||||
|
branch.sort = "-committerdate"; # most-recent branches first
|
||||||
|
column.ui = "auto";
|
||||||
|
help.autocorrect = "prompt";
|
||||||
|
|
||||||
|
alias = {
|
||||||
|
st = "status";
|
||||||
|
co = "checkout";
|
||||||
|
sw = "switch";
|
||||||
|
br = "branch";
|
||||||
|
ci = "commit";
|
||||||
|
last = "log -1 HEAD";
|
||||||
|
unstage = "reset HEAD --";
|
||||||
|
lg = "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --all";
|
||||||
|
# commitizen (Conventional Commits, its default ruleset): `git cz c` ->
|
||||||
|
# `cz commit`, `git cz bump`, etc. `git cc` is a shortcut for the prompt.
|
||||||
|
cz = "!cz";
|
||||||
|
cc = "!cz commit";
|
||||||
|
};
|
||||||
|
|
||||||
|
# SSH commit signing on personal hosts too (the work module sets the same
|
||||||
|
# on the work host). mkDefault so a host without the key in its ssh-agent
|
||||||
|
# can override to false -- otherwise commits there would fail. Reuses the
|
||||||
|
# existing ssh key; a dedicated personal key can be swapped in later.
|
||||||
|
gpg.format = "ssh";
|
||||||
|
user.signingkey = "key::ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAJMVgeRKnfX1G8coU3nAobI485aeUpGTMqH7+zbKI8o emma.thorpe@cloud.com";
|
||||||
|
commit.gpgsign = lib.mkDefault true;
|
||||||
|
tag.gpgsign = lib.mkDefault true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Global ignore file (~/.config/git/ignore).
|
||||||
|
ignores = [
|
||||||
|
"result"
|
||||||
|
"result-*"
|
||||||
|
".direnv"
|
||||||
|
"*.swp"
|
||||||
|
".DS_Store"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.delta = {
|
programs.delta = {
|
||||||
|
|||||||
+264
-9
@@ -1,6 +1,31 @@
|
|||||||
# Interactive shell: zsh + tmux. Wanted on every host.
|
# Interactive shell: zsh + tmux. Wanted on every host.
|
||||||
{ lib, ... }:
|
|
||||||
{
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
# Shared Catppuccin Mocha palette: raw 6-hex strings, no leading "#".
|
||||||
|
ctp = import ../catppuccin-mocha.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
# Prebuilt nix-index database -> working command-not-found
|
||||||
|
# ("cmd not found -> which nix package provides it"), no manual indexing.
|
||||||
|
inputs.nix-index-database.homeModules.default
|
||||||
|
];
|
||||||
|
|
||||||
|
# CLI staples wanted on every host (search, parse, monitor). ripgrep/fd also
|
||||||
|
# back fzf and editor integrations; tea is the Gitea CLI for code.emmathe.dev.
|
||||||
|
home.packages = [
|
||||||
|
pkgs.ripgrep
|
||||||
|
pkgs.fd
|
||||||
|
pkgs.jq
|
||||||
|
pkgs.btop
|
||||||
|
pkgs.tea
|
||||||
|
];
|
||||||
|
|
||||||
programs.zsh = {
|
programs.zsh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableCompletion = true;
|
enableCompletion = true;
|
||||||
@@ -21,35 +46,189 @@
|
|||||||
"^[OB"
|
"^[OB"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
history.append = true;
|
history = {
|
||||||
|
append = true; # append, don't overwrite, on shell exit
|
||||||
|
size = 100000; # in-memory (HISTSIZE)
|
||||||
|
save = 100000; # on-disk (SAVEHIST)
|
||||||
|
ignoreDups = true; # drop consecutive duplicates
|
||||||
|
ignoreSpace = true; # leading-space commands stay out of history
|
||||||
|
expireDuplicatesFirst = true;
|
||||||
|
share = true; # live-share history across sessions
|
||||||
|
extended = true; # record timestamps
|
||||||
|
};
|
||||||
oh-my-zsh = {
|
oh-my-zsh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
plugins = [
|
plugins = [
|
||||||
"git"
|
"git"
|
||||||
"man"
|
"man"
|
||||||
|
"sudo" # double-Esc prefixes the last command with sudo
|
||||||
|
"colored-man-pages"
|
||||||
|
"extract" # `extract <archive>` for any format
|
||||||
];
|
];
|
||||||
theme = "robbyrussell";
|
theme = "robbyrussell";
|
||||||
};
|
};
|
||||||
syntaxHighlighting.enable = true;
|
syntaxHighlighting.enable = true;
|
||||||
# Prefix the prompt with the hostname over SSH.
|
initContent = lib.mkMerge [
|
||||||
initContent = lib.mkOrder 1500 ''
|
# Auto-start tmux in every interactive terminal -- foot, iTerm2, the WSL
|
||||||
|
# shell, the Linux console -- so a new terminal lands straight in the
|
||||||
|
# multiplexer (session "main": attach if present, else create). Panes run
|
||||||
|
# a plain non-login zsh (tmux's default-command "${SHELL}"). Order 200
|
||||||
|
# runs before oh-my-zsh/compinit so the exec replaces the shell before
|
||||||
|
# that setup is wasted. Guards, each preventing a real breakage:
|
||||||
|
# interactive only -> don't hijack scp / `ssh host cmd` / scripted shells
|
||||||
|
# $TMUX empty -> a pane's zsh won't re-exec tmux (infinite loop)
|
||||||
|
# not SSH -> don't force inbound SSH logins into a server tmux
|
||||||
|
# not VS Code -> its integrated terminal manages itself
|
||||||
|
# tmux on PATH -> a failed exec would otherwise kill the login shell
|
||||||
|
# $NO_TMUX unset -> escape hatch: `NO_TMUX=1 <term>` opens a bare shell
|
||||||
|
(lib.mkOrder 200 ''
|
||||||
|
if [[ $- == *i* ]] \
|
||||||
|
&& [[ -z "$TMUX" ]] \
|
||||||
|
&& [[ -z "$NO_TMUX" ]] \
|
||||||
|
&& [[ -z "$SSH_CONNECTION" && -z "$SSH_TTY" ]] \
|
||||||
|
&& [[ "$TERM_PROGRAM" != "vscode" ]] \
|
||||||
|
&& command -v tmux >/dev/null 2>&1; then
|
||||||
|
exec tmux new-session -A -s main
|
||||||
|
fi
|
||||||
|
'')
|
||||||
|
# Prefix the prompt with the hostname over SSH (mkAfter).
|
||||||
|
(lib.mkOrder 1500 ''
|
||||||
if [ "$SSH_CLIENT" ] || [ "$SSH_TTY" ]; then
|
if [ "$SSH_CLIENT" ] || [ "$SSH_TTY" ]; then
|
||||||
export PS1="%M $PS1"
|
export PS1="%M $PS1"
|
||||||
fi
|
fi
|
||||||
'';
|
'')
|
||||||
envExtra = ''
|
];
|
||||||
alias cls=clear
|
shellAliases = {
|
||||||
'';
|
# eza's zsh integration also defines these; set explicitly so the
|
||||||
|
# icons/git intent is obvious.
|
||||||
|
ls = "eza --icons --git";
|
||||||
|
ll = "eza --icons --git -l";
|
||||||
|
la = "eza --icons --git -la";
|
||||||
|
lt = "eza --icons --git --tree";
|
||||||
|
cls = "clear";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Fuzzy finder: Ctrl-R fuzzy history, Ctrl-T files, Alt-C cd.
|
||||||
|
programs.fzf = {
|
||||||
|
enable = true;
|
||||||
|
enableZshIntegration = true;
|
||||||
|
# Catppuccin Mocha colours (rendered into FZF_DEFAULT_OPTS --color). Each
|
||||||
|
# value needs a leading "#"; the palette stores raw hex.
|
||||||
|
colors = {
|
||||||
|
"bg" = "#${ctp.base}";
|
||||||
|
"bg+" = "#${ctp.surface1}"; # current line / selected row
|
||||||
|
"fg" = "#${ctp.text}";
|
||||||
|
"fg+" = "#${ctp.text}";
|
||||||
|
"hl" = "#${ctp.blue}"; # match highlights
|
||||||
|
"hl+" = "#${ctp.blue}";
|
||||||
|
"header" = "#${ctp.red}";
|
||||||
|
"info" = "#${ctp.mauve}";
|
||||||
|
"marker" = "#${ctp.green}";
|
||||||
|
"pointer" = "#${ctp.pink}";
|
||||||
|
"prompt" = "#${ctp.mauve}";
|
||||||
|
"spinner" = "#${ctp.pink}";
|
||||||
|
"border" = "#${ctp.surface1}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Frecency directory jumping: `z <fragment>`.
|
||||||
|
programs.zoxide = {
|
||||||
|
enable = true;
|
||||||
|
enableZshIntegration = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Per-project environments auto-loaded on cd, with the Nix dev-shell cache.
|
||||||
|
programs.direnv = {
|
||||||
|
enable = true;
|
||||||
|
nix-direnv.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Modern ls (drives the ls aliases above).
|
||||||
|
programs.eza = {
|
||||||
|
enable = true;
|
||||||
|
git = true;
|
||||||
|
icons = "auto"; # boolean form is deprecated
|
||||||
|
};
|
||||||
|
|
||||||
|
# Syntax-highlighting pager, used as `bat` (acts like cat when piped). bat
|
||||||
|
# ships no Catppuccin theme, so vendor the upstream tmTheme from catppuccin/bat
|
||||||
|
# (delta in git.nix reuses it as its syntax-theme).
|
||||||
|
programs.bat = {
|
||||||
|
enable = true;
|
||||||
|
config.theme = "Catppuccin Mocha";
|
||||||
|
themes."Catppuccin Mocha" = {
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "catppuccin";
|
||||||
|
repo = "bat";
|
||||||
|
rev = "6810349b28055dce54076712fc05fc68da4b8ec0";
|
||||||
|
sha256 = "1y5sfi7jfr97z1g6vm2mzbsw59j1jizwlmbadvmx842m0i5ak5ll";
|
||||||
|
};
|
||||||
|
file = "themes/Catppuccin Mocha.tmTheme";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# command-not-found backed by the prebuilt nix-index DB (module imported
|
||||||
|
# above). `comma` runs an uninstalled program once: `, cowsay hi`.
|
||||||
|
programs.nix-index.enable = true;
|
||||||
|
programs.nix-index-database.comma.enable = true;
|
||||||
|
|
||||||
|
# Nicer nixos-rebuild/home-manager (diffs) + $NH_FLAKE. No automatic clean:
|
||||||
|
# the scheduled GC's only benefit is reclaiming disk, but it can reap store
|
||||||
|
# paths the current generation still references (notably on nix-darwin, where
|
||||||
|
# it broke completion by removing an in-use oh-my-zsh). GC manually instead:
|
||||||
|
# `nh clean all` / `nix-collect-garbage -d` when nothing important is running.
|
||||||
|
programs.nh = {
|
||||||
|
enable = true;
|
||||||
|
flake = "$HOME/code/nixfiles";
|
||||||
|
};
|
||||||
|
|
||||||
|
# GitHub CLI. Prefer SSH for any git operations it drives, matching the
|
||||||
|
# ssh-based remotes used elsewhere.
|
||||||
|
programs.gh = {
|
||||||
|
enable = true;
|
||||||
|
settings.git_protocol = "ssh";
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.tmux = {
|
programs.tmux = {
|
||||||
enable = true;
|
enable = true;
|
||||||
reverseSplit = true;
|
reverseSplit = true;
|
||||||
terminal = "tmux-direct";
|
# tmux-256color (not tmux-direct): the standard inside-tmux terminfo.
|
||||||
|
# tmux-direct's capabilities desync zsh's line redraw on some terminals
|
||||||
|
# (e.g. iTerm2 -> duplicated chars on Tab, stray newlines). Truecolor is
|
||||||
|
# advertised per outer terminal via the RGB terminal-features below.
|
||||||
|
terminal = "tmux-256color";
|
||||||
newSession = true;
|
newSession = true;
|
||||||
keyMode = "vi";
|
keyMode = "vi";
|
||||||
historyLimit = 500000;
|
historyLimit = 500000;
|
||||||
mouse = true;
|
mouse = true;
|
||||||
|
escapeTime = 10; # was the 500ms default -> laggy ESC in vim
|
||||||
|
focusEvents = true; # let vim see focus changes (autoread)
|
||||||
|
baseIndex = 1; # sets both base-index and pane-base-index
|
||||||
|
|
||||||
|
plugins = with pkgs.tmuxPlugins; [
|
||||||
|
sensible
|
||||||
|
vim-tmux-navigator # Ctrl-h/j/k/l across vim splits and tmux panes
|
||||||
|
yank
|
||||||
|
{
|
||||||
|
# Catppuccin Mocha statusline (v2 API: flavour + window options must be
|
||||||
|
# set before the plugin loads, which home-manager does for plugin
|
||||||
|
# extraConfig; the status modules below go in the main extraConfig,
|
||||||
|
# which HM appends after all plugins).
|
||||||
|
plugin = catppuccin;
|
||||||
|
extraConfig = ''
|
||||||
|
set -g @catppuccin_flavor 'mocha'
|
||||||
|
set -g @catppuccin_window_status_style 'rounded'
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
resurrect # save/restore sessions
|
||||||
|
{
|
||||||
|
plugin = continuum; # auto-save + restore on tmux start (after resurrect)
|
||||||
|
extraConfig = ''
|
||||||
|
set -g @continuum-restore 'on'
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
# `reverseSplit = true` already binds s -> vertical and v -> horizontal
|
# `reverseSplit = true` already binds s -> vertical and v -> horizontal
|
||||||
# split (the dotfiles' vim-style splits).
|
# split (the dotfiles' vim-style splits).
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
@@ -66,6 +245,10 @@
|
|||||||
bind -n M-Up select-pane -U
|
bind -n M-Up select-pane -U
|
||||||
bind -n M-Down select-pane -D
|
bind -n M-Down select-pane -D
|
||||||
|
|
||||||
|
# Truecolor for the outer terminals (foot reports xterm-ish too; iTerm2 is
|
||||||
|
# xterm-256color). Without this, with tmux-256color as default-terminal,
|
||||||
|
# 24-bit colour would be quantised to 256.
|
||||||
|
set -as terminal-features ",xterm-256color:RGB"
|
||||||
# Tell tmux which capabilities the foot terminal supports, so truecolor,
|
# Tell tmux which capabilities the foot terminal supports, so truecolor,
|
||||||
# synchronised output, the system clipboard (OSC 52), window titles and
|
# synchronised output, the system clipboard (OSC 52), window titles and
|
||||||
# cursor styling all pass through.
|
# cursor styling all pass through.
|
||||||
@@ -75,6 +258,78 @@
|
|||||||
set -as terminal-features ",foot*:title"
|
set -as terminal-features ",foot*:title"
|
||||||
set -as terminal-features ",foot*:ccolour"
|
set -as terminal-features ",foot*:ccolour"
|
||||||
set -as terminal-features ",foot*:cstyle"
|
set -as terminal-features ",foot*:cstyle"
|
||||||
|
|
||||||
|
# No home-manager options for these.
|
||||||
|
set -g renumber-windows on
|
||||||
|
set -g set-clipboard on
|
||||||
|
|
||||||
|
# Catppuccin v2 statusline. Must run after the plugin has loaded;
|
||||||
|
# home-manager appends this extraConfig after the whole plugin list.
|
||||||
|
set -g status-left-length 100
|
||||||
|
set -g status-right-length 100
|
||||||
|
set -g status-left ""
|
||||||
|
set -g status-right "#{E:@catppuccin_status_application}"
|
||||||
|
set -ag status-right "#{E:@catppuccin_status_session}"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Add the key to the agent on first use, so the passphrase is typed once per
|
||||||
|
# login session rather than per commit/push (commit signing uses this agent).
|
||||||
|
# The work box keeps its own ssh config (see work/default.nix), so this only
|
||||||
|
# manages ~/.ssh/config on the personal hosts.
|
||||||
|
programs.ssh = {
|
||||||
|
enable = true;
|
||||||
|
# The module's built-in default "*" block is being deprecated; opt out and
|
||||||
|
# carry the defaults we want ourselves under settings."*".
|
||||||
|
enableDefaultConfig = false;
|
||||||
|
settings = {
|
||||||
|
# Global defaults (rendered last, as ssh_config wants). AddKeysToAgent
|
||||||
|
# adds the key on first use so the passphrase is typed once per session.
|
||||||
|
"*" = {
|
||||||
|
AddKeysToAgent = "yes";
|
||||||
|
ForwardAgent = false;
|
||||||
|
Compression = false;
|
||||||
|
ServerAliveInterval = 0;
|
||||||
|
ServerAliveCountMax = 3;
|
||||||
|
HashKnownHosts = false;
|
||||||
|
UserKnownHostsFile = "~/.ssh/known_hosts";
|
||||||
|
ControlMaster = "no";
|
||||||
|
ControlPath = "~/.ssh/master-%r@%n:%p";
|
||||||
|
ControlPersist = "no";
|
||||||
|
}
|
||||||
|
# macOS: also cache the passphrase in the login keychain. UseKeychain
|
||||||
|
# exists only in Apple's ssh; nixpkgs' openssh (which may be the `ssh` on
|
||||||
|
# PATH) rejects it as "Bad configuration option". IgnoreUnknown (emitted
|
||||||
|
# first by the module) makes any non-Apple ssh skip it instead of erroring,
|
||||||
|
# while Apple's ssh still honours it. Darwin-only.
|
||||||
|
// lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin {
|
||||||
|
IgnoreUnknown = "UseKeychain";
|
||||||
|
UseKeychain = "yes";
|
||||||
|
};
|
||||||
|
# Gitea remote (the flake's origin) -- required on every host. HostName
|
||||||
|
# pins the IP so it resolves without DNS. Port 30009 is non-default; pin
|
||||||
|
# the dedicated key (identitiesOnly avoids "too many authentication
|
||||||
|
# failures" when the agent holds several keys).
|
||||||
|
"code.emmathe.dev" = {
|
||||||
|
HostName = "10.187.1.76";
|
||||||
|
User = "git";
|
||||||
|
Port = 30009;
|
||||||
|
IdentityFile = "~/.ssh/code.emmathe.dev";
|
||||||
|
IdentitiesOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Run a user ssh-agent on Linux (macOS provides one via launchd). EDaaS also
|
||||||
|
# enables this in the work module; both being true merges cleanly.
|
||||||
|
services.ssh-agent.enable = lib.mkIf pkgs.stdenv.hostPlatform.isLinux true;
|
||||||
|
|
||||||
|
# Drop the zsh completion dump on every activation. A stale ~/.zcompdump
|
||||||
|
# caches /nix/store paths to completion functions; once a rebuild or a manual
|
||||||
|
# GC removes them, compinit fails with "_git: function definition file not
|
||||||
|
# found" for every completion. Deleting it forces a fresh rebuild from the
|
||||||
|
# current fpath on the next shell.
|
||||||
|
home.activation.resetZcompdump = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
$DRY_RUN_CMD rm -f "$HOME"/.zcompdump* "''${XDG_CACHE_HOME:-$HOME/.cache}"/zsh/.zcompdump* 2>/dev/null || true
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,6 +237,9 @@ in
|
|||||||
# text). Only colors-dark is needed; we never set initial-color-theme=light.
|
# text). Only colors-dark is needed; we never set initial-color-theme=light.
|
||||||
settings = {
|
settings = {
|
||||||
main = {
|
main = {
|
||||||
|
# Nerd Font: monospace plus the powerline/Nerd glyphs the tmux
|
||||||
|
# statusline uses (otherwise they render as blank/"?").
|
||||||
|
font = "JetBrainsMono Nerd Font:size=11";
|
||||||
# Advertise as xterm-256color so remote hosts without foot's terminfo
|
# Advertise as xterm-256color so remote hosts without foot's terminfo
|
||||||
# still behave (tmux re-adds foot's RGB/sync/etc. features -- see
|
# still behave (tmux re-adds foot's RGB/sync/etc. features -- see
|
||||||
# shell.nix). The [main] section is the unheadered top of foot.ini.
|
# shell.nix). The [main] section is the unheadered top of foot.ini.
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
{ pkgs, ... }:
|
# Home-manager module for the work (EDaaS/WSL) profile: corporate git signing,
|
||||||
|
# work toolchain packages and tmux tweaks. Imported only by the work host.
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
# The work box keeps its own (corporate) ~/.ssh/config; don't let the personal
|
||||||
|
# programs.ssh (shell.nix) take it over. The ssh-agent below still runs.
|
||||||
|
programs.ssh.enable = lib.mkForce false;
|
||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
settings = {
|
settings = {
|
||||||
commit.gpgsign = true;
|
commit.gpgsign = true;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# statix lint config. Two default lints are disabled because they flag this
|
||||||
|
# repo's intentional house style, not bugs:
|
||||||
|
# repeated_keys - we use `foo.a = ...; foo.b = ...;` (dotted) over nesting.
|
||||||
|
# empty_pattern - module files use `{ ... }:` / `{ }:` deliberately.
|
||||||
|
disabled = [
|
||||||
|
"repeated_keys",
|
||||||
|
"empty_pattern",
|
||||||
|
]
|
||||||
@@ -6,6 +6,11 @@
|
|||||||
{
|
{
|
||||||
programs.zsh.enable = true;
|
programs.zsh.enable = true;
|
||||||
|
|
||||||
|
# Install the Nerd Font into /Library/Fonts so iTerm2 can use it (set it in
|
||||||
|
# iTerm2 -> Settings -> Profiles -> Text -> Font: "JetBrainsMono Nerd Font").
|
||||||
|
# Provides the powerline/Nerd glyphs the tmux statusline draws.
|
||||||
|
fonts.packages = [ pkgs.nerd-fonts.jetbrains-mono ];
|
||||||
|
|
||||||
# CLI tooling sourced from nixpkgs instead of Homebrew formulae. Pure library
|
# CLI tooling sourced from nixpkgs instead of Homebrew formulae. Pure library
|
||||||
# dependencies are omitted; nix pulls them into closures automatically.
|
# dependencies are omitted; nix pulls them into closures automatically.
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
|
|||||||
@@ -14,9 +14,18 @@
|
|||||||
|
|
||||||
networking.hostName = "Emma-Asahi";
|
networking.hostName = "Emma-Asahi";
|
||||||
|
|
||||||
# No fingerprint reader on this machine; empty service still lets swaylock
|
# Audio (PipeWire) and the swaylock PAM stack are inherited from
|
||||||
# authenticate via password.
|
# workstation.nix. hardware.enableRedistributableFirmware is also set there;
|
||||||
security.pam.services.swaylock = { };
|
# it is harmless here since Asahi supplies its own peripheral firmware below.
|
||||||
|
|
||||||
|
# Binary cache for the Asahi kernel/build artifacts, so the MBP pulls prebuilt
|
||||||
|
# outputs instead of compiling the Asahi kernel locally.
|
||||||
|
nix.settings = {
|
||||||
|
substituters = [ "https://nixos-apple-silicon.cachix.org" ];
|
||||||
|
trusted-public-keys = [
|
||||||
|
"nixos-apple-silicon.cachix.org-1:8psDu5SA5dAD7qA0zMy5UT292TxeEPzIz8VVEr2Js20="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
# Apple peripheral firmware (Wi-Fi/Bluetooth). The directory is gitignored and
|
# Apple peripheral firmware (Wi-Fi/Bluetooth). The directory is gitignored and
|
||||||
# populated out-of-band -- see README.
|
# populated out-of-band -- see README.
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ Flake host: `lyrathorpe-macpro31`. Desktop (`portable = false`, imports
|
|||||||
|
|
||||||
## Hardware configuration
|
## Hardware configuration
|
||||||
|
|
||||||
`hardware-configuration.nix` here is a hand-written **placeholder**. On the real
|
`hardware-configuration.nix` here is the real config generated by
|
||||||
machine, run `nixos-generate-config`, replace the file, and commit it. It assumes
|
`nixos-generate-config` on the machine. Root is an **LVM** logical volume
|
||||||
by-label partitions — ESP `ESP` (vfat, mounted at `/boot`), root `nixos` (ext4),
|
(`/dev/mapper/MacPro-Root`, ext4); the ESP (vfat) and swap are referenced by
|
||||||
and `swap` — so either label them at install time or swap in the generated UUIDs.
|
UUID. The initrd carries `dm-snapshot` for the LVM root. Regenerate and commit
|
||||||
|
if the disk layout changes.
|
||||||
|
|
||||||
## Bootloader
|
## Bootloader
|
||||||
|
|
||||||
|
|||||||
@@ -27,19 +27,9 @@
|
|||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
networking.firewall.allowedTCPPorts = [ 22 ];
|
networking.firewall.allowedTCPPorts = [ 22 ];
|
||||||
|
|
||||||
services.pipewire = {
|
# Dual Harpertown Xeon microcode. Redistributable firmware (GPU/NIC blobs) is
|
||||||
enable = true;
|
# enabled in workstation.nix.
|
||||||
pulse.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# No fingerprint hardware; empty service still lets swaylock authenticate via
|
|
||||||
# password.
|
|
||||||
security.pam.services.swaylock = { };
|
|
||||||
|
|
||||||
# Dual Harpertown Xeon microcode + redistributable firmware (e.g. GPU/NIC
|
|
||||||
# blobs).
|
|
||||||
hardware.cpu.intel.updateMicrocode = true;
|
hardware.cpu.intel.updateMicrocode = true;
|
||||||
hardware.enableRedistributableFirmware = true;
|
|
||||||
|
|
||||||
# GPU note: the stock card varies between units -- ATI Radeon HD 2600 XT or
|
# GPU note: the stock card varies between units -- ATI Radeon HD 2600 XT or
|
||||||
# NVIDIA GeForce 8800 GT. Sway needs a working KMS/modesetting driver; do NOT
|
# NVIDIA GeForce 8800 GT. Sway needs a working KMS/modesetting driver; do NOT
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ install time or swap in the generated UUIDs.
|
|||||||
switch by commenting it out and uncommenting the relevant alternative.
|
switch by commenting it out and uncommenting the relevant alternative.
|
||||||
|
|
||||||
| Firmware | Module | Notes |
|
| Firmware | Module | Notes |
|
||||||
| --- | --- | --- |
|
| ---------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| Stock Lenovo BIOS, or coreboot + **SeaBIOS** payload | `boot-bios.nix` | GRUB on the MBR. Set `device` to the real install disk (`/dev/sda` by default). MBR/legacy layout. |
|
| Stock Lenovo BIOS, or coreboot + **SeaBIOS** payload | `boot-bios.nix` | GRUB on the MBR. Set `device` to the real install disk (`/dev/sda` by default). MBR/legacy layout. |
|
||||||
| coreboot + **GRUB** payload | `boot-coreboot-grub.nix` | GRUB is config-only (`device = "nodev"`); NixOS does **not** write to a disk. Your coreboot `grub.cfg` (in the flash chip) must `search` for and `configfile` the on-disk `/boot/grub/grub.cfg`, or chainload the disk's GRUB. |
|
| coreboot + **GRUB** payload | `boot-coreboot-grub.nix` | GRUB is config-only (`device = "nodev"`); NixOS does **not** write to a disk. Your coreboot `grub.cfg` (in the flash chip) must `search` for and `configfile` the on-disk `/boot/grub/grub.cfg`, or chainload the disk's GRUB. |
|
||||||
| coreboot + **Tianocore/edk2 (UEFI)** payload | `boot-coreboot-uefi.nix` | systemd-boot. `canTouchEfiVariables = true` (coreboot honours NVRAM writes). The module **declares its own ESP** (`/boot` vfat, label `ESP`) — when you regenerate `hardware-configuration.nix`, do **not** let it also define `/boot`. Create + label an `ESP` vfat partition (GPT). |
|
| coreboot + **Tianocore/edk2 (UEFI)** payload | `boot-coreboot-uefi.nix` | systemd-boot. `canTouchEfiVariables = true` (coreboot honours NVRAM writes). The module **declares its own ESP** (`/boot` vfat, label `ESP`) — when you regenerate `hardware-configuration.nix`, do **not** let it also define `/boot`. Create + label an `ESP` vfat partition (GPT). |
|
||||||
|
|||||||
@@ -18,25 +18,18 @@
|
|||||||
|
|
||||||
console.font = "Lat2-Terminus16";
|
console.font = "Lat2-Terminus16";
|
||||||
|
|
||||||
services.pipewire = {
|
# Low-RAM host (4 GiB max): a compressed RAM swap reduces disk paging.
|
||||||
enable = true;
|
zramSwap.enable = true;
|
||||||
pulse.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# This host accepts SSH, so open 22 (the firewall itself is enabled in
|
# This host accepts SSH, so open 22 (the firewall itself is enabled in
|
||||||
# laptop.nix with a default-deny policy).
|
# laptop.nix with a default-deny policy).
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
networking.firewall.allowedTCPPorts = [ 22 ];
|
networking.firewall.allowedTCPPorts = [ 22 ];
|
||||||
|
|
||||||
# The T400's fingerprint reader differs/may be absent; empty service still
|
# Intel Core 2 (Penryn) microcode. Redistributable firmware (enabled in
|
||||||
# lets swaylock authenticate via password.
|
# workstation.nix) supplies the iwlwifi blobs (Intel WiFi Link 5100/5300) and
|
||||||
security.pam.services.swaylock = { };
|
# the radeon firmware needed by the discrete GPU below.
|
||||||
|
|
||||||
# Intel Core 2 (Penryn) microcode + redistributable firmware. The latter also
|
|
||||||
# supplies the iwlwifi blobs (Intel WiFi Link 5100/5300) and the radeon
|
|
||||||
# firmware needed by the discrete GPU below.
|
|
||||||
hardware.cpu.intel.updateMicrocode = true;
|
hardware.cpu.intel.updateMicrocode = true;
|
||||||
hardware.enableRedistributableFirmware = true;
|
|
||||||
|
|
||||||
# This T400 has the optional discrete GPU fitted: an ATI Mobility Radeon HD
|
# This T400 has the optional discrete GPU fitted: an ATI Mobility Radeon HD
|
||||||
# 3470 (RV620), driven by the open `radeon` KMS driver. Load it in the initrd
|
# 3470 (RV620), driven by the open `radeon` KMS driver. Load it in the initrd
|
||||||
|
|||||||
@@ -6,10 +6,23 @@
|
|||||||
time.timeZone = "Europe/London";
|
time.timeZone = "Europe/London";
|
||||||
i18n.defaultLocale = "en_GB.UTF-8";
|
i18n.defaultLocale = "en_GB.UTF-8";
|
||||||
|
|
||||||
|
# Store hygiene. auto-optimise-store hard-links identical files in the store
|
||||||
|
# after each build (cheap dedupe; NOT a garbage collector -- there is
|
||||||
|
# deliberately no automatic GC timer). The larger download buffer avoids
|
||||||
|
# "buffer full" stalls when fetching big NARs over a fast link.
|
||||||
|
nix.settings.auto-optimise-store = true;
|
||||||
|
nix.settings.download-buffer-size = 134217728; # 128 MiB
|
||||||
|
|
||||||
# Minimal system-level CLI available before the home-manager profile loads
|
# Minimal system-level CLI available before the home-manager profile loads
|
||||||
# (e.g. early boot / rescue). User-level tooling lives in home-manager.
|
# (e.g. early boot / rescue). User-level tooling lives in home-manager.
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
git
|
git
|
||||||
fastfetch
|
fastfetch
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Terminal font with powerline/Nerd glyphs. Installed on every host because
|
||||||
|
# the tmux statusline (which uses these glyphs) runs everywhere, not just on
|
||||||
|
# the Sway/graphical hosts. foot names it explicitly (home/sway.nix); the Mac
|
||||||
|
# installs it via the Darwin config.
|
||||||
|
fonts.packages = [ pkgs.nerd-fonts.jetbrains-mono ];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,4 +14,24 @@
|
|||||||
# Default-deny inbound. Hosts that run a listening service open their own
|
# Default-deny inbound. Hosts that run a listening service open their own
|
||||||
# ports next to where the service is enabled (e.g. sshd -> 22 on X1).
|
# ports next to where the service is enabled (e.g. sshd -> 22 on X1).
|
||||||
networking.firewall.enable = true;
|
networking.firewall.enable = true;
|
||||||
|
|
||||||
|
# Disk hygiene for the physical hosts. fstrim reclaims unused SSD blocks on a
|
||||||
|
# weekly timer; cleanOnBoot wipes /tmp at every boot.
|
||||||
|
services.fstrim.enable = true;
|
||||||
|
boot.tmp.cleanOnBoot = true;
|
||||||
|
|
||||||
|
# Audio. PipeWire with the PulseAudio shim covers every graphical host; no
|
||||||
|
# per-machine audio config is needed.
|
||||||
|
services.pipewire = {
|
||||||
|
enable = true;
|
||||||
|
pulse.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# swaylock PAM stack. None of these machines has working fingerprint auth, so
|
||||||
|
# an empty service is enough -- swaylock falls back to password.
|
||||||
|
security.pam.services.swaylock = { };
|
||||||
|
|
||||||
|
# Redistributable firmware (GPU/Wi-Fi/NIC blobs) for the x86 hosts. Harmless
|
||||||
|
# on the Asahi MBP, which supplies its own peripheral firmware out-of-band.
|
||||||
|
hardware.enableRedistributableFirmware = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user