Compare commits
7 Commits
e12d425df5
...
4c29259470
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c29259470 | |||
| 7b72236b4c | |||
| 60120d46bf | |||
| b64a7416c9 | |||
| 3138f6ce11 | |||
| 6569d7d4d8 | |||
| eae286c5ab |
55
README.md
Normal file
55
README.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# NixOS Config
|
||||||
|
|
||||||
|
Personal Nix flake for four machines:
|
||||||
|
|
||||||
|
- `michael` - x86_64 Linux server
|
||||||
|
- `tahani` - x86_64 Linux home server / workstation
|
||||||
|
- `chidi` - aarch64 Darwin work laptop
|
||||||
|
- `jason` - aarch64 Darwin personal laptop
|
||||||
|
|
||||||
|
## Repository Map
|
||||||
|
|
||||||
|
- `modules/` - flake-parts modules, auto-imported via `import-tree`
|
||||||
|
- `modules/_hosts/` - host-specific submodules like hardware, disks, and services
|
||||||
|
- `modules/_lib/` - local helper functions
|
||||||
|
- `apps/` - Nushell apps exposed through the flake
|
||||||
|
- `secrets/` - SOPS-encrypted secrets
|
||||||
|
- `flake.nix` - generated flake entrypoint
|
||||||
|
- `modules/dendritic.nix` - source of truth for flake inputs and `flake.nix` generation
|
||||||
|
|
||||||
|
## How It Is Structured
|
||||||
|
|
||||||
|
This repo uses `den` and organizes configuration around aspects instead of putting everything directly in host files.
|
||||||
|
|
||||||
|
- shared behavior lives in `den.aspects.<name>.<class>` modules
|
||||||
|
- hosts are declared in `modules/hosts.nix`
|
||||||
|
- host composition happens in `modules/<host>.nix`
|
||||||
|
- user-level config mostly lives in Home Manager aspects
|
||||||
|
|
||||||
|
Common examples:
|
||||||
|
|
||||||
|
- `modules/core.nix` - shared Nix and shell foundation
|
||||||
|
- `modules/dev-tools.nix` - VCS, language, and developer tooling
|
||||||
|
- `modules/network.nix` - SSH, fail2ban, and tailscale aspects
|
||||||
|
- `modules/michael.nix` - server composition for `michael`
|
||||||
|
- `modules/tahani.nix` - server/workstation composition for `tahani`
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix run .#build
|
||||||
|
nix run .#build -- michael
|
||||||
|
nix run .#apply
|
||||||
|
nix run .#deploy -- .#tahani
|
||||||
|
nix flake check
|
||||||
|
alejandra .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Updating The Flake
|
||||||
|
|
||||||
|
`flake.nix` is generated. Update inputs in `modules/dendritic.nix`, then regenerate:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix run .#write-flake
|
||||||
|
alejandra .
|
||||||
|
```
|
||||||
66
flake.lock
generated
66
flake.lock
generated
@@ -114,11 +114,11 @@
|
|||||||
},
|
},
|
||||||
"den": {
|
"den": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773203359,
|
"lastModified": 1773295801,
|
||||||
"narHash": "sha256-CU+bk7KxCggu9MNFs6Yp4K8e24RrRYOOnqT0ZPT82+U=",
|
"narHash": "sha256-Wzk6tz4K8lID2El0BG3F3JLFPEx6P74E3UyJwBlE+I0=",
|
||||||
"owner": "vic",
|
"owner": "vic",
|
||||||
"repo": "den",
|
"repo": "den",
|
||||||
"rev": "101b08a257a1ff892901b02f67109ec69f75466f",
|
"rev": "7c781f55d26fe40d84961557aa2e1e9480cee93e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -237,11 +237,11 @@
|
|||||||
},
|
},
|
||||||
"flake-aspects": {
|
"flake-aspects": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773185256,
|
"lastModified": 1773272797,
|
||||||
"narHash": "sha256-e3YqMwdQ2EpVTuWRkK2rkrHywp8QCpkj7x2U53SNoIA=",
|
"narHash": "sha256-sSdYZiIeo98LmdnCR5GMN8B8bsHFgWA+1l9ZEpwXrFU=",
|
||||||
"owner": "vic",
|
"owner": "vic",
|
||||||
"repo": "flake-aspects",
|
"repo": "flake-aspects",
|
||||||
"rev": "81a51a8997abe392b9d0794424a4823adc9bd3af",
|
"rev": "cc5a09d16af05210afe01c22f6b868929a4163b6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -268,11 +268,11 @@
|
|||||||
},
|
},
|
||||||
"flake-file": {
|
"flake-file": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773180483,
|
"lastModified": 1773224147,
|
||||||
"narHash": "sha256-Fz2OYAgaYzmm6KhQWMk18JuyxgVb80pLm7hlXnmXbtg=",
|
"narHash": "sha256-w9RQyKZSTfqoZPRzIf7H4qVHy2N6uFk1MUU+c1K4c40=",
|
||||||
"owner": "vic",
|
"owner": "vic",
|
||||||
"repo": "flake-file",
|
"repo": "flake-file",
|
||||||
"rev": "8edcfd6d941a1a936296c89fd70dd686df947be8",
|
"rev": "97bd69ff570dddccd704077830446ec1ca3a6988",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -406,11 +406,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773179137,
|
"lastModified": 1773286336,
|
||||||
"narHash": "sha256-EdW2bwzlfme0vbMOcStnNmKlOAA05Bp6su2O8VLGT0k=",
|
"narHash": "sha256-+yFtmhOHterllxWmV6YbdevTXpJdGS0mS0UmJ0k9fh0=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "3f98e2bbc661ec0aaf558d8a283d6955f05f1d09",
|
"rev": "7d06e0cefe6e4a1e85b2b3274dcb0b3da242a557",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -422,11 +422,11 @@
|
|||||||
"homebrew-cask": {
|
"homebrew-cask": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773204415,
|
"lastModified": 1773303437,
|
||||||
"narHash": "sha256-ayKgBC9e8y1sx2BHstY1OPrKMBIJAJoIQxIX7HGstGo=",
|
"narHash": "sha256-grP7e0BRp8GDT28hAV5H4Pu51IDQ34913hxGldlQf70=",
|
||||||
"owner": "homebrew",
|
"owner": "homebrew",
|
||||||
"repo": "homebrew-cask",
|
"repo": "homebrew-cask",
|
||||||
"rev": "6b75b8e53d71974d5e81dde8efd27b2937516ac8",
|
"rev": "0300017ecdeaa28c6635c559381ff4d0e1203c86",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -438,11 +438,11 @@
|
|||||||
"homebrew-core": {
|
"homebrew-core": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773213089,
|
"lastModified": 1773306422,
|
||||||
"narHash": "sha256-A64kuAmOD7BLz6ESkpNayFNL+gXF6dMYuF2O8ZgGJ/k=",
|
"narHash": "sha256-EvboT0Gno/1BZ7OcaDFZ737cQr2J6amdrbpHAFbameU=",
|
||||||
"owner": "homebrew",
|
"owner": "homebrew",
|
||||||
"repo": "homebrew-core",
|
"repo": "homebrew-core",
|
||||||
"rev": "a8f0bec4e248fa90aa84a7c4a5b3fbc9c160b6c6",
|
"rev": "f6d9718a1bee00675755ebfbe80964990bebcfda",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -526,11 +526,11 @@
|
|||||||
"treefmt-nix": "treefmt-nix"
|
"treefmt-nix": "treefmt-nix"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773201098,
|
"lastModified": 1773302483,
|
||||||
"narHash": "sha256-yq35qMKDHyMdVlhGfR5BojbjniY2cY9XYmiILeCf1Xc=",
|
"narHash": "sha256-NFnShCTM8fsNF8dRMIgebo8oiTHMKyCEBieYon4K0Ic=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "llm-agents.nix",
|
"repo": "llm-agents.nix",
|
||||||
"rev": "8578734bf5087a1ca45033c2ec8e1a2228f9b95c",
|
"rev": "dd92bb728d845be99ebfee69c1ee951dcbceb2b1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -652,11 +652,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_4": {
|
"nixpkgs_4": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1772956932,
|
"lastModified": 1773110118,
|
||||||
"narHash": "sha256-M0yS4AafhKxPPmOHGqIV0iKxgNO8bHDWdl1kOwGBwRY=",
|
"narHash": "sha256-mPAG8phMbCReKSiKAijjjd3v7uVcJOQ75gSjGJjt/Rk=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "608d0cadfed240589a7eea422407a547ad626a14",
|
"rev": "e607cb5360ff1234862ac9f8839522becb853bb9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -668,11 +668,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_5": {
|
"nixpkgs_5": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773212285,
|
"lastModified": 1773305098,
|
||||||
"narHash": "sha256-56OmaHrnvxJA1D78ZDqBME9ptqRMhw3r+vw2/UKfD24=",
|
"narHash": "sha256-fm+rOZiAzFivuco5d7T+rE8i213EIEuHvoIuWiVlYto=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "15d31785a653f47d6f8fe017ae244bb5282fa3e5",
|
"rev": "b9637319b2e3b8061ba416b46cde41bd9f8b4442",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -753,11 +753,11 @@
|
|||||||
"nono": {
|
"nono": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773209960,
|
"lastModified": 1773270026,
|
||||||
"narHash": "sha256-SZ6Qze+sZpP2gqMmhyYSIlMaumJUhzaSIJwKJaOP4Mo=",
|
"narHash": "sha256-aLMBK2JQkn07wzho79WwolXRZEqvpILdq5bxp9F6Wug=",
|
||||||
"owner": "always-further",
|
"owner": "always-further",
|
||||||
"repo": "nono",
|
"repo": "nono",
|
||||||
"rev": "910034e23d37882862e9694f737094b0a3e67711",
|
"rev": "9f3205847598d04d8b882c8ecb8238e4855d2a41",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1022,11 +1022,11 @@
|
|||||||
"utils": "utils_2"
|
"utils": "utils_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773180218,
|
"lastModified": 1773260683,
|
||||||
"narHash": "sha256-VEt3lAK7jMVE1mkW2S8RaCd3G19M102pCGR6ge5MBsY=",
|
"narHash": "sha256-ZZEX8JD+kiqpNsPOgrksbNrh5w8B63s8ebJplftdqhQ=",
|
||||||
"owner": "agavra",
|
"owner": "agavra",
|
||||||
"repo": "tuicr",
|
"repo": "tuicr",
|
||||||
"rev": "544f8b6f3bbef4577f6b79ded2974684d8a43582",
|
"rev": "392d5e5a7b443cb7bbf234f7f44c6c0352b99c8a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ in {
|
|||||||
{path = "/System/Applications/Music.app/";}
|
{path = "/System/Applications/Music.app/";}
|
||||||
{path = "/System/Applications/System Settings.app/";}
|
{path = "/System/Applications/System Settings.app/";}
|
||||||
{
|
{
|
||||||
path = "${config.users.users.cschmatzler.home}/Downloads";
|
path = "/Users/cschmatzler/Downloads";
|
||||||
section = "others";
|
section = "others";
|
||||||
options = "--sort name --view grid --display stack";
|
options = "--sort name --view grid --display stack";
|
||||||
}
|
}
|
||||||
|
|||||||
58
modules/_hosts/michael/backups.nix
Normal file
58
modules/_hosts/michael/backups.nix
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
services.restic.backups.gitea = {
|
||||||
|
repository = "s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories";
|
||||||
|
paths = ["/var/lib/gitea"];
|
||||||
|
exclude = [
|
||||||
|
"/var/lib/gitea/log"
|
||||||
|
"/var/lib/gitea/data/gitea.db"
|
||||||
|
"/var/lib/gitea/data/gitea.db-shm"
|
||||||
|
"/var/lib/gitea/data/gitea.db-wal"
|
||||||
|
];
|
||||||
|
passwordFile = config.sops.secrets.michael-gitea-restic-password.path;
|
||||||
|
environmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
||||||
|
pruneOpts = [
|
||||||
|
"--keep-daily 7"
|
||||||
|
"--keep-weekly 4"
|
||||||
|
"--keep-monthly 6"
|
||||||
|
];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "daily";
|
||||||
|
Persistent = true;
|
||||||
|
RandomizedDelaySec = "1h";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.restic-backups-gitea = {
|
||||||
|
wants = ["restic-init-gitea.service"];
|
||||||
|
after = ["restic-init-gitea.service"];
|
||||||
|
serviceConfig = {
|
||||||
|
User = lib.mkForce "gitea";
|
||||||
|
Group = lib.mkForce "gitea";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.restic-init-gitea = {
|
||||||
|
description = "Initialize Restic repository for Gitea backups";
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
after = ["network-online.target"];
|
||||||
|
wants = ["network-online.target"];
|
||||||
|
path = [pkgs.restic];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "gitea";
|
||||||
|
Group = "gitea";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
EnvironmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
export RESTIC_PASSWORD=$(cat ${config.sops.secrets.michael-gitea-restic-password.path})
|
||||||
|
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories snapshots &>/dev/null || \
|
||||||
|
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories init
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
114
modules/_hosts/michael/gitea.nix
Normal file
114
modules/_hosts/michael/gitea.nix
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
sops.secrets = {
|
||||||
|
michael-gitea-litestream = {
|
||||||
|
sopsFile = ../../../secrets/michael-gitea-litestream;
|
||||||
|
format = "binary";
|
||||||
|
owner = "gitea";
|
||||||
|
group = "gitea";
|
||||||
|
path = "/run/secrets/michael-gitea-litestream";
|
||||||
|
};
|
||||||
|
michael-gitea-restic-password = {
|
||||||
|
sopsFile = ../../../secrets/michael-gitea-restic-password;
|
||||||
|
format = "binary";
|
||||||
|
owner = "gitea";
|
||||||
|
group = "gitea";
|
||||||
|
path = "/run/secrets/michael-gitea-restic-password";
|
||||||
|
};
|
||||||
|
michael-gitea-restic-env = {
|
||||||
|
sopsFile = ../../../secrets/michael-gitea-restic-env;
|
||||||
|
format = "binary";
|
||||||
|
owner = "gitea";
|
||||||
|
group = "gitea";
|
||||||
|
path = "/run/secrets/michael-gitea-restic-env";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [80 443];
|
||||||
|
|
||||||
|
services.redis.servers.gitea = {
|
||||||
|
enable = true;
|
||||||
|
port = 6380;
|
||||||
|
bind = "127.0.0.1";
|
||||||
|
settings = {
|
||||||
|
maxmemory = "64mb";
|
||||||
|
maxmemory-policy = "allkeys-lru";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gitea = {
|
||||||
|
enable = true;
|
||||||
|
database = {
|
||||||
|
type = "sqlite3";
|
||||||
|
path = "/var/lib/gitea/data/gitea.db";
|
||||||
|
};
|
||||||
|
settings = {
|
||||||
|
server = {
|
||||||
|
ROOT_URL = "https://git.schmatzler.com/";
|
||||||
|
DOMAIN = "git.schmatzler.com";
|
||||||
|
HTTP_ADDR = "127.0.0.1";
|
||||||
|
HTTP_PORT = 3000;
|
||||||
|
LANDING_PAGE = "explore";
|
||||||
|
};
|
||||||
|
service.DISABLE_REGISTRATION = true;
|
||||||
|
security.INSTALL_LOCK = true;
|
||||||
|
cache = {
|
||||||
|
ADAPTER = "redis";
|
||||||
|
HOST = "redis://127.0.0.1:6380/0?pool_size=100&idle_timeout=180s";
|
||||||
|
ITEM_TTL = "16h";
|
||||||
|
};
|
||||||
|
"cache.last_commit" = {
|
||||||
|
ITEM_TTL = "8760h";
|
||||||
|
COMMITS_COUNT = 100;
|
||||||
|
};
|
||||||
|
session = {
|
||||||
|
PROVIDER = "redis";
|
||||||
|
PROVIDER_CONFIG = "redis://127.0.0.1:6380/1?pool_size=100&idle_timeout=180s";
|
||||||
|
COOKIE_SECURE = true;
|
||||||
|
SAME_SITE = "strict";
|
||||||
|
};
|
||||||
|
api.ENABLE_SWAGGER = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.litestream = {
|
||||||
|
enable = true;
|
||||||
|
environmentFile = config.sops.secrets.michael-gitea-litestream.path;
|
||||||
|
settings = {
|
||||||
|
dbs = [
|
||||||
|
{
|
||||||
|
path = "/var/lib/gitea/data/gitea.db";
|
||||||
|
replicas = [
|
||||||
|
{
|
||||||
|
type = "s3";
|
||||||
|
bucket = "michael-gitea-litestream";
|
||||||
|
path = "gitea";
|
||||||
|
endpoint = "s3.eu-central-003.backblazeb2.com";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.litestream.serviceConfig = {
|
||||||
|
User = lib.mkForce "gitea";
|
||||||
|
Group = lib.mkForce "gitea";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.caddy = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts."git.schmatzler.com".extraConfig = ''
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "DENY"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
reverse_proxy localhost:3000
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{config, ...}: {
|
||||||
services.adguardhome = {
|
services.adguardhome = {
|
||||||
enable = true;
|
enable = true;
|
||||||
host = "0.0.0.0";
|
host = "127.0.0.1";
|
||||||
port = 10000;
|
port = 10000;
|
||||||
settings = {
|
settings = {
|
||||||
dhcp = {
|
dhcp = {
|
||||||
@@ -57,4 +57,13 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.caddy.virtualHosts."adguard.manticore-hippocampus.ts.net" = {
|
||||||
|
extraConfig = ''
|
||||||
|
tls {
|
||||||
|
get_certificate tailscale
|
||||||
|
}
|
||||||
|
reverse_proxy localhost:${toString config.services.adguardhome.port}
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{config, ...}: {
|
{config, ...}: {
|
||||||
services.caddy = {
|
services.caddy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableReload = false;
|
||||||
globalConfig = ''
|
globalConfig = ''
|
||||||
admin off
|
admin off
|
||||||
'';
|
'';
|
||||||
@@ -25,8 +26,11 @@
|
|||||||
virtualisation.oci-containers = {
|
virtualisation.oci-containers = {
|
||||||
backend = "docker";
|
backend = "docker";
|
||||||
containers.paperless-ai = {
|
containers.paperless-ai = {
|
||||||
image = "clusterzx/paperless-ai:latest";
|
image = "clusterzx/paperless-ai:v3.0.9";
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
|
ports = [
|
||||||
|
"127.0.0.1:3000:3000"
|
||||||
|
];
|
||||||
volumes = [
|
volumes = [
|
||||||
"paperless-ai-data:/app/data"
|
"paperless-ai-data:/app/data"
|
||||||
];
|
];
|
||||||
@@ -36,11 +40,10 @@
|
|||||||
PAPERLESS_AI_PORT = "3000";
|
PAPERLESS_AI_PORT = "3000";
|
||||||
# Initial setup wizard will configure the rest
|
# Initial setup wizard will configure the rest
|
||||||
PAPERLESS_AI_INITIAL_SETUP = "yes";
|
PAPERLESS_AI_INITIAL_SETUP = "yes";
|
||||||
# Paperless-ngx API URL accessible from container (using host network)
|
PAPERLESS_API_URL = "http://host.docker.internal:${toString config.services.paperless.port}/api";
|
||||||
PAPERLESS_API_URL = "http://127.0.0.1:${toString config.services.paperless.port}/api";
|
|
||||||
};
|
};
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
"--network=host"
|
"--add-host=host.docker.internal:host-gateway"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -57,7 +60,7 @@
|
|||||||
|
|
||||||
services.paperless = {
|
services.paperless = {
|
||||||
enable = true;
|
enable = true;
|
||||||
address = "0.0.0.0";
|
address = "127.0.0.1";
|
||||||
passwordFile = config.sops.secrets.tahani-paperless-password.path;
|
passwordFile = config.sops.secrets.tahani-paperless-password.path;
|
||||||
settings = {
|
settings = {
|
||||||
PAPERLESS_DBENGINE = "sqlite";
|
PAPERLESS_DBENGINE = "sqlite";
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
user = "cschmatzler";
|
|
||||||
|
|
||||||
sshKeys = [
|
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHfRZQ+7ejD3YHbyMTrV0gN1Gc0DxtGgl5CVZSupo5ws"
|
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/I+/2QT47raegzMIyhwMEPKarJP/+Ox9ewA4ZFJwk/"
|
|
||||||
];
|
|
||||||
|
|
||||||
stateVersions = {
|
|
||||||
darwin = 6;
|
|
||||||
nixos = "25.11";
|
|
||||||
homeManager = "25.11";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{pkgs}:
|
|
||||||
pkgs.writeShellScriptBin "open-project" ''
|
|
||||||
TARGET=$(fd -t d --exact-depth 1 . $HOME/Projects |
|
|
||||||
sed "s~$HOME/Projects/~~" |
|
|
||||||
fzf --prompt "project > ")
|
|
||||||
|
|
||||||
if [ -n "$TARGET" ]; then
|
|
||||||
echo "$HOME/Projects/$TARGET"
|
|
||||||
fi
|
|
||||||
''
|
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
defaultEditor = true;
|
defaultEditor = true;
|
||||||
luaLoader.enable = true;
|
luaLoader.enable = true;
|
||||||
colorschemes.catppuccin = {
|
colorschemes.rose-pine = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
flavour = "latte";
|
variant = "dawn";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
extraConfigLua = ''
|
extraConfigLua = ''
|
||||||
|
|||||||
@@ -19,17 +19,6 @@ in {
|
|||||||
];
|
];
|
||||||
extraConfigLua = ''
|
extraConfigLua = ''
|
||||||
require('code-review').setup({
|
require('code-review').setup({
|
||||||
comment = {
|
|
||||||
storage = {
|
|
||||||
backend = "file",
|
|
||||||
file = {
|
|
||||||
dir = ".code-review",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
output = {
|
|
||||||
format = "minimal",
|
|
||||||
},
|
|
||||||
keymaps = false,
|
keymaps = false,
|
||||||
})
|
})
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -1,173 +1,351 @@
|
|||||||
{
|
{
|
||||||
programs.nixvim.plugins.mini = {
|
programs.nixvim = {
|
||||||
enable = true;
|
plugins.mini = {
|
||||||
modules = {
|
enable = true;
|
||||||
ai = {
|
modules = {
|
||||||
custom_textobjects = {
|
ai = {
|
||||||
B.__raw = "require('mini.extra').gen_ai_spec.buffer()";
|
custom_textobjects = {
|
||||||
F.__raw = "require('mini.ai').gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' })";
|
B.__raw = "require('mini.extra').gen_ai_spec.buffer()";
|
||||||
};
|
F.__raw = "require('mini.ai').gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' })";
|
||||||
};
|
|
||||||
align = {};
|
|
||||||
basics = {
|
|
||||||
options = {
|
|
||||||
basic = true;
|
|
||||||
extra_ui = true;
|
|
||||||
};
|
|
||||||
mappings = {
|
|
||||||
basic = false;
|
|
||||||
};
|
|
||||||
autocommands = {
|
|
||||||
basic = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
bracketed = {};
|
|
||||||
clue = {
|
|
||||||
clues.__raw = ''
|
|
||||||
{
|
|
||||||
{ mode = 'n', keys = '<Leader>e', desc = '+Explore/+Edit' },
|
|
||||||
{ mode = 'n', keys = '<Leader>f', desc = '+Find' },
|
|
||||||
{ mode = 'n', keys = '<Leader>v', desc = '+VCS' },
|
|
||||||
{ mode = 'n', keys = '<Leader>l', desc = '+LSP' },
|
|
||||||
{ mode = 'x', keys = '<Leader>l', desc = '+LSP' },
|
|
||||||
{ mode = 'n', keys = '<Leader>o', desc = '+OpenCode' },
|
|
||||||
{ mode = 'x', keys = '<Leader>o', desc = '+OpenCode' },
|
|
||||||
{ mode = 'n', keys = '<Leader>r', desc = '+Review' },
|
|
||||||
{ mode = 'v', keys = '<Leader>r', desc = '+Review' },
|
|
||||||
require("mini.clue").gen_clues.builtin_completion(),
|
|
||||||
require("mini.clue").gen_clues.g(),
|
|
||||||
require("mini.clue").gen_clues.marks(),
|
|
||||||
require("mini.clue").gen_clues.registers(),
|
|
||||||
require("mini.clue").gen_clues.windows({ submode_resize = true }),
|
|
||||||
require("mini.clue").gen_clues.z(),
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
triggers = [
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "<Leader>";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "x";
|
|
||||||
keys = "<Leader>";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "[";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "]";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "x";
|
|
||||||
keys = "[";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "x";
|
|
||||||
keys = "]";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "i";
|
|
||||||
keys = "<C-x>";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "g";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "x";
|
|
||||||
keys = "g";
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "\"";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "x";
|
|
||||||
keys = "\"";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "i";
|
|
||||||
keys = "<C-r>";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "c";
|
|
||||||
keys = "<C-r>";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "<C-w>";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "z";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "x";
|
|
||||||
keys = "z";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "'";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "n";
|
|
||||||
keys = "`";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "x";
|
|
||||||
keys = "'";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mode = "x";
|
|
||||||
keys = "`";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
cmdline = {};
|
|
||||||
comment = {};
|
|
||||||
diff = {};
|
|
||||||
extra = {};
|
|
||||||
git = {};
|
|
||||||
hipatterns = {
|
|
||||||
highlighters = {
|
|
||||||
fixme.__raw = "{ pattern = '%f[%w]()FIXME()%f[%W]', group = 'MiniHipatternsFixme' }";
|
|
||||||
hack.__raw = "{ pattern = '%f[%w]()HACK()%f[%W]', group = 'MiniHipatternsHack' }";
|
|
||||||
todo.__raw = "{ pattern = '%f[%w]()TODO()%f[%W]', group = 'MiniHipatternsTodo' }";
|
|
||||||
note.__raw = "{ pattern = '%f[%w]()NOTE()%f[%W]', group = 'MiniHipatternsNote' }";
|
|
||||||
hex_color.__raw = "require('mini.hipatterns').gen_highlighter.hex_color()";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
icons = {};
|
|
||||||
indentscope = {
|
|
||||||
settings = {
|
|
||||||
symbol = "|";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
jump = {};
|
|
||||||
jump2d = {
|
|
||||||
settings = {
|
|
||||||
spotter.__raw = "require('mini.jump2d').gen_spotter.pattern('[^%s%p]+')";
|
|
||||||
labels = "asdfghjkl";
|
|
||||||
view = {
|
|
||||||
dim = true;
|
|
||||||
n_steps_ahead = 2;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
align = {};
|
||||||
|
basics = {
|
||||||
|
options = {
|
||||||
|
basic = true;
|
||||||
|
extra_ui = true;
|
||||||
|
};
|
||||||
|
mappings = {
|
||||||
|
basic = false;
|
||||||
|
};
|
||||||
|
autocommands = {
|
||||||
|
basic = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
bracketed = {};
|
||||||
|
clue = {
|
||||||
|
clues.__raw = ''
|
||||||
|
{
|
||||||
|
{ mode = 'n', keys = '<Leader>e', desc = '+Explore/+Edit' },
|
||||||
|
{ mode = 'n', keys = '<Leader>f', desc = '+Find' },
|
||||||
|
{ mode = 'n', keys = '<Leader>v', desc = '+VCS' },
|
||||||
|
{ mode = 'n', keys = '<Leader>l', desc = '+LSP' },
|
||||||
|
{ mode = 'x', keys = '<Leader>l', desc = '+LSP' },
|
||||||
|
{ mode = 'n', keys = '<Leader>o', desc = '+OpenCode' },
|
||||||
|
{ mode = 'x', keys = '<Leader>o', desc = '+OpenCode' },
|
||||||
|
{ mode = 'n', keys = '<Leader>r', desc = '+Review' },
|
||||||
|
{ mode = 'v', keys = '<Leader>r', desc = '+Review' },
|
||||||
|
require("mini.clue").gen_clues.builtin_completion(),
|
||||||
|
require("mini.clue").gen_clues.g(),
|
||||||
|
require("mini.clue").gen_clues.marks(),
|
||||||
|
require("mini.clue").gen_clues.registers(),
|
||||||
|
require("mini.clue").gen_clues.windows({ submode_resize = true }),
|
||||||
|
require("mini.clue").gen_clues.z(),
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
triggers = [
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "<Leader>";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "x";
|
||||||
|
keys = "<Leader>";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "[";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "]";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "x";
|
||||||
|
keys = "[";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "x";
|
||||||
|
keys = "]";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "i";
|
||||||
|
keys = "<C-x>";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "g";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "x";
|
||||||
|
keys = "g";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "\"";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "x";
|
||||||
|
keys = "\"";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "i";
|
||||||
|
keys = "<C-r>";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "c";
|
||||||
|
keys = "<C-r>";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "<C-w>";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "z";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "x";
|
||||||
|
keys = "z";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "'";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "n";
|
||||||
|
keys = "`";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "x";
|
||||||
|
keys = "'";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mode = "x";
|
||||||
|
keys = "`";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
cmdline = {};
|
||||||
|
comment = {};
|
||||||
|
diff = {};
|
||||||
|
extra = {};
|
||||||
|
git = {};
|
||||||
|
hipatterns = {
|
||||||
|
highlighters = {
|
||||||
|
fixme.__raw = "{ pattern = '%f[%w]()FIXME()%f[%W]', group = 'MiniHipatternsFixme' }";
|
||||||
|
hack.__raw = "{ pattern = '%f[%w]()HACK()%f[%W]', group = 'MiniHipatternsHack' }";
|
||||||
|
todo.__raw = "{ pattern = '%f[%w]()TODO()%f[%W]', group = 'MiniHipatternsTodo' }";
|
||||||
|
note.__raw = "{ pattern = '%f[%w]()NOTE()%f[%W]', group = 'MiniHipatternsNote' }";
|
||||||
|
hex_color.__raw = "require('mini.hipatterns').gen_highlighter.hex_color()";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
icons = {};
|
||||||
|
indentscope = {
|
||||||
|
settings = {
|
||||||
|
symbol = "|";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
jump = {};
|
||||||
|
jump2d = {
|
||||||
|
settings = {
|
||||||
|
spotter.__raw = "require('mini.jump2d').gen_spotter.pattern('[^%s%p]+')";
|
||||||
|
labels = "asdfghjkl";
|
||||||
|
view = {
|
||||||
|
dim = true;
|
||||||
|
n_steps_ahead = 2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
move = {};
|
||||||
|
notify = {
|
||||||
|
content.format.__raw = ''
|
||||||
|
function(notif)
|
||||||
|
local formatted = MiniNotify.default_format(notif)
|
||||||
|
return '\n ' .. formatted:gsub('\n', ' \n ') .. ' \n'
|
||||||
|
end
|
||||||
|
'';
|
||||||
|
window.config = {
|
||||||
|
border = "none";
|
||||||
|
title = "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
pairs = {};
|
||||||
|
pick = {};
|
||||||
|
splitjoin = {};
|
||||||
|
starter = {};
|
||||||
|
statusline = {
|
||||||
|
content.active.__raw = ''
|
||||||
|
function()
|
||||||
|
local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 })
|
||||||
|
local diff = MiniStatusline.section_diff({ trunc_width = 75 })
|
||||||
|
local diagnostics = MiniStatusline.section_diagnostics({ trunc_width = 75 })
|
||||||
|
local lsp = MiniStatusline.section_lsp({ trunc_width = 75 })
|
||||||
|
local filename = MiniStatusline.section_filename({ trunc_width = 140 })
|
||||||
|
local search = MiniStatusline.section_searchcount({ trunc_width = 75 })
|
||||||
|
|
||||||
|
return _G.CschStatusline.active({
|
||||||
|
mode = mode,
|
||||||
|
mode_hl = mode_hl,
|
||||||
|
diff = diff,
|
||||||
|
diagnostics = diagnostics,
|
||||||
|
lsp = lsp,
|
||||||
|
filename = filename,
|
||||||
|
search = search,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
surround = {};
|
||||||
|
trailspace = {};
|
||||||
|
visits = {};
|
||||||
};
|
};
|
||||||
move = {};
|
mockDevIcons = true;
|
||||||
notify = {};
|
|
||||||
pairs = {};
|
|
||||||
pick = {};
|
|
||||||
splitjoin = {};
|
|
||||||
starter = {};
|
|
||||||
statusline = {};
|
|
||||||
surround = {};
|
|
||||||
trailspace = {};
|
|
||||||
visits = {};
|
|
||||||
};
|
};
|
||||||
mockDevIcons = true;
|
|
||||||
|
extraConfigLua = ''
|
||||||
|
local mini_notify_group = vim.api.nvim_create_augroup('MiniNotifyDesign', { clear = true })
|
||||||
|
_G.CschStatusline = _G.CschStatusline or {}
|
||||||
|
|
||||||
|
local function to_hex(value)
|
||||||
|
return value and string.format('#%06x', value) or nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_hl(name)
|
||||||
|
return vim.api.nvim_get_hl(0, { name = name, link = false })
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_fg(name, fallback)
|
||||||
|
return to_hex(get_hl(name).fg) or fallback
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_bg(name, fallback)
|
||||||
|
return to_hex(get_hl(name).bg) or fallback
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_statusline_highlights()
|
||||||
|
local block_bg = get_bg('CursorLine', get_bg('Visual', '#373b41'))
|
||||||
|
local block_fg = get_fg('StatusLine', get_fg('Normal', '#c5c8c6'))
|
||||||
|
|
||||||
|
vim.api.nvim_set_hl(0, 'CschStatuslineBlock', { fg = block_fg, bg = block_bg })
|
||||||
|
end
|
||||||
|
|
||||||
|
local function statusline_group(hl, strings)
|
||||||
|
local parts = vim.tbl_filter(function(x)
|
||||||
|
return type(x) == 'string' and x ~= ""
|
||||||
|
end, strings or {})
|
||||||
|
|
||||||
|
if #parts == 0 then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.format('%%#%s# %s ', hl, table.concat(parts, ' '))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function statusline_block(text, hl)
|
||||||
|
if text == nil or text == "" then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.format('%%#%s# %s ', hl, text)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function statusline_filesize()
|
||||||
|
local size = math.max(vim.fn.line2byte(vim.fn.line('$') + 1) - 1, 0)
|
||||||
|
|
||||||
|
if size < 1024 then
|
||||||
|
return string.format('%dB', size)
|
||||||
|
elseif size < 1048576 then
|
||||||
|
return string.format('%.2fKiB', size / 1024)
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.format('%.2fMiB', size / 1048576)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function statusline_filetype()
|
||||||
|
local filetype = vim.bo.filetype
|
||||||
|
|
||||||
|
if filetype == "" then
|
||||||
|
return vim.bo.buftype ~= "" and vim.bo.buftype or 'text'
|
||||||
|
end
|
||||||
|
|
||||||
|
local icon = ""
|
||||||
|
if _G.MiniIcons ~= nil then
|
||||||
|
icon = _G.MiniIcons.get('filetype', filetype) or ""
|
||||||
|
end
|
||||||
|
|
||||||
|
return (icon ~= "" and (icon .. ' ') or "") .. filetype
|
||||||
|
end
|
||||||
|
|
||||||
|
local function statusline_fileinfo()
|
||||||
|
local label = statusline_filetype()
|
||||||
|
|
||||||
|
if MiniStatusline.is_truncated(120) or vim.bo.buftype ~= "" then
|
||||||
|
return label
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.format('%s · %s', label, statusline_filesize())
|
||||||
|
end
|
||||||
|
|
||||||
|
local function statusline_location()
|
||||||
|
local line = vim.fn.line('.')
|
||||||
|
local total_lines = vim.fn.line('$')
|
||||||
|
local column = vim.fn.virtcol('.')
|
||||||
|
|
||||||
|
if MiniStatusline.is_truncated(90) then
|
||||||
|
return string.format('Ln %d Col %d', line, column)
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.format('Ln %d/%d · Col %d', line, total_lines, column)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _G.CschStatusline.active(parts)
|
||||||
|
local left = vim.tbl_filter(function(x)
|
||||||
|
return x ~= ""
|
||||||
|
end, {
|
||||||
|
statusline_block(parts.mode, parts.mode_hl),
|
||||||
|
statusline_group('MiniStatuslineDevinfo', { parts.diff, parts.diagnostics, parts.lsp }),
|
||||||
|
'%<',
|
||||||
|
statusline_group('MiniStatuslineFilename', { parts.filename }),
|
||||||
|
})
|
||||||
|
local right = vim.tbl_filter(function(x)
|
||||||
|
return x ~= ""
|
||||||
|
end, {
|
||||||
|
statusline_block(statusline_fileinfo(), 'CschStatuslineBlock'),
|
||||||
|
statusline_block(parts.search, 'CschStatuslineBlock'),
|
||||||
|
statusline_block(statusline_location(), parts.mode_hl),
|
||||||
|
})
|
||||||
|
|
||||||
|
return table.concat(left, "") .. '%=%#StatusLine#' .. table.concat(right, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_mini_notify_highlights()
|
||||||
|
local border = vim.api.nvim_get_hl(0, { name = 'FloatBorder' })
|
||||||
|
local normal = vim.api.nvim_get_hl(0, { name = 'NormalFloat' })
|
||||||
|
local popup_bg = get_bg('Pmenu', get_bg('CursorLine', get_bg('NormalFloat', '#303446')))
|
||||||
|
local title = vim.api.nvim_get_hl(0, { name = 'FloatTitle' })
|
||||||
|
|
||||||
|
border.bg = 'NONE'
|
||||||
|
normal.bg = popup_bg
|
||||||
|
normal.bold = true
|
||||||
|
title.bg = 'NONE'
|
||||||
|
|
||||||
|
vim.api.nvim_set_hl(0, 'MiniNotifyBorder', border)
|
||||||
|
vim.api.nvim_set_hl(0, 'MiniNotifyNormal', normal)
|
||||||
|
vim.api.nvim_set_hl(0, 'MiniNotifyTitle', title)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.api.nvim_create_autocmd('ColorScheme', {
|
||||||
|
group = mini_notify_group,
|
||||||
|
callback = function()
|
||||||
|
set_mini_notify_highlights()
|
||||||
|
set_statusline_highlights()
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
set_mini_notify_highlights()
|
||||||
|
set_statusline_highlights()
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,36 @@ in {
|
|||||||
render-markdown-nvim
|
render-markdown-nvim
|
||||||
];
|
];
|
||||||
extraConfigLua = ''
|
extraConfigLua = ''
|
||||||
|
local api = vim.api
|
||||||
|
local opencode_output_filetype = 'opencode_output'
|
||||||
|
local opencode_window_filetypes = {
|
||||||
|
opencode = true,
|
||||||
|
opencode_output = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local palette = {
|
||||||
|
base = '#faf4ed',
|
||||||
|
surface = '#fffaf3',
|
||||||
|
overlay = '#f2e9e1',
|
||||||
|
highlight_med = '#dfdad9',
|
||||||
|
text = '#575279',
|
||||||
|
subtle = '#797593',
|
||||||
|
muted = '#9893a5',
|
||||||
|
pine = '#286983',
|
||||||
|
iris = '#907aa9',
|
||||||
|
foam = '#56949f',
|
||||||
|
leaf = '#6d8f89',
|
||||||
|
gold = '#ea9d34',
|
||||||
|
rose = '#d7827e',
|
||||||
|
love = '#b4637a',
|
||||||
|
}
|
||||||
|
|
||||||
|
local function set_highlights(highlights)
|
||||||
|
for group, spec in pairs(highlights) do
|
||||||
|
api.nvim_set_hl(0, group, spec)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local opencode_markdown_conceal_query = vim.treesitter.query.parse('markdown_inline', [[
|
local opencode_markdown_conceal_query = vim.treesitter.query.parse('markdown_inline', [[
|
||||||
[
|
[
|
||||||
(emphasis_delimiter)
|
(emphasis_delimiter)
|
||||||
@@ -66,8 +96,28 @@ in {
|
|||||||
] @conceal)
|
] @conceal)
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
local function collect_conceal_marks(ctx)
|
||||||
|
local marks = {}
|
||||||
|
|
||||||
|
for _, node in opencode_markdown_conceal_query:iter_captures(ctx.root, ctx.buf) do
|
||||||
|
local start_row, start_col, end_row, end_col = node:range()
|
||||||
|
marks[#marks + 1] = {
|
||||||
|
conceal = true,
|
||||||
|
start_row = start_row,
|
||||||
|
start_col = start_col,
|
||||||
|
opts = {
|
||||||
|
end_row = end_row,
|
||||||
|
end_col = end_col,
|
||||||
|
conceal = "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return marks
|
||||||
|
end
|
||||||
|
|
||||||
local function set_opencode_output_conceal()
|
local function set_opencode_output_conceal()
|
||||||
if vim.bo.filetype ~= 'opencode_output' then
|
if vim.bo.filetype ~= opencode_output_filetype then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -75,101 +125,172 @@ in {
|
|||||||
vim.wo.concealcursor = 'nvic'
|
vim.wo.concealcursor = 'nvic'
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.treesitter.language.register('markdown', 'opencode_output')
|
local function hide_opencode_statusline()
|
||||||
vim.treesitter.language.register('markdown_inline', 'opencode_output')
|
if not opencode_window_filetypes[vim.bo.filetype] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd({ 'FileType', 'BufWinEnter', 'WinEnter' }, {
|
vim.wo.statusline = ' '
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.treesitter.language.register('markdown', opencode_output_filetype)
|
||||||
|
vim.treesitter.language.register('markdown_inline', opencode_output_filetype)
|
||||||
|
|
||||||
|
api.nvim_create_autocmd({ 'FileType', 'BufWinEnter', 'WinEnter' }, {
|
||||||
callback = set_opencode_output_conceal,
|
callback = set_opencode_output_conceal,
|
||||||
})
|
})
|
||||||
|
api.nvim_create_autocmd({ 'FileType', 'BufWinEnter', 'WinEnter', 'BufEnter' }, {
|
||||||
|
pattern = '*',
|
||||||
|
callback = hide_opencode_statusline,
|
||||||
|
})
|
||||||
|
|
||||||
require('render-markdown').setup({
|
set_highlights({
|
||||||
|
RenderMarkdownCode = { bg = palette.surface },
|
||||||
|
RenderMarkdownCodeBorder = { fg = palette.highlight_med, bg = palette.surface },
|
||||||
|
RenderMarkdownCodeInline = { bg = palette.surface },
|
||||||
|
RenderMarkdownH1 = { fg = palette.pine, bold = true },
|
||||||
|
RenderMarkdownH2 = { fg = palette.iris, bold = true },
|
||||||
|
RenderMarkdownH3 = { fg = palette.foam, bold = true },
|
||||||
|
RenderMarkdownH4 = { fg = palette.gold, bold = true },
|
||||||
|
OpencodeInputLegend = { fg = palette.subtle, bold = true },
|
||||||
|
OpencodeAgentBuild = { bg = palette.muted, fg = palette.base, bold = true },
|
||||||
|
})
|
||||||
|
|
||||||
|
local render_markdown_config = {
|
||||||
anti_conceal = { enabled = false },
|
anti_conceal = { enabled = false },
|
||||||
|
heading = {
|
||||||
|
icons = { '◆ ', '◇ ', '○ ', '· ', '· ', '· ' },
|
||||||
|
backgrounds = {},
|
||||||
|
position = 'inline',
|
||||||
|
width = 'block',
|
||||||
|
left_pad = 0,
|
||||||
|
right_pad = 2,
|
||||||
|
border = false,
|
||||||
|
sign = false,
|
||||||
|
},
|
||||||
|
code = {
|
||||||
|
sign = false,
|
||||||
|
width = 'full',
|
||||||
|
left_pad = 2,
|
||||||
|
right_pad = 0,
|
||||||
|
border = 'thin',
|
||||||
|
language_icon = false,
|
||||||
|
language_name = true,
|
||||||
|
},
|
||||||
|
bullet = {
|
||||||
|
icons = { '·', '–', '·', '–' },
|
||||||
|
},
|
||||||
custom_handlers = {
|
custom_handlers = {
|
||||||
markdown_inline = {
|
markdown_inline = {
|
||||||
extends = true,
|
extends = true,
|
||||||
parse = function(ctx)
|
parse = collect_conceal_marks,
|
||||||
local marks = {}
|
|
||||||
|
|
||||||
for _, node in opencode_markdown_conceal_query:iter_captures(ctx.root, ctx.buf) do
|
|
||||||
local start_row, start_col, end_row, end_col = node:range()
|
|
||||||
marks[#marks + 1] = {
|
|
||||||
conceal = true,
|
|
||||||
start_row = start_row,
|
|
||||||
start_col = start_col,
|
|
||||||
opts = {
|
|
||||||
end_row = end_row,
|
|
||||||
end_col = end_col,
|
|
||||||
conceal = "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return marks
|
|
||||||
end,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
file_types = { 'opencode_output' },
|
file_types = { opencode_output_filetype },
|
||||||
win_options = {
|
win_options = {
|
||||||
conceallevel = { rendered = 3 },
|
conceallevel = { rendered = 3 },
|
||||||
concealcursor = { rendered = "nvic" },
|
concealcursor = { rendered = 'nvic' },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
require('render-markdown').setup(render_markdown_config)
|
||||||
|
|
||||||
|
local opencode_icon_overrides = {
|
||||||
|
header_user = '│',
|
||||||
|
header_assistant = '│',
|
||||||
|
run = '▸',
|
||||||
|
task = '◦',
|
||||||
|
read = '◦',
|
||||||
|
edit = '◦',
|
||||||
|
write = '◦',
|
||||||
|
plan = '◦',
|
||||||
|
search = '◦',
|
||||||
|
web = '◦',
|
||||||
|
list = '◦',
|
||||||
|
tool = '◦',
|
||||||
|
snapshot = '◦',
|
||||||
|
restore_point = '◦',
|
||||||
|
file = '·',
|
||||||
|
folder = '·',
|
||||||
|
attached_file = '·',
|
||||||
|
agent = '·',
|
||||||
|
reference = '·',
|
||||||
|
reasoning = '◦',
|
||||||
|
question = '?',
|
||||||
|
border = '│',
|
||||||
|
}
|
||||||
|
|
||||||
|
require('opencode').setup({
|
||||||
|
server = {
|
||||||
|
url = 'http://127.0.0.1',
|
||||||
|
port = 18822,
|
||||||
|
auto_kill = false,
|
||||||
|
},
|
||||||
|
input = {
|
||||||
|
text = {
|
||||||
|
wrap = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
debug = {
|
||||||
|
show_ids = false,
|
||||||
|
},
|
||||||
|
ui = {
|
||||||
|
icons = {
|
||||||
|
preset = 'nerdfonts',
|
||||||
|
overrides = opencode_icon_overrides,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require('opencode').setup({
|
|
||||||
server = {
|
|
||||||
url = 'http://127.0.0.1',
|
|
||||||
port = 18822,
|
|
||||||
auto_kill = false,
|
|
||||||
},
|
|
||||||
input = {
|
|
||||||
text = {
|
|
||||||
wrap = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ui = {
|
|
||||||
icons = {
|
|
||||||
preset = 'nerdfonts',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
do
|
do
|
||||||
local config = require('opencode.config')
|
local config = require('opencode.config')
|
||||||
local formatter = require('opencode.ui.formatter')
|
local formatter = require('opencode.ui.formatter')
|
||||||
local format_utils = require('opencode.ui.formatter.utils')
|
local format_utils = require('opencode.ui.formatter.utils')
|
||||||
local icons = require('opencode.ui.icons')
|
local icons = require('opencode.ui.icons')
|
||||||
local util = require('opencode.util')
|
local util = require('opencode.util')
|
||||||
|
|
||||||
formatter._format_reasoning = function(output, part)
|
local function format_reasoning_title(part)
|
||||||
local text = vim.trim(part.text or "")
|
local title = 'Reasoning'
|
||||||
local start_line = output:get_line_count() + 1
|
local time = part.time
|
||||||
|
|
||||||
local title = 'Reasoning'
|
if time and type(time) == 'table' and time.start then
|
||||||
local time = part.time
|
local duration_text = util.format_duration_seconds(time.start, time['end'])
|
||||||
if time and type(time) == 'table' and time.start then
|
if duration_text then
|
||||||
local duration_text = util.format_duration_seconds(time.start, time['end'])
|
title = string.format('%s %s', title, duration_text)
|
||||||
if duration_text then
|
|
||||||
title = string.format('%s %s', title, duration_text)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
format_utils.format_action(output, icons.get('reasoning'), title, "")
|
|
||||||
|
|
||||||
if config.ui.output.tools.show_reasoning_output and text ~= "" then
|
|
||||||
output:add_empty_line()
|
|
||||||
output:add_lines(vim.split(text, '\n'), ' ')
|
|
||||||
output:add_empty_line()
|
|
||||||
end
|
|
||||||
|
|
||||||
local end_line = output:get_line_count()
|
|
||||||
if end_line - start_line > 1 then
|
|
||||||
formatter.add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')
|
|
||||||
else
|
|
||||||
output:add_extmark(start_line - 1, {
|
|
||||||
line_hl_group = 'OpencodeReasoningText',
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return title
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function highlight_reasoning_block(output, start_line)
|
||||||
|
local end_line = output:get_line_count()
|
||||||
|
|
||||||
|
if end_line - start_line > 1 then
|
||||||
|
formatter.add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
output:add_extmark(start_line - 1, {
|
||||||
|
line_hl_group = 'OpencodeReasoningText',
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
formatter._format_reasoning = function(output, part)
|
||||||
|
local text = vim.trim(part.text or "")
|
||||||
|
local start_line = output:get_line_count() + 1
|
||||||
|
|
||||||
|
format_utils.format_action(output, icons.get('reasoning'), format_reasoning_title(part), "")
|
||||||
|
|
||||||
|
if config.ui.output.tools.show_reasoning_output and text ~= "" then
|
||||||
|
output:add_empty_line()
|
||||||
|
output:add_lines(vim.split(text, '\n'), ' ')
|
||||||
|
output:add_empty_line()
|
||||||
|
end
|
||||||
|
|
||||||
|
highlight_reasoning_block(output, start_line)
|
||||||
|
end
|
||||||
|
end
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,26 @@
|
|||||||
end, { force = true, all = true })
|
end, { force = true, all = true })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Fix grammar-bundled treesitter queries that use #match? with Lua pattern
|
||||||
|
-- syntax (e.g. %d) instead of Vim regex. Neovim 0.11 picks the first
|
||||||
|
-- non-extending query file in the rtp as the base, so the grammar-bundled
|
||||||
|
-- (buggy) queries take precedence over the corrected site-level queries.
|
||||||
|
-- Override affected languages with the site-level version.
|
||||||
|
do
|
||||||
|
local langs = { "sql" }
|
||||||
|
for _, lang in ipairs(langs) do
|
||||||
|
local files = vim.api.nvim_get_runtime_file(
|
||||||
|
"queries/" .. lang .. "/highlights.scm", true)
|
||||||
|
if #files > 1 then
|
||||||
|
local f = io.open(files[#files])
|
||||||
|
if f then
|
||||||
|
vim.treesitter.query.set(lang, "highlights", f:read("*all"))
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
settings = {
|
settings = {
|
||||||
model = "anthropic/claude-opus-4-6";
|
model = "anthropic/claude-opus-4-6";
|
||||||
small_model = "anthropic/claude-haiku-4-5";
|
small_model = "anthropic/claude-haiku-4-5";
|
||||||
theme = "catppuccin";
|
theme = "rosepine";
|
||||||
plugin = ["opencode-anthropic-auth@latest"];
|
plugin = ["opencode-anthropic-auth@latest"];
|
||||||
permission = {
|
permission = {
|
||||||
read = {
|
read = {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
nix = {
|
nix = {
|
||||||
settings.trusted-users = ["@admin" "cschmatzler"];
|
settings.trusted-users = ["cschmatzler"];
|
||||||
gc.interval = {
|
gc.interval = {
|
||||||
Weekday = 0;
|
Weekday = 0;
|
||||||
Hour = 2;
|
Hour = 2;
|
||||||
|
|||||||
@@ -23,16 +23,19 @@
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
flake.flakeModules = {
|
flake.flakeModules = {
|
||||||
|
# Shared system foundations
|
||||||
|
core = ./core.nix;
|
||||||
|
network = ./network.nix;
|
||||||
|
nixos-system = ./nixos-system.nix;
|
||||||
|
|
||||||
|
# User environment
|
||||||
ai-tools = ./ai-tools.nix;
|
ai-tools = ./ai-tools.nix;
|
||||||
atuin = ./atuin.nix;
|
atuin = ./atuin.nix;
|
||||||
core = ./core.nix;
|
|
||||||
desktop = ./desktop.nix;
|
desktop = ./desktop.nix;
|
||||||
dev-tools = ./dev-tools.nix;
|
dev-tools = ./dev-tools.nix;
|
||||||
email = ./email.nix;
|
email = ./email.nix;
|
||||||
finance = ./finance.nix;
|
finance = ./finance.nix;
|
||||||
neovim = ./neovim.nix;
|
neovim = ./neovim.nix;
|
||||||
network = ./network.nix;
|
|
||||||
nixos-system = ./nixos-system.nix;
|
|
||||||
shell = ./shell.nix;
|
shell = ./shell.nix;
|
||||||
ssh-client = ./ssh-client.nix;
|
ssh-client = ./ssh-client.nix;
|
||||||
terminal = ./terminal.nix;
|
terminal = ./terminal.nix;
|
||||||
|
|||||||
@@ -316,36 +316,36 @@
|
|||||||
|
|
||||||
gui = {
|
gui = {
|
||||||
authorColors = {
|
authorColors = {
|
||||||
"*" = "#7287fd";
|
"*" = "#907aa9";
|
||||||
};
|
};
|
||||||
theme = {
|
theme = {
|
||||||
activeBorderColor = [
|
activeBorderColor = [
|
||||||
"#8839ef"
|
"#907aa9"
|
||||||
"bold"
|
"bold"
|
||||||
];
|
];
|
||||||
inactiveBorderColor = [
|
inactiveBorderColor = [
|
||||||
"#6c6f85"
|
"#9893a5"
|
||||||
];
|
];
|
||||||
optionsTextColor = [
|
optionsTextColor = [
|
||||||
"#1e66f5"
|
"#286983"
|
||||||
];
|
];
|
||||||
selectedLineBgColor = [
|
selectedLineBgColor = [
|
||||||
"#ccd0da"
|
"#f2e9e1"
|
||||||
];
|
];
|
||||||
cherryPickedCommitBgColor = [
|
cherryPickedCommitBgColor = [
|
||||||
"#bcc0cc"
|
"#dfdad9"
|
||||||
];
|
];
|
||||||
cherryPickedCommitFgColor = [
|
cherryPickedCommitFgColor = [
|
||||||
"#8839ef"
|
"#907aa9"
|
||||||
];
|
];
|
||||||
defaultFgColor = [
|
defaultFgColor = [
|
||||||
"#4c4f69"
|
"#575279"
|
||||||
];
|
];
|
||||||
searchingActiveBorderColor = [
|
searchingActiveBorderColor = [
|
||||||
"#df8e1d"
|
"#ea9d34"
|
||||||
];
|
];
|
||||||
unstagedChangesColor = [
|
unstagedChangesColor = [
|
||||||
"#d20f39"
|
"#b4637a"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -378,21 +378,23 @@
|
|||||||
ast-grep
|
ast-grep
|
||||||
bun
|
bun
|
||||||
delta
|
delta
|
||||||
|
deadnix
|
||||||
devenv
|
devenv
|
||||||
docker
|
docker
|
||||||
docker-compose
|
docker-compose
|
||||||
gh
|
gh
|
||||||
git
|
|
||||||
gnumake
|
gnumake
|
||||||
hyperfine
|
hyperfine
|
||||||
jj-ryu
|
jj-ryu
|
||||||
jj-starship
|
jj-starship
|
||||||
|
nil
|
||||||
nodejs_24
|
nodejs_24
|
||||||
nurl
|
nurl
|
||||||
pnpm
|
pnpm
|
||||||
postgresql_17
|
postgresql_17
|
||||||
serie
|
serie
|
||||||
sqlite
|
sqlite
|
||||||
|
statix
|
||||||
tea
|
tea
|
||||||
tokei
|
tokei
|
||||||
tree-sitter
|
tree-sitter
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
address = "christoph@schmatzler.com";
|
address = "christoph@schmatzler.com";
|
||||||
userName = "christoph.schmatzler@icloud.com";
|
userName = "christoph.schmatzler@icloud.com";
|
||||||
realName = "Christoph Schmatzler";
|
realName = "Christoph Schmatzler";
|
||||||
passwordCommand = ["cat" "/run/secrets/tahani-email-password"];
|
passwordCommand = ["${pkgs.coreutils}/bin/cat" "/run/secrets/tahani-email-password"];
|
||||||
folders = {
|
folders = {
|
||||||
inbox = "INBOX";
|
inbox = "INBOX";
|
||||||
drafts = "Drafts";
|
drafts = "Drafts";
|
||||||
|
|||||||
@@ -11,180 +11,16 @@
|
|||||||
den.aspects.tailscale
|
den.aspects.tailscale
|
||||||
];
|
];
|
||||||
|
|
||||||
den.aspects.michael.nixos = {
|
den.aspects.michael.nixos = {modulesPath, ...}: {
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
modulesPath,
|
|
||||||
...
|
|
||||||
}: {
|
|
||||||
imports = [
|
imports = [
|
||||||
(modulesPath + "/installer/scan/not-detected.nix")
|
(modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
./_hosts/michael/backups.nix
|
||||||
./_hosts/michael/disk-config.nix
|
./_hosts/michael/disk-config.nix
|
||||||
|
./_hosts/michael/gitea.nix
|
||||||
./_hosts/michael/hardware-configuration.nix
|
./_hosts/michael/hardware-configuration.nix
|
||||||
inputs.disko.nixosModules.default
|
inputs.disko.nixosModules.default
|
||||||
];
|
];
|
||||||
|
|
||||||
networking.hostName = "michael";
|
networking.hostName = "michael";
|
||||||
|
|
||||||
sops.secrets = {
|
|
||||||
michael-gitea-litestream = {
|
|
||||||
sopsFile = ../secrets/michael-gitea-litestream;
|
|
||||||
format = "binary";
|
|
||||||
owner = "gitea";
|
|
||||||
group = "gitea";
|
|
||||||
};
|
|
||||||
michael-gitea-restic-password = {
|
|
||||||
sopsFile = ../secrets/michael-gitea-restic-password;
|
|
||||||
format = "binary";
|
|
||||||
owner = "gitea";
|
|
||||||
group = "gitea";
|
|
||||||
};
|
|
||||||
michael-gitea-restic-env = {
|
|
||||||
sopsFile = ../secrets/michael-gitea-restic-env;
|
|
||||||
format = "binary";
|
|
||||||
owner = "gitea";
|
|
||||||
group = "gitea";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [80 443];
|
|
||||||
|
|
||||||
services.redis.servers.gitea = {
|
|
||||||
enable = true;
|
|
||||||
port = 6380;
|
|
||||||
bind = "127.0.0.1";
|
|
||||||
settings = {
|
|
||||||
maxmemory = "64mb";
|
|
||||||
maxmemory-policy = "allkeys-lru";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.gitea = {
|
|
||||||
enable = true;
|
|
||||||
database = {
|
|
||||||
type = "sqlite3";
|
|
||||||
path = "/var/lib/gitea/data/gitea.db";
|
|
||||||
};
|
|
||||||
settings = {
|
|
||||||
server = {
|
|
||||||
ROOT_URL = "https://git.schmatzler.com/";
|
|
||||||
DOMAIN = "git.schmatzler.com";
|
|
||||||
HTTP_ADDR = "127.0.0.1";
|
|
||||||
HTTP_PORT = 3000;
|
|
||||||
LANDING_PAGE = "explore";
|
|
||||||
};
|
|
||||||
service.DISABLE_REGISTRATION = true;
|
|
||||||
security.INSTALL_LOCK = true;
|
|
||||||
cache = {
|
|
||||||
ADAPTER = "redis";
|
|
||||||
HOST = "redis://127.0.0.1:6380/0?pool_size=100&idle_timeout=180s";
|
|
||||||
ITEM_TTL = "16h";
|
|
||||||
};
|
|
||||||
"cache.last_commit" = {
|
|
||||||
ITEM_TTL = "8760h";
|
|
||||||
COMMITS_COUNT = 100;
|
|
||||||
};
|
|
||||||
session = {
|
|
||||||
PROVIDER = "redis";
|
|
||||||
PROVIDER_CONFIG = "redis://127.0.0.1:6380/1?pool_size=100&idle_timeout=180s";
|
|
||||||
COOKIE_SECURE = true;
|
|
||||||
SAME_SITE = "strict";
|
|
||||||
};
|
|
||||||
api.ENABLE_SWAGGER = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.litestream = {
|
|
||||||
enable = true;
|
|
||||||
environmentFile = config.sops.secrets.michael-gitea-litestream.path;
|
|
||||||
settings = {
|
|
||||||
dbs = [
|
|
||||||
{
|
|
||||||
path = "/var/lib/gitea/data/gitea.db";
|
|
||||||
replicas = [
|
|
||||||
{
|
|
||||||
type = "s3";
|
|
||||||
bucket = "michael-gitea-litestream";
|
|
||||||
path = "gitea";
|
|
||||||
endpoint = "s3.eu-central-003.backblazeb2.com";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.litestream = {
|
|
||||||
serviceConfig = {
|
|
||||||
User = lib.mkForce "gitea";
|
|
||||||
Group = lib.mkForce "gitea";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.caddy = {
|
|
||||||
enable = true;
|
|
||||||
virtualHosts."git.schmatzler.com".extraConfig = ''
|
|
||||||
header {
|
|
||||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
||||||
X-Content-Type-Options "nosniff"
|
|
||||||
X-Frame-Options "DENY"
|
|
||||||
Referrer-Policy "strict-origin-when-cross-origin"
|
|
||||||
}
|
|
||||||
reverse_proxy localhost:3000
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
services.restic.backups.gitea = {
|
|
||||||
repository = "s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories";
|
|
||||||
paths = ["/var/lib/gitea"];
|
|
||||||
exclude = [
|
|
||||||
"/var/lib/gitea/log"
|
|
||||||
"/var/lib/gitea/data/gitea.db"
|
|
||||||
"/var/lib/gitea/data/gitea.db-shm"
|
|
||||||
"/var/lib/gitea/data/gitea.db-wal"
|
|
||||||
];
|
|
||||||
passwordFile = config.sops.secrets.michael-gitea-restic-password.path;
|
|
||||||
environmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
|
||||||
pruneOpts = [
|
|
||||||
"--keep-daily 7"
|
|
||||||
"--keep-weekly 4"
|
|
||||||
"--keep-monthly 6"
|
|
||||||
];
|
|
||||||
timerConfig = {
|
|
||||||
OnCalendar = "daily";
|
|
||||||
Persistent = true;
|
|
||||||
RandomizedDelaySec = "1h";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.restic-backups-gitea = {
|
|
||||||
wants = ["restic-init-gitea.service"];
|
|
||||||
after = ["restic-init-gitea.service"];
|
|
||||||
serviceConfig = {
|
|
||||||
User = lib.mkForce "gitea";
|
|
||||||
Group = lib.mkForce "gitea";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.restic-init-gitea = {
|
|
||||||
description = "Initialize Restic repository for Gitea backups";
|
|
||||||
wantedBy = ["multi-user.target"];
|
|
||||||
after = ["network-online.target"];
|
|
||||||
wants = ["network-online.target"];
|
|
||||||
path = [pkgs.restic];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
User = "gitea";
|
|
||||||
Group = "gitea";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
EnvironmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
export RESTIC_PASSWORD=$(cat ${config.sops.secrets.michael-gitea-restic-password.path})
|
|
||||||
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories snapshots &>/dev/null || \
|
|
||||||
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories init
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
extraEnv =
|
extraEnv =
|
||||||
''
|
''
|
||||||
$env.LS_COLORS = (${pkgs.vivid}/bin/vivid generate catppuccin-latte)
|
$env.LS_COLORS = (${pkgs.vivid}/bin/vivid generate rose-pine-dawn)
|
||||||
''
|
''
|
||||||
+ lib.optionalString pkgs.stdenv.isDarwin ''
|
+ lib.optionalString pkgs.stdenv.isDarwin ''
|
||||||
# Nushell on Darwin doesn't source /etc/zprofile or path_helper,
|
# Nushell on Darwin doesn't source /etc/zprofile or path_helper,
|
||||||
@@ -36,65 +36,55 @@
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
# --- Catppuccin Latte Theme ---
|
# --- Rosé Pine Dawn Theme ---
|
||||||
let theme = {
|
let theme = {
|
||||||
rosewater: "#dc8a78"
|
love: "#b4637a"
|
||||||
flamingo: "#dd7878"
|
gold: "#ea9d34"
|
||||||
pink: "#ea76cb"
|
rose: "#d7827e"
|
||||||
mauve: "#8839ef"
|
pine: "#286983"
|
||||||
red: "#d20f39"
|
foam: "#56949f"
|
||||||
maroon: "#e64553"
|
iris: "#907aa9"
|
||||||
peach: "#fe640b"
|
leaf: "#6d8f89"
|
||||||
yellow: "#df8e1d"
|
text: "#575279"
|
||||||
green: "#40a02b"
|
subtle: "#797593"
|
||||||
teal: "#179299"
|
muted: "#9893a5"
|
||||||
sky: "#04a5e5"
|
highlight_high: "#cecacd"
|
||||||
sapphire: "#209fb5"
|
highlight_med: "#dfdad9"
|
||||||
blue: "#1e66f5"
|
highlight_low: "#f4ede8"
|
||||||
lavender: "#7287fd"
|
overlay: "#f2e9e1"
|
||||||
text: "#4c4f69"
|
surface: "#fffaf3"
|
||||||
subtext1: "#5c5f77"
|
base: "#faf4ed"
|
||||||
subtext0: "#6c6f85"
|
|
||||||
overlay2: "#7c7f93"
|
|
||||||
overlay1: "#8c8fa1"
|
|
||||||
overlay0: "#9ca0b0"
|
|
||||||
surface2: "#acb0be"
|
|
||||||
surface1: "#bcc0cc"
|
|
||||||
surface0: "#ccd0da"
|
|
||||||
base: "#eff1f5"
|
|
||||||
mantle: "#e6e9ef"
|
|
||||||
crust: "#dce0e8"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let scheme = {
|
let scheme = {
|
||||||
recognized_command: $theme.blue
|
recognized_command: $theme.pine
|
||||||
unrecognized_command: $theme.text
|
unrecognized_command: $theme.text
|
||||||
constant: $theme.peach
|
constant: $theme.gold
|
||||||
punctuation: $theme.overlay2
|
punctuation: $theme.muted
|
||||||
operator: $theme.sky
|
operator: $theme.subtle
|
||||||
string: $theme.green
|
string: $theme.gold
|
||||||
virtual_text: $theme.surface2
|
virtual_text: $theme.highlight_high
|
||||||
variable: { fg: $theme.flamingo attr: i }
|
variable: { fg: $theme.rose attr: i }
|
||||||
filepath: $theme.yellow
|
filepath: $theme.iris
|
||||||
}
|
}
|
||||||
|
|
||||||
$env.config.color_config = {
|
$env.config.color_config = {
|
||||||
separator: { fg: $theme.surface2 attr: b }
|
separator: { fg: $theme.highlight_high attr: b }
|
||||||
leading_trailing_space_bg: { fg: $theme.lavender attr: u }
|
leading_trailing_space_bg: { fg: $theme.iris attr: u }
|
||||||
header: { fg: $theme.text attr: b }
|
header: { fg: $theme.text attr: b }
|
||||||
row_index: $scheme.virtual_text
|
row_index: $scheme.virtual_text
|
||||||
record: $theme.text
|
record: $theme.text
|
||||||
list: $theme.text
|
list: $theme.text
|
||||||
hints: $scheme.virtual_text
|
hints: $scheme.virtual_text
|
||||||
search_result: { fg: $theme.base bg: $theme.yellow }
|
search_result: { fg: $theme.base bg: $theme.gold }
|
||||||
shape_closure: $theme.teal
|
shape_closure: $theme.foam
|
||||||
closure: $theme.teal
|
closure: $theme.foam
|
||||||
shape_flag: { fg: $theme.maroon attr: i }
|
shape_flag: { fg: $theme.love attr: i }
|
||||||
shape_matching_brackets: { attr: u }
|
shape_matching_brackets: { attr: u }
|
||||||
shape_garbage: $theme.red
|
shape_garbage: $theme.love
|
||||||
shape_keyword: $theme.mauve
|
shape_keyword: $theme.iris
|
||||||
shape_match_pattern: $theme.green
|
shape_match_pattern: $theme.leaf
|
||||||
shape_signature: $theme.teal
|
shape_signature: $theme.foam
|
||||||
shape_table: $scheme.punctuation
|
shape_table: $scheme.punctuation
|
||||||
cell-path: $scheme.punctuation
|
cell-path: $scheme.punctuation
|
||||||
shape_list: $scheme.punctuation
|
shape_list: $scheme.punctuation
|
||||||
@@ -104,53 +94,53 @@
|
|||||||
empty: { attr: n }
|
empty: { attr: n }
|
||||||
filesize: {||
|
filesize: {||
|
||||||
if $in < 1kb {
|
if $in < 1kb {
|
||||||
$theme.teal
|
$theme.foam
|
||||||
} else if $in < 10kb {
|
} else if $in < 10kb {
|
||||||
$theme.green
|
$theme.leaf
|
||||||
} else if $in < 100kb {
|
} else if $in < 100kb {
|
||||||
$theme.yellow
|
$theme.gold
|
||||||
} else if $in < 10mb {
|
} else if $in < 10mb {
|
||||||
$theme.peach
|
$theme.rose
|
||||||
} else if $in < 100mb {
|
} else if $in < 100mb {
|
||||||
$theme.maroon
|
$theme.love
|
||||||
} else if $in < 1gb {
|
} else if $in < 1gb {
|
||||||
$theme.red
|
$theme.love
|
||||||
} else {
|
} else {
|
||||||
$theme.mauve
|
$theme.iris
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
duration: {||
|
duration: {||
|
||||||
if $in < 1day {
|
if $in < 1day {
|
||||||
$theme.teal
|
$theme.foam
|
||||||
} else if $in < 1wk {
|
} else if $in < 1wk {
|
||||||
$theme.green
|
$theme.leaf
|
||||||
} else if $in < 4wk {
|
} else if $in < 4wk {
|
||||||
$theme.yellow
|
$theme.gold
|
||||||
} else if $in < 12wk {
|
} else if $in < 12wk {
|
||||||
$theme.peach
|
$theme.rose
|
||||||
} else if $in < 24wk {
|
} else if $in < 24wk {
|
||||||
$theme.maroon
|
$theme.love
|
||||||
} else if $in < 52wk {
|
} else if $in < 52wk {
|
||||||
$theme.red
|
$theme.love
|
||||||
} else {
|
} else {
|
||||||
$theme.mauve
|
$theme.iris
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
datetime: {|| (date now) - $in |
|
datetime: {|| (date now) - $in |
|
||||||
if $in < 1day {
|
if $in < 1day {
|
||||||
$theme.teal
|
$theme.foam
|
||||||
} else if $in < 1wk {
|
} else if $in < 1wk {
|
||||||
$theme.green
|
$theme.leaf
|
||||||
} else if $in < 4wk {
|
} else if $in < 4wk {
|
||||||
$theme.yellow
|
$theme.gold
|
||||||
} else if $in < 12wk {
|
} else if $in < 12wk {
|
||||||
$theme.peach
|
$theme.rose
|
||||||
} else if $in < 24wk {
|
} else if $in < 24wk {
|
||||||
$theme.maroon
|
$theme.love
|
||||||
} else if $in < 52wk {
|
} else if $in < 52wk {
|
||||||
$theme.red
|
$theme.love
|
||||||
} else {
|
} else {
|
||||||
$theme.mauve
|
$theme.iris
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shape_external: $scheme.unrecognized_command
|
shape_external: $scheme.unrecognized_command
|
||||||
@@ -158,11 +148,11 @@
|
|||||||
shape_external_resolved: $scheme.recognized_command
|
shape_external_resolved: $scheme.recognized_command
|
||||||
shape_block: $scheme.recognized_command
|
shape_block: $scheme.recognized_command
|
||||||
block: $scheme.recognized_command
|
block: $scheme.recognized_command
|
||||||
shape_custom: $theme.pink
|
shape_custom: $theme.rose
|
||||||
custom: $theme.pink
|
custom: $theme.rose
|
||||||
background: $theme.base
|
background: $theme.base
|
||||||
foreground: $theme.text
|
foreground: $theme.text
|
||||||
cursor: { bg: $theme.rosewater fg: $theme.base }
|
cursor: { bg: $theme.text fg: $theme.base }
|
||||||
shape_range: $scheme.operator
|
shape_range: $scheme.operator
|
||||||
range: $scheme.operator
|
range: $scheme.operator
|
||||||
shape_pipe: $scheme.operator
|
shape_pipe: $scheme.operator
|
||||||
@@ -187,51 +177,51 @@
|
|||||||
shape_literal: $scheme.constant
|
shape_literal: $scheme.constant
|
||||||
string: $scheme.string
|
string: $scheme.string
|
||||||
shape_string: $scheme.string
|
shape_string: $scheme.string
|
||||||
shape_string_interpolation: $theme.flamingo
|
shape_string_interpolation: $theme.rose
|
||||||
shape_raw_string: $scheme.string
|
shape_raw_string: $scheme.string
|
||||||
shape_externalarg: $scheme.string
|
shape_externalarg: $scheme.string
|
||||||
}
|
}
|
||||||
$env.config.highlight_resolved_externals = true
|
$env.config.highlight_resolved_externals = true
|
||||||
$env.config.explore = {
|
$env.config.explore = {
|
||||||
status_bar_background: { fg: $theme.text, bg: $theme.mantle },
|
status_bar_background: { fg: $theme.text, bg: $theme.surface },
|
||||||
command_bar_text: { fg: $theme.text },
|
command_bar_text: { fg: $theme.text },
|
||||||
highlight: { fg: $theme.base, bg: $theme.yellow },
|
highlight: { fg: $theme.base, bg: $theme.gold },
|
||||||
status: {
|
status: {
|
||||||
error: $theme.red,
|
error: $theme.love,
|
||||||
warn: $theme.yellow,
|
warn: $theme.gold,
|
||||||
info: $theme.blue,
|
info: $theme.pine,
|
||||||
},
|
},
|
||||||
selected_cell: { bg: $theme.blue fg: $theme.base },
|
selected_cell: { bg: $theme.pine fg: $theme.base },
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Custom Commands ---
|
# --- Custom Commands ---
|
||||||
def --env open_project [] {
|
def --env open_project [] {
|
||||||
let base = ($env.HOME | path join "Projects")
|
let base = ($env.HOME | path join "Projects")
|
||||||
let choice = (
|
let choice = (
|
||||||
${pkgs.fd}/bin/fd -t d -d 1 -a . ($base | path join "Personal") ($base | path join "Work")
|
${pkgs.fd}/bin/fd -t d -d 1 -a . ($base | path join "Personal") ($base | path join "Work")
|
||||||
| lines
|
| lines
|
||||||
| each {|p| $p | str replace $"($base)/" "" }
|
| each {|p| $p | str replace $"($base)/" "" }
|
||||||
| str join "\n"
|
| str join "\n"
|
||||||
| ${pkgs.fzf}/bin/fzf --prompt "project > "
|
| ${pkgs.fzf}/bin/fzf --prompt "project > "
|
||||||
)
|
)
|
||||||
if ($choice | str trim | is-not-empty) {
|
if ($choice | str trim | is-not-empty) {
|
||||||
cd ($base | path join ($choice | str trim))
|
cd ($base | path join ($choice | str trim))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Keybinding: Ctrl+O for open_project ---
|
|
||||||
$env.config.keybindings = ($env.config.keybindings | append [
|
|
||||||
{
|
|
||||||
name: open_project
|
|
||||||
modifier: control
|
|
||||||
keycode: char_o
|
|
||||||
mode: [emacs vi_insert vi_normal]
|
|
||||||
event: {
|
|
||||||
send: executehostcommand
|
|
||||||
cmd: "open_project"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
|
||||||
|
# --- Keybinding: Ctrl+O for open_project ---
|
||||||
|
$env.config.keybindings = ($env.config.keybindings | append [
|
||||||
|
{
|
||||||
|
name: open_project
|
||||||
|
modifier: control
|
||||||
|
keycode: char_o
|
||||||
|
mode: [emacs vi_insert vi_normal]
|
||||||
|
event: {
|
||||||
|
send: executehostcommand
|
||||||
|
cmd: "open_project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -284,7 +274,6 @@
|
|||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
vivid
|
vivid
|
||||||
(callPackage ./_lib/open-project.nix {})
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
{...}: {
|
{...}: {
|
||||||
den.aspects.ssh-client.homeManager = {
|
den.aspects.ssh-client.homeManager = {
|
||||||
config,
|
config,
|
||||||
lib,
|
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: {
|
}: let
|
||||||
|
homeDir = "${
|
||||||
|
if pkgs.stdenv.hostPlatform.isDarwin
|
||||||
|
then "/Users"
|
||||||
|
else "/home"
|
||||||
|
}/${config.home.username}";
|
||||||
|
in {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableDefaultConfig = false;
|
enableDefaultConfig = false;
|
||||||
includes = [
|
includes = [
|
||||||
(lib.mkIf pkgs.stdenv.hostPlatform.isLinux "/home/${config.home.username}/.ssh/config_external")
|
"${homeDir}/.ssh/config_external"
|
||||||
(lib.mkIf pkgs.stdenv.hostPlatform.isDarwin "/Users/${config.home.username}/.ssh/config_external")
|
|
||||||
];
|
];
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
"*" = {};
|
"*" = {};
|
||||||
"github.com" = {
|
"github.com" = {
|
||||||
identitiesOnly = true;
|
identitiesOnly = true;
|
||||||
identityFile = [
|
identityFile = [
|
||||||
(lib.mkIf pkgs.stdenv.hostPlatform.isLinux "/home/${config.home.username}/.ssh/id_ed25519")
|
"${homeDir}/.ssh/id_ed25519"
|
||||||
(lib.mkIf pkgs.stdenv.hostPlatform.isDarwin "/Users/${config.home.username}/.ssh/id_ed25519")
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
home.packages = [pkgs.openssh];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,13 @@
|
|||||||
tahani-paperless-password = {
|
tahani-paperless-password = {
|
||||||
sopsFile = ../secrets/tahani-paperless-password;
|
sopsFile = ../secrets/tahani-paperless-password;
|
||||||
format = "binary";
|
format = "binary";
|
||||||
|
path = "/run/secrets/tahani-paperless-password";
|
||||||
};
|
};
|
||||||
tahani-email-password = {
|
tahani-email-password = {
|
||||||
sopsFile = ../secrets/tahani-email-password;
|
sopsFile = ../secrets/tahani-email-password;
|
||||||
format = "binary";
|
format = "binary";
|
||||||
owner = "cschmatzler";
|
owner = "cschmatzler";
|
||||||
|
path = "/run/secrets/tahani-email-password";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
virtualisation.docker.enable = true;
|
virtualisation.docker.enable = true;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
}: {
|
}: {
|
||||||
xdg.configFile."ghostty/config".text = ''
|
xdg.configFile."ghostty/config".text = ''
|
||||||
command = ${pkgs.nushell}/bin/nu
|
command = ${pkgs.nushell}/bin/nu
|
||||||
theme = Catppuccin Latte
|
theme = Rose Pine Dawn
|
||||||
window-padding-x = 12
|
window-padding-x = 12
|
||||||
window-padding-y = 3
|
window-padding-y = 3
|
||||||
window-padding-balance = true
|
window-padding-balance = true
|
||||||
@@ -24,19 +24,19 @@
|
|||||||
programs.bat = {
|
programs.bat = {
|
||||||
enable = true;
|
enable = true;
|
||||||
config = {
|
config = {
|
||||||
theme = "Catppuccin Latte";
|
theme = "Rosé Pine Dawn";
|
||||||
pager = "ov";
|
pager = "ov";
|
||||||
};
|
};
|
||||||
themes = {
|
themes = {
|
||||||
"Catppuccin Latte" = {
|
"Rosé Pine Dawn" = {
|
||||||
src =
|
src =
|
||||||
pkgs.fetchFromGitHub {
|
pkgs.fetchFromGitHub {
|
||||||
owner = "catppuccin";
|
owner = "rose-pine";
|
||||||
repo = "bat";
|
repo = "tm-theme";
|
||||||
rev = "6810349b28055dce54076712fc05fc68da4b8ec0";
|
rev = "23bb25b9c421cdc9ea89ff3ad3825840cd19d65d";
|
||||||
sha256 = "lJapSgRVENTrbmpVyn+UQabC9fpV1G1e+CdlJ090uvg=";
|
hash = "sha256-GUFdv5V5OZ2PG+gfsbiohMT23LWsrZda34ReHBr2Xy0=";
|
||||||
};
|
};
|
||||||
file = "themes/Catppuccin Latte.tmTheme";
|
file = "dist/rose-pine-dawn.tmTheme";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -55,11 +55,11 @@
|
|||||||
--preview-window='border-rounded' --prompt=' ' --marker=' ' --pointer=' '
|
--preview-window='border-rounded' --prompt=' ' --marker=' ' --pointer=' '
|
||||||
--separator='─' --scrollbar='┃' --layout='reverse'
|
--separator='─' --scrollbar='┃' --layout='reverse'
|
||||||
|
|
||||||
--color=bg+:#CCD0DA,bg:#EFF1F5,spinner:#DC8A78,hl:#D20F39
|
--color=bg+:#f2e9e1,bg:#faf4ed,spinner:#ea9d34,hl:#d7827e
|
||||||
--color=fg:#4C4F69,header:#D20F39,info:#8839EF,pointer:#DC8A78
|
--color=fg:#797593,header:#286983,info:#56949f,pointer:#907aa9
|
||||||
--color=marker:#7287FD,fg+:#4C4F69,prompt:#8839EF,hl+:#D20F39
|
--color=marker:#b4637a,fg+:#575279,prompt:#797593,hl+:#d7827e
|
||||||
--color=selected-bg:#BCC0CC
|
--color=selected-bg:#f2e9e1
|
||||||
--color=border:#9CA0B0,label:#4C4F69
|
--color=border:#dfdad9,label:#575279
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
programs.zellij = {
|
programs.zellij = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
theme = "catppuccin-latte";
|
theme = "rose-pine-dawn";
|
||||||
default_layout = "default";
|
default_layout = "default";
|
||||||
default_shell = "${pkgs.nushell}/bin/nu";
|
default_shell = "${pkgs.nushell}/bin/nu";
|
||||||
pane_frames = false;
|
pane_frames = false;
|
||||||
@@ -12,6 +12,24 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xdg.configFile."zellij/themes/rose-pine-dawn.kdl".text = ''
|
||||||
|
themes {
|
||||||
|
rose-pine-dawn {
|
||||||
|
fg "#575279"
|
||||||
|
bg "#f2e9e1"
|
||||||
|
black "#faf4ed"
|
||||||
|
red "#b4637a"
|
||||||
|
green "#6d8f89"
|
||||||
|
yellow "#ea9d34"
|
||||||
|
blue "#286983"
|
||||||
|
magenta "#907aa9"
|
||||||
|
cyan "#56949f"
|
||||||
|
white "#575279"
|
||||||
|
orange "#d7827e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
xdg.configFile."zellij/layouts/default.kdl".text = ''
|
xdg.configFile."zellij/layouts/default.kdl".text = ''
|
||||||
layout {
|
layout {
|
||||||
default_tab_template {
|
default_tab_template {
|
||||||
@@ -23,26 +41,26 @@
|
|||||||
plugin location="file:${pkgs.zjstatus}/bin/zjstatus.wasm" {
|
plugin location="file:${pkgs.zjstatus}/bin/zjstatus.wasm" {
|
||||||
hide_frame_for_single_pane "true"
|
hide_frame_for_single_pane "true"
|
||||||
|
|
||||||
format_left "{mode}#[fg=#1e66f5,bg=#eff1f5,bold] {session}#[bg=#eff1f5] {tabs}"
|
format_left "{mode}#[fg=#286983,bg=#faf4ed,bold] {session}#[bg=#faf4ed] {tabs}"
|
||||||
format_right "{datetime}"
|
format_right "{datetime}"
|
||||||
format_space "#[bg=#eff1f5]"
|
format_space "#[bg=#faf4ed]"
|
||||||
|
|
||||||
mode_normal "#[fg=#eff1f5,bg=#1e66f5] "
|
mode_normal "#[fg=#faf4ed,bg=#286983] "
|
||||||
mode_locked "#[fg=#eff1f5,bg=#fe640b] L "
|
mode_locked "#[fg=#faf4ed,bg=#ea9d34] L "
|
||||||
mode_tab "#[fg=#eff1f5,bg=#40a02b] T "
|
mode_tab "#[fg=#faf4ed,bg=#6d8f89] T "
|
||||||
mode_pane "#[fg=#eff1f5,bg=#8839ef] P "
|
mode_pane "#[fg=#faf4ed,bg=#907aa9] P "
|
||||||
mode_session "#[fg=#eff1f5,bg=#04a5e5] S "
|
mode_session "#[fg=#faf4ed,bg=#56949f] S "
|
||||||
mode_resize "#[fg=#eff1f5,bg=#df8e1d] R "
|
mode_resize "#[fg=#faf4ed,bg=#ea9d34] R "
|
||||||
mode_move "#[fg=#eff1f5,bg=#ea76cb] M "
|
mode_move "#[fg=#faf4ed,bg=#d7827e] M "
|
||||||
mode_search "#[fg=#eff1f5,bg=#d20f39] S "
|
mode_search "#[fg=#faf4ed,bg=#b4637a] S "
|
||||||
|
|
||||||
tab_normal "#[fg=#acb0be,bg=#eff1f5] {index} {name} {fullscreen_indicator}{sync_indicator}{floating_indicator}"
|
tab_normal "#[fg=#9893a5,bg=#faf4ed] {index} {name} {fullscreen_indicator}{sync_indicator}{floating_indicator}"
|
||||||
tab_active "#[fg=#eff1f5,bg=#1e66f5,bold,underline] {index} {name} {fullscreen_indicator}{sync_indicator}{floating_indicator}"
|
tab_active "#[fg=#faf4ed,bg=#286983,bold,underline] {index} {name} {fullscreen_indicator}{sync_indicator}{floating_indicator}"
|
||||||
tab_fullscreen_indicator " "
|
tab_fullscreen_indicator " "
|
||||||
tab_sync_indicator " "
|
tab_sync_indicator " "
|
||||||
tab_floating_indicator " "
|
tab_floating_indicator " "
|
||||||
|
|
||||||
datetime "#[fg=#4c4f69,bg=#eff1f5] {format} "
|
datetime "#[fg=#575279,bg=#faf4ed] {format} "
|
||||||
datetime_format "%A, %d %b %Y %H:%M"
|
datetime_format "%A, %d %b %Y %H:%M"
|
||||||
datetime_timezone "Europe/Berlin"
|
datetime_timezone "Europe/Berlin"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user