mirror of
https://codeberg.org/muon/home.git
synced 2026-07-03 23:49:35 +00:00
Merge branch 'main' of codeberg.org:muon/home
This commit is contained in:
commit
87f09972b0
47 changed files with 2603 additions and 136 deletions
|
|
@ -3,6 +3,7 @@ keys:
|
||||||
- &muho age1v4s4hg7u3vjjkarvrk7v6ev7w3wja2r5xm7f4t06culw3fuq7qns8sfju7
|
- &muho age1v4s4hg7u3vjjkarvrk7v6ev7w3wja2r5xm7f4t06culw3fuq7qns8sfju7
|
||||||
- &mups age1n7qz2w3hkf7fcdv92kxw9k6uef487na2tlc87486rcjwj8lyfuws5q46gn
|
- &mups age1n7qz2w3hkf7fcdv92kxw9k6uef487na2tlc87486rcjwj8lyfuws5q46gn
|
||||||
- &murk age1mgjhkqy9x27gv2t2xvq46dxcajkr9c8zes7rr3dj0ac7md2j6vas43dftp
|
- &murk age1mgjhkqy9x27gv2t2xvq46dxcajkr9c8zes7rr3dj0ac7md2j6vas43dftp
|
||||||
|
- &musk age1m97a3eptxwpdd7h5kkqe9gkmhg6rquc64qjmlsfqfhfqv8q72crqrylhgc
|
||||||
|
|
||||||
creation_rules:
|
creation_rules:
|
||||||
- path_regex: modules/nixos/sops/secrets.ya?ml$
|
- path_regex: modules/nixos/sops/secrets.ya?ml$
|
||||||
|
|
@ -12,6 +13,7 @@ creation_rules:
|
||||||
- *muho
|
- *muho
|
||||||
- *mups
|
- *mups
|
||||||
- *murk
|
- *murk
|
||||||
|
- *musk
|
||||||
|
|
||||||
- path_regex: modules/home/sops/secrets.ya?ml$
|
- path_regex: modules/home/sops/secrets.ya?ml$
|
||||||
key_groups:
|
key_groups:
|
||||||
|
|
@ -20,3 +22,4 @@ creation_rules:
|
||||||
- *muho
|
- *muho
|
||||||
- *mups
|
- *mups
|
||||||
- *murk
|
- *murk
|
||||||
|
- *musk
|
||||||
|
|
|
||||||
102
flake.lock
generated
102
flake.lock
generated
|
|
@ -139,11 +139,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760948891,
|
"lastModified": 1769996383,
|
||||||
"narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=",
|
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04",
|
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -233,11 +233,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768598210,
|
"lastModified": 1773367248,
|
||||||
"narHash": "sha256-kkgA32s/f4jaa4UG+2f8C225Qvclxnqs76mf8zvTVPg=",
|
"narHash": "sha256-FFMc1uAwy2GYasd0rdNDVxKyAgzuoJH2M+GglBQbqf0=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "c47b2cc64a629f8e075de52e4742de688f930dc6",
|
"rev": "be0c641a6a5564caa33982faa1fe2c60d92131c7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -254,11 +254,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1747978958,
|
"lastModified": 1768598210,
|
||||||
"narHash": "sha256-pQQnbxWpY3IiZqgelXHIe/OAE/Yv4NSQq7fch7M6nXQ=",
|
"narHash": "sha256-kkgA32s/f4jaa4UG+2f8C225Qvclxnqs76mf8zvTVPg=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "7419250703fd5eb50e99bdfb07a86671939103ea",
|
"rev": "c47b2cc64a629f8e075de52e4742de688f930dc6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -275,11 +275,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767104570,
|
"lastModified": 1772330611,
|
||||||
"narHash": "sha256-GKgwu5//R+cLdKysZjGqvUEEOGXXLdt93sNXeb2M/Lk=",
|
"narHash": "sha256-UZjPc/d5XRxvjDbk4veAO4XFdvx6BUum2l40V688Xq8=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "e4e78a2cbeaddd07ab7238971b16468cc1d14daf",
|
"rev": "58fd7ff0eec2cda43e705c4c0585729ec471d400",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -294,11 +294,11 @@
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767822991,
|
"lastModified": 1769548169,
|
||||||
"narHash": "sha256-iyrn9AcPZCoyxX4OT8eMkBsjG7SRUQXXS/V1JzxS7rA=",
|
"narHash": "sha256-03+JxvzmfwRu+5JafM0DLbxgHttOQZkUtDWBmeUkN8Y=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "impermanence",
|
"repo": "impermanence",
|
||||||
"rev": "82e5bc4508cab9e8d5a136626276eb5bbce5e9c5",
|
"rev": "7b1d382faf603b6d264f58627330f9faa5cba149",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -309,11 +309,11 @@
|
||||||
},
|
},
|
||||||
"mnw": {
|
"mnw": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758834834,
|
"lastModified": 1770419553,
|
||||||
"narHash": "sha256-Y7IvY4F8vajZyp3WGf+KaiIVwondEkMFkt92Cr9NZmg=",
|
"narHash": "sha256-b1XqsH7AtVf2dXmq2iyRr2NC1yG7skY7Z6N2MpWHlK4=",
|
||||||
"owner": "Gerg-L",
|
"owner": "Gerg-L",
|
||||||
"repo": "mnw",
|
"repo": "mnw",
|
||||||
"rev": "cfbc7d1cc832e318d0863a5fc91d940a96034001",
|
"rev": "2aaffa8030d0b262176146adbb6b0e6374ce2957",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -330,15 +330,16 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765720983,
|
"lastModified": 1768214250,
|
||||||
"narHash": "sha256-tWtukpABmux6EC/FuCJEgA1kmRjcRPtED44N+GGPq+4=",
|
"narHash": "sha256-hnBZDQWUxJV3KbtvyGW5BKLO/fAwydrxm5WHCWMQTbw=",
|
||||||
"owner": "feel-co",
|
"owner": "feel-co",
|
||||||
"repo": "ndg",
|
"repo": "ndg",
|
||||||
"rev": "f399ace8bb8e1f705dd8942b24d207aa4d75c936",
|
"rev": "a6bd3c1ce2668d096e4fdaaa03ad7f03ba1fbca8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "feel-co",
|
"owner": "feel-co",
|
||||||
|
"ref": "refs/tags/v2.6.0",
|
||||||
"repo": "ndg",
|
"repo": "ndg",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|
@ -350,11 +351,11 @@
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768475717,
|
"lastModified": 1771150922,
|
||||||
"narHash": "sha256-185VOlWF4K9gzwr7M56ArjqDt6beN/5TxCYLEyVPOcs=",
|
"narHash": "sha256-+oQJun4CFDlOQRocbZpqQDj7agoy56/4ZjT1oUR7NOs=",
|
||||||
"owner": "thiagokokada",
|
"owner": "thiagokokada",
|
||||||
"repo": "nix-alien",
|
"repo": "nix-alien",
|
||||||
"rev": "a579610c67dc946f39c2a64656699eb29eb2ffb5",
|
"rev": "96045e886ba0dd45b27590e7c0c6e77bbb54033d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -387,11 +388,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765267181,
|
"lastModified": 1771130777,
|
||||||
"narHash": "sha256-d3NBA9zEtBu2JFMnTBqWj7Tmi7R5OikoU2ycrdhQEws=",
|
"narHash": "sha256-UIKOwG0D9XVIJfNWg6+gENAvQP+7LO46eO0Jpe+ItJ0=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nix-index-database",
|
"repo": "nix-index-database",
|
||||||
"rev": "82befcf7dc77c909b0f2a09f5da910ec95c5b78f",
|
"rev": "efec7aaad8d43f8e5194df46a007456093c40f88",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -422,11 +423,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1748026106,
|
"lastModified": 1768564909,
|
||||||
"narHash": "sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o=",
|
"narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "063f43f2dbdef86376cc29ad646c45c46e93234c",
|
"rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -438,11 +439,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768305791,
|
"lastModified": 1771008912,
|
||||||
"narHash": "sha256-AIdl6WAn9aymeaH/NvBj0H9qM+XuAuYbGMZaP0zcXAQ=",
|
"narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "1412caf7bf9e660f2f962917c14b1ea1c3bc695e",
|
"rev": "a82ccc39b39b621151d6732718e3e250109076fa",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -470,11 +471,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_4": {
|
"nixpkgs_4": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768564909,
|
"lastModified": 1773282481,
|
||||||
"narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=",
|
"narHash": "sha256-b/GV2ysM8mKHhinse2wz+uP37epUrSE+sAKXy/xvBY4=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f",
|
"rev": "fe416aaedd397cacb33a610b33d60ff2b431b127",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -537,16 +538,15 @@
|
||||||
"systems": "systems_2"
|
"systems": "systems_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767628834,
|
"lastModified": 1773343795,
|
||||||
"narHash": "sha256-qiPFYDicHq4/ji0/9QxVM8hhjspsJrYcMR/S3zKlfjQ=",
|
"narHash": "sha256-0+HEuOytpwyPt7i1jj6v2QJ+NXXisCYnL2XNwPBltvg=",
|
||||||
"owner": "thamenato",
|
"owner": "NotAShelf",
|
||||||
"repo": "nvf",
|
"repo": "nvf",
|
||||||
"rev": "7161c8d857cf7c641433cc750a1a3666f82a3ff0",
|
"rev": "83b44eaf50b96bd5d06b1a56a3a51f1b2362db52",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "thamenato",
|
"owner": "NotAShelf",
|
||||||
"ref": "fix-nvim-treesitter",
|
|
||||||
"repo": "nvf",
|
"repo": "nvf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|
@ -573,11 +573,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768481291,
|
"lastModified": 1773096132,
|
||||||
"narHash": "sha256-NjKtkJraCZEnLHAJxLTI+BfdU//9coAz9p5TqveZwPU=",
|
"narHash": "sha256-M3zEnq9OElB7zqc+mjgPlByPm1O5t2fbUrH3t/Hm5Ag=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "e085e303dfcce21adcb5fec535d65aacb066f101",
|
"rev": "d1ff3b1034d5bab5d7d8086a7803c5a5968cd784",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -626,11 +626,11 @@
|
||||||
"tinted-zed": "tinted-zed"
|
"tinted-zed": "tinted-zed"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768603455,
|
"lastModified": 1772296853,
|
||||||
"narHash": "sha256-ih6dYNhX1oSg0emfSAvf3iRcgsJtMmS6RUaoCX8kNoU=",
|
"narHash": "sha256-pAtzPsgHRKw/2Kv8HgAjSJg450FDldHPWsP3AKG/Xj0=",
|
||||||
"owner": "danth",
|
"owner": "danth",
|
||||||
"repo": "stylix",
|
"repo": "stylix",
|
||||||
"rev": "590e5c68c4d5e8c766420473c0185d75113f653b",
|
"rev": "c4b8e80a1020e09a1f081ad0f98ce804a6e85acf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -794,11 +794,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768638486,
|
"lastModified": 1773290887,
|
||||||
"narHash": "sha256-+LC0wOiliUXbIj6zT2hCoOQ0zn33BD2NxGoy0QqP3Eo=",
|
"narHash": "sha256-L1yMYmFffHfZNP+hKJGRBmrFKkn/VDhu7jEbVftBQuM=",
|
||||||
"owner": "0xc000022070",
|
"owner": "0xc000022070",
|
||||||
"repo": "zen-browser-flake",
|
"repo": "zen-browser-flake",
|
||||||
"rev": "76bbc35c59419b8b0616fb779ce5600e85edab11",
|
"rev": "9346698c4562819f61b4e5097151ec0b17729fab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
50
flake.nix
50
flake.nix
|
|
@ -14,8 +14,7 @@
|
||||||
nix-alien.url = "github:thiagokokada/nix-alien";
|
nix-alien.url = "github:thiagokokada/nix-alien";
|
||||||
|
|
||||||
nvf = {
|
nvf = {
|
||||||
# url = "github:NotAShelf/nvf";
|
url = "github:NotAShelf/nvf";
|
||||||
url = "github:thamenato/nvf/fix-nvim-treesitter";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -47,35 +46,32 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
utils = import ./utils.nix {inherit inputs system sources;};
|
utils = import ./utils.nix {inherit inputs system sources;};
|
||||||
|
|
||||||
|
# Discover hosts: all subdirectories of hosts/
|
||||||
|
hosts = builtins.attrNames (nixpkgs.lib.filterAttrs
|
||||||
|
(_: type: type == "directory")
|
||||||
|
(builtins.readDir ./hosts));
|
||||||
|
|
||||||
|
nixosConfigs = builtins.listToAttrs (map (host: {
|
||||||
|
name = host;
|
||||||
|
value = utils.mkHost ./hosts/${host}/configuration.nix;
|
||||||
|
}) hosts);
|
||||||
in {
|
in {
|
||||||
nixosConfigurations = {
|
nixosConfigurations = nixosConfigs;
|
||||||
# desktop
|
|
||||||
muon = utils.mkHost ./hosts/muon/configuration.nix;
|
|
||||||
|
|
||||||
# laptop
|
|
||||||
muop = utils.mkHost ./hosts/muop/configuration.nix;
|
|
||||||
|
|
||||||
# server
|
|
||||||
muho = utils.mkHost ./hosts/muho/configuration.nix;
|
|
||||||
|
|
||||||
# vps
|
|
||||||
mups = utils.mkHost ./hosts/mups/configuration.nix;
|
|
||||||
|
|
||||||
# vm
|
|
||||||
muvm = utils.mkHost ./hosts/muvm/configuration.nix;
|
|
||||||
|
|
||||||
# work
|
|
||||||
murk = utils.mkHost ./hosts/murk/configuration.nix;
|
|
||||||
|
|
||||||
# lenovo
|
|
||||||
muvo = utils.mkHost ./hosts/muvo/configuration.nix;
|
|
||||||
|
|
||||||
# installer
|
|
||||||
muin = utils.mkHost ./hosts/muin/configuration.nix;
|
|
||||||
};
|
|
||||||
|
|
||||||
homeManagerModules.default = ./modules/home;
|
homeManagerModules.default = ./modules/home;
|
||||||
|
|
||||||
|
# Standalone HM configurations — one per host.
|
||||||
|
# osConfig is injected so all modules using it continue to work.
|
||||||
|
# Use: home-manager switch --flake '.#muon@<host>'
|
||||||
|
homeConfigurations = builtins.listToAttrs (map (host: {
|
||||||
|
name = "muon@${host}";
|
||||||
|
value = utils.mkHome {
|
||||||
|
hostConfig = nixosConfigs.${host};
|
||||||
|
homeFile = ./hosts/${host}/home.nix;
|
||||||
|
};
|
||||||
|
}) hosts);
|
||||||
|
|
||||||
colmena = {
|
colmena = {
|
||||||
meta = {
|
meta = {
|
||||||
nixpkgs = import inputs.nixpkgs {inherit system;};
|
nixpkgs = import inputs.nixpkgs {inherit system;};
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ in {
|
||||||
mods.server.ntfy.enable = true;
|
mods.server.ntfy.enable = true;
|
||||||
mods.server.lemmy.enable = true;
|
mods.server.lemmy.enable = true;
|
||||||
mods.server.audio.enable = true;
|
mods.server.audio.enable = true;
|
||||||
|
mods.server.murmur.enable = true;
|
||||||
mods.server.atuin.enable = true;
|
mods.server.atuin.enable = true;
|
||||||
mods.server.seedbox.enable = true;
|
mods.server.seedbox.enable = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ in {
|
||||||
mods.xdg.enable = true;
|
mods.xdg.enable = true;
|
||||||
mods.social.enable = false;
|
mods.social.enable = false;
|
||||||
mods.i3.enable = false;
|
mods.i3.enable = false;
|
||||||
|
mods.terminal.wezterm.enable = true;
|
||||||
|
mods.terminal.nushell.enable = true;
|
||||||
mods.terminal.zsh.enable = true;
|
mods.terminal.zsh.enable = true;
|
||||||
mods.terminal.emulator.enable = false;
|
mods.terminal.emulator.enable = false;
|
||||||
mods.terminal.development.enable = true;
|
mods.terminal.development.enable = true;
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,16 @@ in {
|
||||||
gnumeric
|
gnumeric
|
||||||
opensnitch
|
opensnitch
|
||||||
opensnitch-ui
|
opensnitch-ui
|
||||||
|
mumble
|
||||||
];
|
];
|
||||||
|
|
||||||
|
nixpkgs.config.permittedInsecurePackages = [
|
||||||
|
"libsoup-2.74.3"
|
||||||
|
];
|
||||||
|
|
||||||
|
users.users.muon.extraGroups = ["docker"];
|
||||||
|
virtualisation.docker.enable = true;
|
||||||
|
|
||||||
# System
|
# System
|
||||||
mods.user.name = "muon";
|
mods.user.name = "muon";
|
||||||
networking.hostName = cfg.user.name;
|
networking.hostName = cfg.user.name;
|
||||||
|
|
@ -61,6 +69,20 @@ in {
|
||||||
services.xserver.windowManager.i3.enable = true;
|
services.xserver.windowManager.i3.enable = true;
|
||||||
services.actual.enable = true;
|
services.actual.enable = true;
|
||||||
|
|
||||||
|
# Reverse proxy: *.word.local -> localhost:3030
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
virtualHosts."~^(?<subdomain>.+)\\.word\\.local$" = {
|
||||||
|
serverName = "~^(?<subdomain>.+)\\.word\\.local$";
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:3030";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||||
|
|
||||||
virtualisation.virtualbox.host.enable = true;
|
virtualisation.virtualbox.host.enable = true;
|
||||||
users.extraGroups.vboxusers.members = ["user-with-access-to-virtualbox"];
|
users.extraGroups.vboxusers.members = ["user-with-access-to-virtualbox"];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,21 @@ in {
|
||||||
mods.xdg.enable = true;
|
mods.xdg.enable = true;
|
||||||
mods.social.enable = true;
|
mods.social.enable = true;
|
||||||
mods.i3.enable = true;
|
mods.i3.enable = true;
|
||||||
|
mods.terminal.wezterm.enable = true;
|
||||||
|
mods.terminal.nushell.enable = true;
|
||||||
mods.terminal.zsh.enable = true;
|
mods.terminal.zsh.enable = true;
|
||||||
mods.terminal.emulator.enable = true;
|
mods.terminal.emulator.enable = true;
|
||||||
mods.terminal.development.enable = true;
|
mods.terminal.development.enable = true;
|
||||||
mods.terminal.tools.enable = true;
|
mods.terminal.tools.enable = true;
|
||||||
|
mods.terminal.hr.enable = true;
|
||||||
|
mods.terminal.gh.enable = true;
|
||||||
mods.desktop.development.enable = true;
|
mods.desktop.development.enable = true;
|
||||||
mods.desktop.productivity.enable = true;
|
mods.desktop.productivity.enable = true;
|
||||||
mods.desktop.media.enable = true;
|
mods.desktop.media.enable = true;
|
||||||
mods.zen.enable = true;
|
mods.zen.enable = true;
|
||||||
mods.obsidian.enable = true;
|
mods.obsidian.enable = true;
|
||||||
|
mods.opencode.enable = true;
|
||||||
|
mods.octo.enable = true;
|
||||||
|
|
||||||
# Hardware preferences
|
# Hardware preferences
|
||||||
|
|
||||||
|
|
@ -64,6 +70,16 @@ in {
|
||||||
input.sensitivity = -0.4;
|
input.sensitivity = -0.4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# SSH: auto-add work key to gpg-agent on first use
|
||||||
|
programs.ssh = {
|
||||||
|
enable = true;
|
||||||
|
matchBlocks."*" = {
|
||||||
|
identityFile = "~/.ssh/work_ed25519";
|
||||||
|
addKeysToAgent = "yes";
|
||||||
|
};
|
||||||
|
matchBlocks."muho".identityFile = "~/.ssh/id_ed25519";
|
||||||
|
};
|
||||||
|
|
||||||
# Version of first install
|
# Version of first install
|
||||||
home.stateVersion = "23.05";
|
home.stateVersion = "23.05";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,15 @@ in {
|
||||||
mods.terminal.emulator.enable = true;
|
mods.terminal.emulator.enable = true;
|
||||||
mods.terminal.development.enable = true;
|
mods.terminal.development.enable = true;
|
||||||
mods.terminal.tools.enable = true;
|
mods.terminal.tools.enable = true;
|
||||||
|
mods.terminal.gh.enable = true;
|
||||||
|
mods.terminal.hr.enable = true;
|
||||||
mods.desktop.development.enable = true;
|
mods.desktop.development.enable = true;
|
||||||
mods.desktop.productivity.enable = false;
|
mods.desktop.productivity.enable = false;
|
||||||
mods.zen.enable = true;
|
mods.zen.enable = true;
|
||||||
mods.obsidian.enable = true;
|
mods.obsidian.enable = true;
|
||||||
mods.theme.slideshow.enable = true;
|
mods.theme.slideshow.enable = true;
|
||||||
|
mods.octo.enable = true;
|
||||||
|
mods.theme.slideshow = true;
|
||||||
|
|
||||||
home.packages = with pkgs;
|
home.packages = with pkgs;
|
||||||
[
|
[
|
||||||
|
|
@ -43,7 +47,6 @@ in {
|
||||||
go
|
go
|
||||||
rainfrog
|
rainfrog
|
||||||
tealdeer
|
tealdeer
|
||||||
gh
|
|
||||||
(callPackage ./packages/mender-cli.nix {})
|
(callPackage ./packages/mender-cli.nix {})
|
||||||
]
|
]
|
||||||
# Non-free </3
|
# Non-free </3
|
||||||
|
|
|
||||||
117
hosts/musk/configuration.nix
Normal file
117
hosts/musk/configuration.nix
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
|
system,
|
||||||
|
sources,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
cfg = config.mods;
|
||||||
|
keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKEio+Y5wBVD1wILaH2R3wV10FvVjiqy/4gGBWHOITTB muon@muon"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKevYmkH7xvYoquBjnYZ7PJiVqf+GOh9fxAJBN6wZGBB gin4@hi.is"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILmAOd9VbhyJeibt6Vrb101MNTk5W8+rh94Djv/C+pyu muon@muho"
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
# Hardware
|
||||||
|
imports = [
|
||||||
|
./hardware-configuration.nix
|
||||||
|
"${
|
||||||
|
builtins.fetchTarball {
|
||||||
|
url = "https://github.com/nix-community/disko/archive/refs/tags/v1.12.0.tar.gz";
|
||||||
|
sha256 = "0wbx518d2x54yn4xh98cgm65wvj0gpy6nia6ra7ns4j63hx14fkq";
|
||||||
|
}
|
||||||
|
}/module.nix"
|
||||||
|
./disk-config.nix
|
||||||
|
# (inputs.nixpkgs
|
||||||
|
# + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.systemPackages = with inputs.nix-alien.packages.${system}; [
|
||||||
|
nix-alien
|
||||||
|
pkgs.libratbag
|
||||||
|
pkgs.piper
|
||||||
|
pkgs.libpq
|
||||||
|
pkgs.qmk
|
||||||
|
pkgs.jq
|
||||||
|
pkgs.wireguard-tools
|
||||||
|
pkgs.opencode
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.binfmt = {
|
||||||
|
emulatedSystems = ["aarch64-linux"];
|
||||||
|
preferStaticEmulators = true; # Make it work with Docker
|
||||||
|
};
|
||||||
|
|
||||||
|
# System
|
||||||
|
mods.user.name = "muon";
|
||||||
|
networking.hostName = "musk";
|
||||||
|
networking.hostId = "a2309091";
|
||||||
|
mods.home.file = ./home.nix;
|
||||||
|
nix.settings.trusted-users = ["root" "muon"];
|
||||||
|
users.users.muon.extraGroups = ["docker"];
|
||||||
|
|
||||||
|
# Modules
|
||||||
|
mods.desktop.enable = true;
|
||||||
|
mods.boot.enable = true;
|
||||||
|
|
||||||
|
mods.theme.enable = true;
|
||||||
|
mods.theme.scheme = "catppuccin-macchiato";
|
||||||
|
mods.theme.wallpaper = ./wallpaper.png;
|
||||||
|
|
||||||
|
services.xserver.windowManager.i3.enable = true;
|
||||||
|
# mods.desktop.wayland.enable = true;
|
||||||
|
|
||||||
|
mods.impermanence.enable = true;
|
||||||
|
|
||||||
|
virtualisation.docker.enable = true;
|
||||||
|
|
||||||
|
users.users.muon.openssh.authorizedKeys.keys = keys;
|
||||||
|
users.users.root.openssh.authorizedKeys.keys = keys;
|
||||||
|
|
||||||
|
# Persist
|
||||||
|
environment.persistence."/persist" = {
|
||||||
|
directories = ["/etc/NetworkManager" "/var/lib/NetworkManager"];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Hardware preferences
|
||||||
|
# environment.variables = {
|
||||||
|
# WINIT_HIDPI_FACTOR = "1";
|
||||||
|
# WINIT_X11_SCALE_FACTOR = "1";
|
||||||
|
# };
|
||||||
|
|
||||||
|
## Monitors
|
||||||
|
mods.monitors = {
|
||||||
|
primary = {
|
||||||
|
name = "DP-1";
|
||||||
|
config = {
|
||||||
|
enable = true;
|
||||||
|
mode = "2560x1440";
|
||||||
|
position = "0x0";
|
||||||
|
rate = "60.00";
|
||||||
|
dpi = 72;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
right = {
|
||||||
|
name = "HDMI-1";
|
||||||
|
config = {
|
||||||
|
enable = true;
|
||||||
|
mode = "2560x1440";
|
||||||
|
position = "2560x0";
|
||||||
|
rate = "60.00";
|
||||||
|
dpi = 72;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
## Mouse
|
||||||
|
services.libinput.mouse.accelProfile = "flat";
|
||||||
|
|
||||||
|
## Keyboard
|
||||||
|
hardware.keyboard.qmk.enable = true;
|
||||||
|
|
||||||
|
# Version of first install
|
||||||
|
system.stateVersion = "23.05";
|
||||||
|
}
|
||||||
72
hosts/musk/disk-config.nix
Normal file
72
hosts/musk/disk-config.nix
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
disko.devices = {
|
||||||
|
disk = {
|
||||||
|
main = {
|
||||||
|
type = "disk";
|
||||||
|
device = "/dev/sda";
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
ESP = {
|
||||||
|
size = "512M";
|
||||||
|
type = "EF00";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot";
|
||||||
|
mountOptions = [ "umask=0077" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
luks = {
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "luks";
|
||||||
|
name = "crypted";
|
||||||
|
# disable settings.keyFile if you want to use interactive password entry
|
||||||
|
#passwordFile = "/tmp/secret.key"; # Interactive
|
||||||
|
# settings = {
|
||||||
|
# allowDiscards = true;
|
||||||
|
# keyFile = "/tmp/secret.key";
|
||||||
|
# };
|
||||||
|
# additionalKeyFiles = [ "/tmp/additionalSecret.key" ];
|
||||||
|
content = {
|
||||||
|
type = "btrfs";
|
||||||
|
extraArgs = [ "-f" ];
|
||||||
|
subvolumes = {
|
||||||
|
"/root" = {
|
||||||
|
mountpoint = "/";
|
||||||
|
mountOptions = [ "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
"/home" = {
|
||||||
|
mountpoint = "/home";
|
||||||
|
mountOptions = [ "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
"/nix" = {
|
||||||
|
mountpoint = "/nix";
|
||||||
|
mountOptions = [ "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
"/persist" = {
|
||||||
|
mountpoint = "/persist";
|
||||||
|
mountOptions = [ "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
"/log" = {
|
||||||
|
mountpoint = "/var/log";
|
||||||
|
mountOptions = [ "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
"/swap" = {
|
||||||
|
mountpoint = "/swap";
|
||||||
|
swap.swapfile.size = "4G";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/persist".neededForBoot = true;
|
||||||
|
fileSystems."/var/log".neededForBoot = true;
|
||||||
|
}
|
||||||
18
hosts/musk/hardware-configuration.nix
Normal file
18
hosts/musk/hardware-configuration.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||||
|
# and may be overwritten by future invocations. Please make changes
|
||||||
|
# to /etc/nixos/configuration.nix instead.
|
||||||
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
}
|
||||||
101
hosts/musk/home.nix
Normal file
101
hosts/musk/home.nix
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
inputs,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
cfg = osConfig.mods;
|
||||||
|
color = config.lib.stylix.colors.withHashtag;
|
||||||
|
in {
|
||||||
|
# Modules
|
||||||
|
mods.xdg.enable = true;
|
||||||
|
mods.i3.enable = true;
|
||||||
|
# mods.hyprland.enable = true;
|
||||||
|
mods.terminal.zsh.enable = true;
|
||||||
|
mods.terminal.nushell.enable = true;
|
||||||
|
mods.terminal.emulator.enable = true;
|
||||||
|
mods.terminal.wezterm.enable = true;
|
||||||
|
mods.terminal.development.enable = true;
|
||||||
|
mods.terminal.tools.enable = true;
|
||||||
|
mods.terminal.gh.enable = true;
|
||||||
|
mods.terminal.hr.enable = true;
|
||||||
|
mods.desktop.development.enable = true;
|
||||||
|
mods.desktop.productivity.enable = false;
|
||||||
|
mods.zen.enable = true;
|
||||||
|
mods.octo.enable = true;
|
||||||
|
|
||||||
|
home.packages = with pkgs;
|
||||||
|
[
|
||||||
|
thunderbird
|
||||||
|
pulseaudio
|
||||||
|
pavucontrol
|
||||||
|
alsa-utils
|
||||||
|
rustdesk-flutter
|
||||||
|
|
||||||
|
# tools
|
||||||
|
docker
|
||||||
|
fish
|
||||||
|
devenv
|
||||||
|
dbeaver-bin
|
||||||
|
ruff
|
||||||
|
just
|
||||||
|
go
|
||||||
|
rainfrog
|
||||||
|
tealdeer
|
||||||
|
(callPackage ./packages/mender-cli.nix {})
|
||||||
|
]
|
||||||
|
# Non-free </3
|
||||||
|
++ [google-cloud-sdk google-cloud-sql-proxy];
|
||||||
|
|
||||||
|
services.flameshot = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
General = {
|
||||||
|
disabledTrayIcon = true;
|
||||||
|
showStartupLaunchMessage = false;
|
||||||
|
startupLaunch = true;
|
||||||
|
|
||||||
|
uiColor = color.base01;
|
||||||
|
contrastUiColor = color.base00;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Hardware preferences
|
||||||
|
## Monitors
|
||||||
|
xsession.windowManager.i3.config.workspaceOutputAssign = [
|
||||||
|
{
|
||||||
|
workspace = "1";
|
||||||
|
output = "${cfg.monitors.primary.name}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
workspace = "2";
|
||||||
|
output = "${cfg.monitors.right.name}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services.autorandr.enable = true;
|
||||||
|
programs.autorandr = {
|
||||||
|
enable = true;
|
||||||
|
hooks.postswitch = {
|
||||||
|
"notify-i3" = "${pkgs.i3}/bin/i3-msg restart";
|
||||||
|
"set-wallpaper" = ''
|
||||||
|
${lib.getExe pkgs.feh} --bg-fill --nofehbg ${./wallpaper.png}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
profiles.default = {
|
||||||
|
fingerprint = {
|
||||||
|
"${cfg.monitors.right.name}" = "00ffffffffffff0030aef465010101011e1e0103803c22782a31d5a65453a0240a5054bfcf00d1c0d100b300a9c09500818081c08100e973006aa0a034504220680055502100001a565e00a0a0a029503020350055502100001a000000fd00304b0f6e1e000a202020202020000000fc00513237712d31300a202020202001ff020329f04b10050403021f1413121101230907078301000067030c001000183c681a00000101304b00023a801871382d40582c450055502100001e662156aa51001e30468f330055502100001eab22a0a050841a303020360055502100001a7c2e90a0601a1e403020360055502100001a000000000000000000000000000026";
|
||||||
|
"${cfg.monitors.primary.name}" = "00ffffffffffff0005e30427b11a0000321f0104a53c22783be445a554529e260d5054bfef00d1c0b30095008180814081c001010101565e00a0a0a029503020350055502100001e000000ff005141424d434841303036383333000000fc00513237563447350a2020202020000000fd00304b72721e010a2020202020200163020318f14b0103051404131f120211902309070783010000a073006aa0a029500820350055502100001a2a4480a0703827403020350055502100001a023a801871382d40582c450055502100001ef03c00d051a0355060883a0055502100001c000000000000000000000000000000000000000000000000000000000000005f";
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
"${cfg.monitors.primary.name}" = cfg.monitors.primary.config;
|
||||||
|
"${cfg.monitors.right.name}" = cfg.monitors.right.config;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Version of first install
|
||||||
|
home.stateVersion = "23.05";
|
||||||
|
}
|
||||||
54
hosts/musk/packages/mender-cli.nix
Normal file
54
hosts/musk/packages/mender-cli.nix
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
stdenv,
|
||||||
|
buildGoModule,
|
||||||
|
fetchFromGitHub,
|
||||||
|
makeWrapper,
|
||||||
|
installShellFiles,
|
||||||
|
xz,
|
||||||
|
go,
|
||||||
|
}:
|
||||||
|
buildGoModule rec {
|
||||||
|
pname = "mender-cli";
|
||||||
|
version = "1.12.0";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "mendersoftware";
|
||||||
|
repo = "mender-cli";
|
||||||
|
rev = version;
|
||||||
|
sha256 = "sha256-Pf87wTHXcFlnYsgx7ieiIJ9PWJFPUkFJYTkKJKmMFEQ=";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorHash = "sha256-MqyBa+wsbuXqtM4DL/QGBUWuEYlG8BRxIXq7O1LJUyM=";
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
makeWrapper
|
||||||
|
installShellFiles
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
xz
|
||||||
|
];
|
||||||
|
|
||||||
|
allowGoReference = true;
|
||||||
|
|
||||||
|
postFixup = ''
|
||||||
|
wrapProgram "$out/bin/mender-cli" \
|
||||||
|
--prefix PATH : ${go}/bin
|
||||||
|
'';
|
||||||
|
|
||||||
|
postInstall = lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
|
||||||
|
installShellCompletion --cmd mender-cli \
|
||||||
|
--bash <($out/bin/mender-cli completion bash) \
|
||||||
|
--fish <($out/bin/mender-cli completion fish) \
|
||||||
|
--zsh <($out/bin/mender-cli completion zsh) \
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Mender CLI tool to simplify integration between the Mender server and cloud services like continuous integration (CI)/build automation";
|
||||||
|
mainProgram = "mender-cli";
|
||||||
|
homepage = "https://github.com/mendersoftware/mender-cli/";
|
||||||
|
changelog = "https://github.com/mendersoftware/mender-cli/releases/tag/${version}";
|
||||||
|
license = lib.licenses.asl20;
|
||||||
|
};
|
||||||
|
}
|
||||||
BIN
hosts/musk/wallpaper.png
Normal file
BIN
hosts/musk/wallpaper.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 MiB |
|
|
@ -5,28 +5,91 @@
|
||||||
osConfig,
|
osConfig,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
fsss = with pkgs;
|
# Bootstrap script that runs as the first program inside a new wezterm window.
|
||||||
writeShellApplication {
|
# It sets up the three tabs synchronously before the shell prompt appears,
|
||||||
name = "fsss";
|
# so by the time the window is visible the layout is already complete.
|
||||||
runtimeInputs = [flameshot curl xsel];
|
# Receives the project path as $1.
|
||||||
|
wezterm-zmenu-init = pkgs.writeShellApplication {
|
||||||
|
name = "wezterm-zmenu-init";
|
||||||
|
runtimeInputs = [pkgs.wezterm pkgs.zsh];
|
||||||
text = ''
|
text = ''
|
||||||
flameshot gui -r -s > /tmp/ss.png;if [ ! -s /tmp/ss.png ]; then
|
ZPATH=$1
|
||||||
exit 1
|
WIN=$(wezterm cli list --format json 2>/dev/null \
|
||||||
fi
|
| tr ',' '\n' \
|
||||||
AUTH=$(cat ${config.sops.secrets.zipline-auth.path})
|
| awk -v pane="$WEZTERM_PANE" '
|
||||||
curl -H "authorization: $AUTH" https://share.muon.host/api/upload -F file=@/tmp/ss.png -H "Content-Type: multipart/form-data" -H "Format: date" -H "Image-Compression-Percent: 90" -H "No-JSON: true" | tr -d '\n' | xsel -ib;
|
/window_id/ { gsub(/.*: */,""); w=int($0) }
|
||||||
|
/pane_id/ { gsub(/.*: */,""); if (int($0)==pane) { print w; exit } }')
|
||||||
|
P1=$(wezterm cli spawn --window-id "$WIN" --cwd "$ZPATH" -- direnv exec . nvim)
|
||||||
|
wezterm cli spawn --window-id "$WIN" --cwd "$ZPATH" > /dev/null
|
||||||
|
wezterm cli spawn --window-id "$WIN" --cwd "$ZPATH" -- lazygit > /dev/null
|
||||||
|
wezterm cli activate-tab --tab-index 0 --pane-id "$P1" 2>/dev/null
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
zmenu = with pkgs;
|
zmenu = with pkgs;
|
||||||
writeShellApplication {
|
writeShellApplication {
|
||||||
name = "zmenu";
|
name = "zmenu";
|
||||||
runtimeInputs = [zellij zoxide wmctrl i3 rofi alacritty zsh];
|
runtimeInputs =
|
||||||
text = ''
|
[zoxide wmctrl i3 rofi zsh]
|
||||||
|
++ lib.optionals config.mods.terminal.wezterm.enable [wezterm]
|
||||||
|
++ lib.optionals (!config.mods.terminal.wezterm.enable) [zellij alacritty];
|
||||||
|
text =
|
||||||
|
if config.mods.terminal.wezterm.enable
|
||||||
|
then ''
|
||||||
|
ZPATH=$(zoxide query -l | sed -e "s|$HOME/||g" | rofi -dmenu)
|
||||||
|
[[ -z "$ZPATH" ]] && exit
|
||||||
|
ZSESH=$(echo "$ZPATH" | tr / -)
|
||||||
|
|
||||||
|
# Per-workspace socket registry so we can focus existing workspaces.
|
||||||
|
SOCKDIR="$XDG_RUNTIME_DIR/zmenu-wez"
|
||||||
|
mkdir -p "$SOCKDIR"
|
||||||
|
SOCKFILE="$SOCKDIR/$ZSESH"
|
||||||
|
|
||||||
|
SOCK=""
|
||||||
|
if [[ -f "$SOCKFILE" ]]; then
|
||||||
|
SOCK=$(cat "$SOCKFILE")
|
||||||
|
# Extract the PID from the socket path (gui-sock-<pid>) and check
|
||||||
|
# if the process is still alive. Dead sockets linger on disk.
|
||||||
|
SOCK_PID=''${SOCK##*-}
|
||||||
|
if ! kill -0 "$SOCK_PID" 2>/dev/null; then
|
||||||
|
rm -f "$SOCKFILE"
|
||||||
|
SOCK=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$SOCK" ]]; then
|
||||||
|
# Workspace open: raise its window by matching the wezterm PID in
|
||||||
|
# wmctrl's process list, then activate a pane to ensure focus.
|
||||||
|
SOCK_PID=''${SOCK##*-}
|
||||||
|
WIN_HEX=$(wmctrl -lp | awk -v pid="$SOCK_PID" '$3==pid {print $1; exit}')
|
||||||
|
wmctrl -i -a "$WIN_HEX"
|
||||||
|
PANE=$(WEZTERM_UNIX_SOCKET="$SOCK" wezterm cli list --format json 2>/dev/null \
|
||||||
|
| tr ',' '\n' \
|
||||||
|
| awk '/pane_id/{gsub(/.*: */,""); print int($0); exit}')
|
||||||
|
WEZTERM_UNIX_SOCKET="$SOCK" wezterm cli activate-pane --pane-id "$PANE" 2>/dev/null
|
||||||
|
else
|
||||||
|
# Not open: the init script runs as the first program inside the new
|
||||||
|
# window. It sets up all tabs synchronously before the shell prompt
|
||||||
|
# appears, so the layout is complete before anything is visible.
|
||||||
|
wezterm start --always-new-process \
|
||||||
|
--workspace "$ZSESH" --cwd "$HOME/$ZPATH" \
|
||||||
|
-- ${lib.getExe wezterm-zmenu-init} "$HOME/$ZPATH" &
|
||||||
|
WEZ_PID=$!
|
||||||
|
|
||||||
|
# Record the socket for future focus calls.
|
||||||
|
for _ in $(seq 50); do
|
||||||
|
sleep 0.1
|
||||||
|
[[ -S /run/user/$UID/wezterm/gui-sock-$WEZ_PID ]] && break
|
||||||
|
done
|
||||||
|
echo "/run/user/$UID/wezterm/gui-sock-$WEZ_PID" > "$SOCKFILE"
|
||||||
|
fi
|
||||||
|
''
|
||||||
|
else ''
|
||||||
ZPATH=$(zoxide query -l | sed -e "s|$HOME/||g" | rofi -dmenu)
|
ZPATH=$(zoxide query -l | sed -e "s|$HOME/||g" | rofi -dmenu)
|
||||||
[[ -z "$ZPATH" ]] && exit
|
[[ -z "$ZPATH" ]] && exit
|
||||||
ZSESH=$(echo "$ZPATH" | tr / -)
|
ZSESH=$(echo "$ZPATH" | tr / -)
|
||||||
ZWIND=$(wmctrl -l | grep "$ZSESH$" || echo "")
|
ZWIND=$(wmctrl -l | grep "$ZSESH$" || echo "")
|
||||||
cd "$ZPATH"
|
cd "$HOME/$ZPATH"
|
||||||
if [[ -z "$ZWIND" ]]; then
|
if [[ -z "$ZWIND" ]]; then
|
||||||
alacritty -T "$ZSESH" -e zsh -c "zellij -s $ZSESH -n dev || zellij a $ZSESH"
|
alacritty -T "$ZSESH" -e zsh -c "zellij -s $ZSESH -n dev || zellij a $ZSESH"
|
||||||
else
|
else
|
||||||
|
|
@ -106,7 +169,10 @@ in
|
||||||
enable = true;
|
enable = true;
|
||||||
config = {
|
config = {
|
||||||
modifier = modifier;
|
modifier = modifier;
|
||||||
terminal = "alacritty";
|
terminal =
|
||||||
|
if config.mods.terminal.wezterm.enable
|
||||||
|
then "wezterm"
|
||||||
|
else "alacritty";
|
||||||
menu = "rofi -show drun";
|
menu = "rofi -show drun";
|
||||||
|
|
||||||
window = {
|
window = {
|
||||||
|
|
@ -155,8 +221,10 @@ in
|
||||||
// {
|
// {
|
||||||
"XF86AudioRaiseVolume" = "exec --no-startup-id pactl set-sink-volume 0 +2%";
|
"XF86AudioRaiseVolume" = "exec --no-startup-id pactl set-sink-volume 0 +2%";
|
||||||
"XF86AudioLowerVolume" = "exec --no-startup-id pactl set-sink-volume 0 -2%";
|
"XF86AudioLowerVolume" = "exec --no-startup-id pactl set-sink-volume 0 -2%";
|
||||||
"Print" = "exec ${getExe fsss}";
|
"Print" = "exec flameshot gui -c -s";
|
||||||
"${modifier}+z" = "exec ${getExe zmenu}";
|
"${modifier}+z" = "exec ${getExe zmenu}";
|
||||||
|
"${modifier}+p" = "exec clipmenu";
|
||||||
|
"${modifier}+b" = "exec ${getExe pkgs.rofi-rbw-x11}";
|
||||||
"${modifier}+y" = "sticky toggle";
|
"${modifier}+y" = "sticky toggle";
|
||||||
"${modifier}+g" = "floating toggle";
|
"${modifier}+g" = "floating toggle";
|
||||||
});
|
});
|
||||||
|
|
|
||||||
54
modules/home/desktop/packages/librediscord.nix
Normal file
54
modules/home/desktop/packages/librediscord.nix
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
fetchFromGitLab,
|
||||||
|
gtk3,
|
||||||
|
libsoup_2_4,
|
||||||
|
json-glib,
|
||||||
|
leveldb,
|
||||||
|
rtaudio,
|
||||||
|
libopus,
|
||||||
|
libsodium,
|
||||||
|
libsecret,
|
||||||
|
pkg-config,
|
||||||
|
stdenv,
|
||||||
|
lib,
|
||||||
|
}: let
|
||||||
|
version = "0.1.0";
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
pname = "LibreDiscord";
|
||||||
|
|
||||||
|
src = fetchFromGitLab {
|
||||||
|
owner = "Zipdox";
|
||||||
|
repo = "LibreDiscord";
|
||||||
|
rev = "a8130fab059e69437f30e320374fe6f5d21398f8";
|
||||||
|
hash = "sha256-yr2pxW0e2ruMnDzkQMv2BQrOcN18m8zdzovnD4Dxr3M=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
gtk3
|
||||||
|
libsoup_2_4
|
||||||
|
json-glib
|
||||||
|
leveldb
|
||||||
|
rtaudio
|
||||||
|
libopus
|
||||||
|
libsodium
|
||||||
|
libsecret
|
||||||
|
];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp build/librediscord $out/bin
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Voice client for Discord written in C using GTK3 and GLib";
|
||||||
|
homepage = "https://gitlab.com/Zipdox/LibreDiscord";
|
||||||
|
license = lib.licenses.gpl3Only;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -48,12 +48,12 @@ in
|
||||||
programs.zsh.sessionVariables.BROWSER = "librewolf";
|
programs.zsh.sessionVariables.BROWSER = "librewolf";
|
||||||
|
|
||||||
services.flameshot = {
|
services.flameshot = {
|
||||||
enable = false;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
General = {
|
General = {
|
||||||
disabledTrayIcon = true;
|
disabledTrayIcon = true;
|
||||||
showStartupLaunchMessage = false;
|
showStartupLaunchMessage = false;
|
||||||
startupLaunch = false;
|
startupLaunch = true;
|
||||||
|
|
||||||
uiColor = color.base01;
|
uiColor = color.base01;
|
||||||
contrastUiColor = color.base00;
|
contrastUiColor = color.base00;
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,19 @@ in {
|
||||||
# Communication
|
# Communication
|
||||||
# kotatogram-desktop
|
# kotatogram-desktop
|
||||||
signal-desktop
|
signal-desktop
|
||||||
|
abaddon
|
||||||
vesktop-nogain
|
vesktop-nogain
|
||||||
|
# (callPackage ./packages/librediscord.nix {})
|
||||||
|
jami
|
||||||
|
|
||||||
# Video
|
# Video
|
||||||
freetube
|
freetube
|
||||||
|
|
||||||
|
# Security
|
||||||
|
gcr
|
||||||
];
|
];
|
||||||
|
|
||||||
|
services.gnome-keyring.enable = true;
|
||||||
|
services.dunst.enable = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,5 +17,7 @@ in
|
||||||
secrets.atuin-auth = {};
|
secrets.atuin-auth = {};
|
||||||
secrets.hr-password = {};
|
secrets.hr-password = {};
|
||||||
secrets.sops-key = {};
|
secrets.sops-key = {};
|
||||||
|
secrets.google-db-test = {};
|
||||||
|
secrets.google-db-prod = {};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ zipline-auth: ENC[AES256_GCM,data:RkJI6GuH7RzdcSlKn32gMGojjB6rkdDcnNUvsi/BTfJk2s
|
||||||
atuin-auth: ENC[AES256_GCM,data:LDkiXWIwxor8Ro383gonJCyqu+nyxS7DrI2J8uo4Cqu2X61rBUlnpNR6YirUZS/lYAnWYJhZM7sR0G7ZNh9EgQ==,iv:UEs2KW8ImMnaQrSLrIGbVXEq86QiVPAPNIXBZpa3jFI=,tag:N0rhnPbasFzkoI3CJ9CV+Q==,type:str]
|
atuin-auth: ENC[AES256_GCM,data:LDkiXWIwxor8Ro383gonJCyqu+nyxS7DrI2J8uo4Cqu2X61rBUlnpNR6YirUZS/lYAnWYJhZM7sR0G7ZNh9EgQ==,iv:UEs2KW8ImMnaQrSLrIGbVXEq86QiVPAPNIXBZpa3jFI=,tag:N0rhnPbasFzkoI3CJ9CV+Q==,type:str]
|
||||||
hr-password: ENC[AES256_GCM,data:QZuzAnTJ2KgPnffHvdCWrJEM5d/FXxhX3dA1,iv:FgDw6aXDY0jCpJiYc9WOobR96TXNtnvN7neJu8drxMM=,tag:YT82wryVy3V+41w0YbMOrA==,type:str]
|
hr-password: ENC[AES256_GCM,data:QZuzAnTJ2KgPnffHvdCWrJEM5d/FXxhX3dA1,iv:FgDw6aXDY0jCpJiYc9WOobR96TXNtnvN7neJu8drxMM=,tag:YT82wryVy3V+41w0YbMOrA==,type:str]
|
||||||
sops-key: ENC[AES256_GCM,data:msX0EJqJauteOBICUsLcVgqNxqGcqvD+Xi/B2EhUX2OAoyBH5oDae8XWlQCi2RdOm4NtnrSTnG8FRQXfkXO+tne0VEfYTCjeVtU=,iv:qxpvofr56Ey17xcPpju/mQgiz+0cOYED5caAHs3myXw=,tag:oDFXh0rlc0tmV2IUJ1ezBQ==,type:str]
|
sops-key: ENC[AES256_GCM,data:msX0EJqJauteOBICUsLcVgqNxqGcqvD+Xi/B2EhUX2OAoyBH5oDae8XWlQCi2RdOm4NtnrSTnG8FRQXfkXO+tne0VEfYTCjeVtU=,iv:qxpvofr56Ey17xcPpju/mQgiz+0cOYED5caAHs3myXw=,tag:oDFXh0rlc0tmV2IUJ1ezBQ==,type:str]
|
||||||
|
google-db-test: ENC[AES256_GCM,data:ZMm/BF/k+XnZZkHMDSV/fk3ds0LAOHAmag==,iv:tmfJ7ju5yAO6Oco3jXYNyqzJr7cgshyd/SkjfYnEl6U=,tag:jMD2N6TsgbRwefhJ/XYhtg==,type:str]
|
||||||
|
google-db-prod: ENC[AES256_GCM,data:fIPL9XKk9sAmpVsQBubSVbh3DlEEKadG9g==,iv:R34zkCIUDlk5/wg8eU8RZIanGayL+nX+7ZhyVmbcQC0=,tag:lu24b28742O46fjUaw2UBA==,type:str]
|
||||||
sops:
|
sops:
|
||||||
age:
|
age:
|
||||||
- recipient: age1m97a3eptxwpdd7h5kkqe9gkmhg6rquc64qjmlsfqfhfqv8q72crqrylhgc
|
- recipient: age1m97a3eptxwpdd7h5kkqe9gkmhg6rquc64qjmlsfqfhfqv8q72crqrylhgc
|
||||||
|
|
@ -40,7 +42,7 @@ sops:
|
||||||
a0V1N2VjUDE4Z3R5MGxMQVNmOVp0bVUK9cppJW33tKFOSvbIn/2Dga8k7/McaTpK
|
a0V1N2VjUDE4Z3R5MGxMQVNmOVp0bVUK9cppJW33tKFOSvbIn/2Dga8k7/McaTpK
|
||||||
m7M+83guMzNoOlpJ/WYU1BaePcM974AgjVR0WD/v+xGBvGKubKHqtw==
|
m7M+83guMzNoOlpJ/WYU1BaePcM974AgjVR0WD/v+xGBvGKubKHqtw==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-08-04T07:58:56Z"
|
lastmodified: "2026-01-21T14:37:21Z"
|
||||||
mac: ENC[AES256_GCM,data:aJw3KK4GMj5/Q06v1C5rdSerdO21cNxpTIJYoxmfhBKudzD7lSL6l+d47kWoB0U4J5jtbs9obWz2MH3CvyPBapjJaSFnYEXk1JuGihf8GK3QrqLAt+dmF2ZD1FBLpQELripueneyHkzT32180hpXGnppNlgOuATlIMSPosvlpVI=,iv:SpGAyTqqbpuxcLkMq7VnLQUoR6oW0ERgnyPaqVHpaN8=,tag:OSNGT8/5E+PRhoR8dIyaSA==,type:str]
|
mac: ENC[AES256_GCM,data:bxr3U1Ig0qjuOcxHeOlOrXO0xtZs0vKTuXn8GE1dJGCFDjVgakbIwiW6+2WNYUbIpipCAwdecgb0jBngwt3zKGS4PMzapUXxl7RoCr5DWCh6kSD4CCUH4v8guuy0k8SMQXDO3CdbUd/5/asIPfxlvEESCQL54X2OJlt5xpE7PsU=,iv:m/lrHHFYXFKCVEOK462II8bcFvw7k4rKEuMOHHmzT/8=,tag:jgEQso2bAShLJERsOHhrKw==,type:str]
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.10.2
|
version: 3.11.0
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,17 @@
|
||||||
imports = [
|
imports = [
|
||||||
./shell.nix
|
./shell.nix
|
||||||
./emulator.nix
|
./emulator.nix
|
||||||
|
./wezterm.nix
|
||||||
|
./nushell.nix
|
||||||
./development.nix
|
./development.nix
|
||||||
./tools.nix
|
./tools.nix
|
||||||
./yazi.nix
|
./yazi.nix
|
||||||
|
./hr
|
||||||
./helix
|
./helix
|
||||||
./nvim
|
./nvim
|
||||||
./zellij
|
./zellij
|
||||||
|
./opencode
|
||||||
|
./gh.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
config = lib.mkIf osConfig.mods.desktop.enable {
|
config = lib.mkIf osConfig.mods.desktop.enable {
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,12 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
nix-direnv.enable = true;
|
nix-direnv.enable = true;
|
||||||
enableZshIntegration = lib.mkIf config.mods.terminal.zsh.enable true;
|
enableZshIntegration = lib.mkIf config.mods.terminal.zsh.enable true;
|
||||||
|
enableNushellIntegration = lib.mkIf config.mods.terminal.nushell.enable true;
|
||||||
};
|
};
|
||||||
|
|
||||||
home.sessionVariables.EDITOR = "nvim";
|
home.sessionVariables.EDITOR = "nvim";
|
||||||
programs.zsh.sessionVariables.EDITOR = "nvim";
|
programs.zsh.sessionVariables = lib.mkIf config.mods.terminal.zsh.enable {
|
||||||
|
EDITOR = "nvim";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
modules/home/terminal/gh.nix
Normal file
30
modules/home/terminal/gh.nix
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.mods.terminal.gh.enable = lib.mkEnableOption "enables gh and gh-dash";
|
||||||
|
|
||||||
|
config = lib.mkIf config.mods.terminal.gh.enable {
|
||||||
|
programs.gh = {
|
||||||
|
enable = true;
|
||||||
|
extensions = [pkgs.gh-dash];
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.gh-dash = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
keybindings = {
|
||||||
|
prs = [
|
||||||
|
{
|
||||||
|
key = "C";
|
||||||
|
command = "nvim -c 'Octo pr edit {{.PrNumber}}'";
|
||||||
|
description = "Open PR in Octo.nvim";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
{
|
{
|
||||||
name = "nix";
|
name = "nix";
|
||||||
auto-format = true;
|
auto-format = true;
|
||||||
formatter.command = "${pkgs.nixfmt-classic}/bin/nixfmt";
|
formatter.command = "${pkgs.nixfmt}/bin/nixfmt";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "rust";
|
name = "rust";
|
||||||
|
|
|
||||||
65
modules/home/terminal/hr/default.nix
Normal file
65
modules/home/terminal/hr/default.nix
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
cfg = config.mods.terminal;
|
||||||
|
|
||||||
|
test-port = "5436";
|
||||||
|
prod-port = "5437";
|
||||||
|
in {
|
||||||
|
options.mods.terminal.hr.enable = lib.mkEnableOption "Hefring (Work Tooling)";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.hr.enable {
|
||||||
|
programs.nushell = lib.mkIf cfg.nushell.enable {
|
||||||
|
extraConfig = ''
|
||||||
|
$env.PROJECT_ID = if ($env | get -o PROJECT_ID | is-empty) { "mk2-test" } else { $env.PROJECT_ID }
|
||||||
|
'' + builtins.readFile ./hr.nu;
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.starship.settings.custom.project_id = {
|
||||||
|
command = "if $env.PROJECT_ID =~ 'prod' { $'(ansi yellow_bold) (ansi blue_bold)($env.PROJECT_ID)(ansi reset)' } else { $'(ansi blue_bold)($env.PROJECT_ID)(ansi reset)' }";
|
||||||
|
when = "not ($env | get -o PROJECT_ID | is-empty)";
|
||||||
|
shell = ["nu" "--no-config-file" "-c"];
|
||||||
|
format = "on $output ";
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.zsh.initContent =
|
||||||
|
''
|
||||||
|
export MK2_TEST_SQL_INSTANCE_USER=gijs
|
||||||
|
export MK2_TEST_SQL_INSTANCE_PASSWORD="$(cat ${config.sops.secrets.google-db-test.path})"
|
||||||
|
export MK2_TEST_SQL_INSTANCE_PORT=${test-port}
|
||||||
|
export MK2_TEST_SQL_INSTANCE_HOST=localhost
|
||||||
|
export MK2_PROD_SQL_INSTANCE_USER=gijs
|
||||||
|
export MK2_PROD_SQL_INSTANCE_PASSWORD="$(cat ${config.sops.secrets.google-db-prod.path})"
|
||||||
|
export MK2_PROD_SQL_INSTANCE_HOST=localhost
|
||||||
|
export MK2_PROD_SQL_INSTANCE_PORT=${prod-port}
|
||||||
|
''
|
||||||
|
+ builtins.readFile ./hr.sh;
|
||||||
|
|
||||||
|
systemd.user.services = let
|
||||||
|
proxy-service = name: port: {
|
||||||
|
"google-db-proxy-${name}" = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Google Cloud SQL Proxy (${name})";
|
||||||
|
After = ["network.target"];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Type = "simple";
|
||||||
|
Environment = [
|
||||||
|
"GOOGLE_APPLICATION_CREDENTIALS=${config.home.homeDirectory}/.config/gcloud/application_default_credentials.json"
|
||||||
|
];
|
||||||
|
ExecStart = "${pkgs.google-cloud-sql-proxy}/bin/cloud-sql-proxy mk2-${name}:europe-west1:mk2-${name}-sql-instance -p ${port}";
|
||||||
|
Restart = "always";
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
WantedBy = ["default.target"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
proxy-service "test" test-port
|
||||||
|
// proxy-service "prod" prod-port;
|
||||||
|
};
|
||||||
|
}
|
||||||
474
modules/home/terminal/hr/hr.nu
Normal file
474
modules/home/terminal/hr/hr.nu
Normal file
|
|
@ -0,0 +1,474 @@
|
||||||
|
# HR - Hefring work tooling for nushell
|
||||||
|
#
|
||||||
|
# This module provides commands for working with Hefring Cloud Run services and Cloud Functions.
|
||||||
|
#
|
||||||
|
# Key features:
|
||||||
|
# - Shell-style argument passing: -key value supports dot notation for nested structures
|
||||||
|
# Example: hr call service -items.0.type "trip" -items.0.id "123"
|
||||||
|
#
|
||||||
|
# - Nushell record syntax with --data flag for complex payloads:
|
||||||
|
# Example: hr call service --data {company_id: "abc", items: [{type: "trip"}]}
|
||||||
|
#
|
||||||
|
# - Automatic type detection: numbers, booleans, and JSON are parsed automatically
|
||||||
|
# Example: -count "42" → number, -active "true" → boolean
|
||||||
|
#
|
||||||
|
# - Pretty display: Payloads are shown as Nushell tables before sending
|
||||||
|
|
||||||
|
def _hr_usage [] {
|
||||||
|
print "Usage: hr <command>"
|
||||||
|
print "Commands:"
|
||||||
|
print " switch Switch PROJECT_ID between mk2-test and mk2-prod"
|
||||||
|
print " call Call a Cloud Run service route"
|
||||||
|
print " cf Call a Cloud Function"
|
||||||
|
print " init py Initialize a python devenv environment (git-ignored)"
|
||||||
|
print " init go Initialize a go devenv environment (git-ignored)"
|
||||||
|
print " init rs Initialize a rust devenv environment (git-ignored)"
|
||||||
|
print " init cpp Initialize a C++ devenv environment (git-ignored)"
|
||||||
|
print " freeze Freeze dependencies to requirements.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_init_devenv [] {
|
||||||
|
if (".gitignore" | path exists) {
|
||||||
|
cp .gitignore .gitignore.bak
|
||||||
|
}
|
||||||
|
|
||||||
|
if (which devenv | is-empty) {
|
||||||
|
error make { msg: "Error: devenv not found in path." }
|
||||||
|
}
|
||||||
|
|
||||||
|
devenv init
|
||||||
|
print "Direnv allowed"
|
||||||
|
|
||||||
|
if (".gitignore.bak" | path exists) {
|
||||||
|
mv .gitignore.bak .gitignore
|
||||||
|
} else if (".gitignore" | path exists) {
|
||||||
|
rm .gitignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_add_ignores [files: list<string>] {
|
||||||
|
let git_dir = (do { git rev-parse --git-dir } | complete)
|
||||||
|
if $git_dir.exit_code != 0 {
|
||||||
|
print "Warning: Not a git repository. Skipping git ignore setup."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let exclude_file = (git rev-parse --git-path info/exclude)
|
||||||
|
mkdir (($exclude_file) | path dirname)
|
||||||
|
|
||||||
|
for file in $files {
|
||||||
|
let already_exists = (
|
||||||
|
if ($exclude_file | path exists) {
|
||||||
|
open $exclude_file | lines | any { |line| $line == $file }
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if not $already_exists {
|
||||||
|
$"($file)\n" | save --append $exclude_file
|
||||||
|
print $"Added ($file) to local git exclude \(($exclude_file)\)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_py_files [] {
|
||||||
|
"
|
||||||
|
{pkgs, ...}: {
|
||||||
|
packages = [ pkgs.google-cloud-sdk pkgs.libpq ];
|
||||||
|
|
||||||
|
languages.python = {
|
||||||
|
enable = true;
|
||||||
|
venv.enable = true;
|
||||||
|
uv = {
|
||||||
|
enable = true;
|
||||||
|
sync = {
|
||||||
|
enable = true;
|
||||||
|
allExtras = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# We use the named index \"google\" defined in uv.toml
|
||||||
|
env.UV_INDEX_GOOGLE_USERNAME = \"oauth2accesstoken\";
|
||||||
|
env.PROJECT_ID = \"mk2-test\";
|
||||||
|
|
||||||
|
enterShell = ''
|
||||||
|
export PATH=\"$DEVENV_STATE/venv/bin:$PATH\"
|
||||||
|
if ! gcloud auth print-access-token >/dev/null 2>&1; then
|
||||||
|
echo \"⚠️ gcloud not authenticated. Run 'gcloud auth login' to access Google Artifact Registry.\"
|
||||||
|
else
|
||||||
|
export UV_INDEX_GOOGLE_PASSWORD=$(gcloud auth print-access-token)
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
" | save -f devenv.nix
|
||||||
|
|
||||||
|
"
|
||||||
|
[[index]]
|
||||||
|
name = \"google\"
|
||||||
|
url = \"https://europe-west1-python.pkg.dev/mk2-prod/python-packages/simple/\"
|
||||||
|
" | save -f uv.toml
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_rs_files [] {
|
||||||
|
"
|
||||||
|
{pkgs, ...}: {
|
||||||
|
languages.rust = {
|
||||||
|
enable = true;
|
||||||
|
channel = \"stable\";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
" | save -f devenv.nix
|
||||||
|
|
||||||
|
"
|
||||||
|
inputs:
|
||||||
|
rust-overlay:
|
||||||
|
url: github:oxalica/rust-overlay
|
||||||
|
inputs:
|
||||||
|
nixpkgs:
|
||||||
|
follows: nixpkgs
|
||||||
|
" | save -f devenv.yaml
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_cpp_files [] {
|
||||||
|
"
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
# Use glibc-compatible static openssl to match system libs
|
||||||
|
staticOpenSSL = pkgs.openssl.override { static = true; };
|
||||||
|
|
||||||
|
# Shim to satisfy CMake looking for \"ssl.a\"
|
||||||
|
compatOpenSSL = pkgs.runCommand \"openssl-compat\" {} ''
|
||||||
|
mkdir -p $out/lib
|
||||||
|
ln -s ${staticOpenSSL.out}/lib/libssl.a $out/lib/ssl.a
|
||||||
|
ln -s ${staticOpenSSL.out}/lib/libcrypto.a $out/lib/crypto.a
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
packages = [
|
||||||
|
pkgs.cmake
|
||||||
|
pkgs.clang-tools
|
||||||
|
pkgs.pkg-config
|
||||||
|
pkgs.mosquitto
|
||||||
|
|
||||||
|
staticOpenSSL
|
||||||
|
compatOpenSSL
|
||||||
|
];
|
||||||
|
# Explicitly add lib paths so linker finds -lssl AND ssl.a
|
||||||
|
env.LIBRARY_PATH = \"${staticOpenSSL.out}/lib:${compatOpenSSL}/lib\";
|
||||||
|
env.CPATH = \"${staticOpenSSL.dev}/include\";
|
||||||
|
|
||||||
|
languages.cplusplus.enable = true;
|
||||||
|
}
|
||||||
|
" | save -f devenv.nix
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_go_files [] {
|
||||||
|
"
|
||||||
|
{pkgs, ...}: {
|
||||||
|
languages.go = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
" | save -f devenv.nix
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_init_base [name: string, write_files: closure, ignores: list<string>] {
|
||||||
|
print $"Initializing ($name) devenv..."
|
||||||
|
|
||||||
|
# 1. Init devenv
|
||||||
|
_hr_init_devenv
|
||||||
|
|
||||||
|
# 2. Write language-specific files
|
||||||
|
do $write_files
|
||||||
|
|
||||||
|
# 3. Add to local git exclude
|
||||||
|
let base_ignores = [
|
||||||
|
".devenv*"
|
||||||
|
".direnv"
|
||||||
|
"devenv.nix"
|
||||||
|
"devenv.yaml"
|
||||||
|
"devenv.lock"
|
||||||
|
".envrc"
|
||||||
|
]
|
||||||
|
_hr_add_ignores ($base_ignores ++ $ignores)
|
||||||
|
|
||||||
|
direnv allow
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_setpath [data: any, path: list, value: any] {
|
||||||
|
# Recursively build nested structure, similar to jq's setpath
|
||||||
|
if ($path | is-empty) {
|
||||||
|
$value
|
||||||
|
} else if ($path | length) == 1 {
|
||||||
|
$data | upsert ($path | first) $value
|
||||||
|
} else {
|
||||||
|
let key = ($path | first)
|
||||||
|
let rest = ($path | skip 1)
|
||||||
|
let next_key = ($rest | first)
|
||||||
|
|
||||||
|
# Check if key exists in data and get intermediate value
|
||||||
|
let key_type = ($key | describe)
|
||||||
|
let data_type = ($data | describe)
|
||||||
|
let is_list = ($data_type | str starts-with "list") or ($data_type | str starts-with "table")
|
||||||
|
|
||||||
|
# Determine if key exists and get intermediate structure
|
||||||
|
let intermediate = if $key_type == "int" and $is_list {
|
||||||
|
# Array index
|
||||||
|
if $key < ($data | length) {
|
||||||
|
$data | get $key
|
||||||
|
} else {
|
||||||
|
# Index doesn't exist, create structure based on next key
|
||||||
|
if ($next_key | describe) == "int" { [] } else { {} }
|
||||||
|
}
|
||||||
|
} else if $key_type != "int" {
|
||||||
|
# Object key
|
||||||
|
if $key in $data {
|
||||||
|
$data | get $key
|
||||||
|
} else {
|
||||||
|
# Key doesn't exist, create structure based on next key
|
||||||
|
if ($next_key | describe) == "int" { [] } else { {} }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Data is not a list but key is int - create array
|
||||||
|
if ($next_key | describe) == "int" { [] } else { {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Recursively set the rest of the path
|
||||||
|
let updated_intermediate = (_hr_setpath $intermediate $rest $value)
|
||||||
|
|
||||||
|
# Update data with the new intermediate value
|
||||||
|
$data | upsert $key $updated_intermediate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_add_json_field [json: string, key: string, value: string] {
|
||||||
|
# Determine if value should be parsed as raw JSON or treated as a string
|
||||||
|
let is_bool = ($value == "true" or $value == "false")
|
||||||
|
let is_number = ($value =~ '^-?(0|[1-9][0-9]*)(\.[0-9]+)?$')
|
||||||
|
let is_json_container = ($value =~ '^\[' or $value =~ '^\{')
|
||||||
|
|
||||||
|
# Parse the value into the appropriate type
|
||||||
|
let parsed_value = if $is_bool or $is_number {
|
||||||
|
$value | from json
|
||||||
|
} else if $is_json_container {
|
||||||
|
let parsed = (do { $value | from json } | complete)
|
||||||
|
if $parsed.exit_code == 0 {
|
||||||
|
$value | from json
|
||||||
|
} else {
|
||||||
|
print $"Warning: Value for '($key)' looks like JSON but is invalid. Treating as string." --stderr
|
||||||
|
$value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$value
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert key path (e.g., "items.0.type") to a list of path segments
|
||||||
|
# Numbers are converted to integers for array indexing
|
||||||
|
let path_segments = ($key | split row "." | each { |segment|
|
||||||
|
if ($segment =~ '^[0-9]+$') {
|
||||||
|
$segment | into int
|
||||||
|
} else {
|
||||||
|
$segment
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let data = ($json | from json)
|
||||||
|
_hr_setpath $data $path_segments $parsed_value | to json
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_parse_flags [args: list<string>] {
|
||||||
|
mut json_str = "{}"
|
||||||
|
mut i = 0
|
||||||
|
while $i < ($args | length) {
|
||||||
|
let arg = ($args | get $i)
|
||||||
|
if ($arg | str starts-with "-") {
|
||||||
|
let key = ($arg | str replace --regex '^-+' '')
|
||||||
|
let next_i = $i + 1
|
||||||
|
if $next_i >= ($args | length) {
|
||||||
|
error make { msg: $"Error: Missing value for option ($key)" }
|
||||||
|
}
|
||||||
|
let next = ($args | get $next_i)
|
||||||
|
if ($next | str starts-with "-") {
|
||||||
|
error make { msg: $"Error: Missing value for option ($key)" }
|
||||||
|
}
|
||||||
|
$json_str = (_hr_add_json_field $json_str $key $next)
|
||||||
|
$i = $i + 2
|
||||||
|
} else {
|
||||||
|
error make { msg: $"Error: Unexpected argument '($arg)'" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$json_str | from json
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_call [args: list<string>] {
|
||||||
|
if ($args | is-empty) {
|
||||||
|
print "Usage: hr call <route-name>[/path] [OPTIONS]"
|
||||||
|
print ""
|
||||||
|
print "Options:"
|
||||||
|
print " -key value Set JSON field (supports dot notation, e.g., -items.0.type \"trip\")"
|
||||||
|
print " --data <record> Pass structured data as a Nushell record"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let route_arg = ($args | first)
|
||||||
|
let rest = ($args | skip 1)
|
||||||
|
|
||||||
|
let parts = if ($route_arg | str contains "/") {
|
||||||
|
let service = ($route_arg | split row "/" | first)
|
||||||
|
let path = "/" + ($route_arg | split row "/" | skip 1 | str join "/")
|
||||||
|
{ service: $service, path: $path }
|
||||||
|
} else {
|
||||||
|
{ service: $route_arg, path: "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
let project_number = if $env.PROJECT_ID == "mk2-prod" {
|
||||||
|
"1013087376822"
|
||||||
|
} else {
|
||||||
|
"322048751601"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if --data flag is present
|
||||||
|
let data_idx = ($rest | enumerate | where item == "--data" | get index.0? | default (-1))
|
||||||
|
|
||||||
|
let payload_record = if $data_idx >= 0 {
|
||||||
|
# Use --data record
|
||||||
|
if ($data_idx + 1) >= ($rest | length) {
|
||||||
|
error make { msg: "Error: --data requires a record argument" }
|
||||||
|
}
|
||||||
|
let data_str = ($rest | get ($data_idx + 1))
|
||||||
|
# Try to parse as Nushell code to get a record
|
||||||
|
try {
|
||||||
|
nu -c $data_str
|
||||||
|
} catch {
|
||||||
|
error make { msg: $"Error: --data argument must be a valid Nushell record, got: ($data_str)" }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Use -key value pairs
|
||||||
|
_hr_parse_flags $rest
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload = ($payload_record | to json -r)
|
||||||
|
let url = $"https://($parts.service)-($project_number).europe-west1.run.app($parts.path)"
|
||||||
|
|
||||||
|
print $"Calling ($url)..."
|
||||||
|
print ($payload | from json)
|
||||||
|
|
||||||
|
let token = (gcloud auth print-identity-token)
|
||||||
|
^curl -s -S -L $url -H $"Authorization: Bearer ($token)" -H "Content-Type: application/json" -d $payload
|
||||||
|
}
|
||||||
|
|
||||||
|
def _hr_cf [args: list<string>] {
|
||||||
|
if ($args | is-empty) {
|
||||||
|
print "Usage: hr cf <function-name> [OPTIONS]"
|
||||||
|
print ""
|
||||||
|
print "Options:"
|
||||||
|
print " -key value Set JSON field (supports dot notation, e.g., -items.0.type \"trip\")"
|
||||||
|
print " --data <record> Pass structured data as a Nushell record"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let function_name = ($args | first)
|
||||||
|
let rest = ($args | skip 1)
|
||||||
|
|
||||||
|
# Check if --data flag is present
|
||||||
|
let data_idx = ($rest | enumerate | where item == "--data" | get index.0? | default (-1))
|
||||||
|
|
||||||
|
let payload_record = if $data_idx >= 0 {
|
||||||
|
# Use --data record
|
||||||
|
if ($data_idx + 1) >= ($rest | length) {
|
||||||
|
error make { msg: "Error: --data requires a record argument" }
|
||||||
|
}
|
||||||
|
let data_str = ($rest | get ($data_idx + 1))
|
||||||
|
# Try to parse as Nushell code to get a record
|
||||||
|
try {
|
||||||
|
nu -c $data_str
|
||||||
|
} catch {
|
||||||
|
error make { msg: $"Error: --data argument must be a valid Nushell record, got: ($data_str)" }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Use -key value pairs
|
||||||
|
_hr_parse_flags $rest
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload = ($payload_record | to json -r)
|
||||||
|
let url = $"https://europe-west1-($env.PROJECT_ID).cloudfunctions.net/($function_name)"
|
||||||
|
|
||||||
|
print $"Calling ($url)..."
|
||||||
|
print ($payload | from json)
|
||||||
|
|
||||||
|
let token = (gcloud auth print-identity-token)
|
||||||
|
^curl -s -S -L $url -H $"Authorization: Bearer ($token)" -H "Content-Type: application/json" -d $payload
|
||||||
|
}
|
||||||
|
|
||||||
|
# HR - Hefring work tooling
|
||||||
|
export def --env --wrapped hr [...args: string] {
|
||||||
|
if ($args | is-empty) {
|
||||||
|
_hr_usage
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmd = ($args | first)
|
||||||
|
let rest = ($args | skip 1)
|
||||||
|
|
||||||
|
match $cmd {
|
||||||
|
"switch" => {
|
||||||
|
if ($rest | is-empty) {
|
||||||
|
if $env.PROJECT_ID == "mk2-test" {
|
||||||
|
$env.PROJECT_ID = "mk2-prod"
|
||||||
|
print "Switched PROJECT_ID to mk2-prod"
|
||||||
|
} else {
|
||||||
|
$env.PROJECT_ID = "mk2-test"
|
||||||
|
print "Switched PROJECT_ID to mk2-test"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match ($rest | first) {
|
||||||
|
"test" => {
|
||||||
|
$env.PROJECT_ID = "mk2-test"
|
||||||
|
print "Set PROJECT_ID to mk2-test"
|
||||||
|
}
|
||||||
|
"prod" => {
|
||||||
|
$env.PROJECT_ID = "mk2-prod"
|
||||||
|
print "Set PROJECT_ID to mk2-prod"
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
print "Usage: hr switch [test|prod]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"init" => {
|
||||||
|
if ($rest | is-empty) {
|
||||||
|
_hr_usage
|
||||||
|
return
|
||||||
|
}
|
||||||
|
match ($rest | first) {
|
||||||
|
"py" => { _hr_init_base "Python" { _hr_py_files } ["uv.lock" "uv.toml"] }
|
||||||
|
"rs" => { _hr_init_base "Rust" { _hr_rs_files } [] }
|
||||||
|
"go" => { _hr_init_base "Go" { _hr_go_files } [] }
|
||||||
|
"cpp" => {
|
||||||
|
_hr_init_base "C++" { _hr_cpp_files } []
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
make -j (sys cpu | length)
|
||||||
|
cp compile_commands.json ..
|
||||||
|
}
|
||||||
|
_ => { _hr_usage }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"freeze" => {
|
||||||
|
let extra_index_url = "https://europe-west1-python.pkg.dev/mk2-prod/python-packages/simple/"
|
||||||
|
uv pip install keyrings.google-artifactregistry-auth==1.1.2 keyring
|
||||||
|
uv pip install --no-cache -e ".[test]" --extra-index-url $extra_index_url --keyring-provider subprocess
|
||||||
|
$"--extra-index-url ($extra_index_url)\n" | save -f requirements.txt
|
||||||
|
uv pip freeze --exclude-editable | save --append requirements.txt
|
||||||
|
}
|
||||||
|
"call" => {
|
||||||
|
_hr_call $rest
|
||||||
|
}
|
||||||
|
"cf" => {
|
||||||
|
_hr_cf $rest
|
||||||
|
}
|
||||||
|
_ => { _hr_usage }
|
||||||
|
}
|
||||||
|
}
|
||||||
414
modules/home/terminal/hr/hr.sh
Normal file
414
modules/home/terminal/hr/hr.sh
Normal file
|
|
@ -0,0 +1,414 @@
|
||||||
|
# Set default PROJECT_ID if not already set
|
||||||
|
if [[ -z "$PROJECT_ID" ]]; then
|
||||||
|
export PROJECT_ID="mk2-test"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_hr_usage() {
|
||||||
|
echo "Usage: hr <command>"
|
||||||
|
echo "Commands:"
|
||||||
|
echo " switch Switch PROJECT_ID between mk2-test and mk2-prod"
|
||||||
|
echo " call Call a Cloud Run service route"
|
||||||
|
echo " cf Call a Cloud Function"
|
||||||
|
echo " init py Initialize a python devenv environment (git-ignored)"
|
||||||
|
echo " init go Initialize a go devenv environment (git-ignored)"
|
||||||
|
echo " freeze Freeze dependencies to requirements.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_init_devenv() {
|
||||||
|
if [ -f .gitignore ]; then
|
||||||
|
cp .gitignore .gitignore.bak
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v devenv >/dev/null; then
|
||||||
|
devenv init
|
||||||
|
echo "Direnv allowed"
|
||||||
|
else
|
||||||
|
echo "Error: devenv not found in path."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f .gitignore.bak ]; then
|
||||||
|
mv .gitignore.bak .gitignore
|
||||||
|
elif [ -f .gitignore ]; then
|
||||||
|
rm .gitignore
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_add_ignores() {
|
||||||
|
if git rev-parse --git-dir >/dev/null 2>&1; then
|
||||||
|
EXCLUDE_FILE=$(git rev-parse --git-path info/exclude)
|
||||||
|
mkdir -p "$(dirname "$EXCLUDE_FILE")"
|
||||||
|
|
||||||
|
for file in "$@"; do
|
||||||
|
if ! grep -Fxq "$file" "$EXCLUDE_FILE" 2>/dev/null; then
|
||||||
|
echo "$file" >>"$EXCLUDE_FILE"
|
||||||
|
echo "Added $file to local git exclude ($EXCLUDE_FILE)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "Warning: Not a git repository. Skipping git ignore setup."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_py_files() {
|
||||||
|
cat <<EOF >devenv.nix
|
||||||
|
{pkgs, ...}: {
|
||||||
|
packages = [ pkgs.google-cloud-sdk pkgs.libpq ];
|
||||||
|
|
||||||
|
languages.python = {
|
||||||
|
enable = true;
|
||||||
|
venv.enable = true;
|
||||||
|
uv = {
|
||||||
|
enable = true;
|
||||||
|
sync = {
|
||||||
|
enable = true;
|
||||||
|
allExtras = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# We use the named index "google" defined in uv.toml
|
||||||
|
env.UV_INDEX_GOOGLE_USERNAME = "oauth2accesstoken";
|
||||||
|
env.PROJECT_ID = "mk2-test";
|
||||||
|
|
||||||
|
enterShell = ''
|
||||||
|
export PATH="\$DEVENV_STATE/venv/bin:\$PATH"
|
||||||
|
if ! gcloud auth print-access-token >/dev/null 2>&1; then
|
||||||
|
echo "⚠️ gcloud not authenticated. Run 'gcloud auth login' to access Google Artifact Registry."
|
||||||
|
else
|
||||||
|
export UV_INDEX_GOOGLE_PASSWORD=\$(gcloud auth print-access-token)
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF >uv.toml
|
||||||
|
[[index]]
|
||||||
|
name = "google"
|
||||||
|
url = "https://europe-west1-python.pkg.dev/mk2-prod/python-packages/simple/"
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_rs_files() {
|
||||||
|
cat <<EOF >devenv.nix
|
||||||
|
{pkgs, ...}: {
|
||||||
|
languages.rust = {
|
||||||
|
enable = true;
|
||||||
|
channel = "stable";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF >devenv.yaml
|
||||||
|
inputs:
|
||||||
|
rust-overlay:
|
||||||
|
url: github:oxalica/rust-overlay
|
||||||
|
inputs:
|
||||||
|
nixpkgs:
|
||||||
|
follows: nixpkgs
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_cpp_files() {
|
||||||
|
cat <<EOF >devenv.nix
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
# Use glibc-compatible static openssl to match system libs
|
||||||
|
staticOpenSSL = pkgs.openssl.override { static = true; };
|
||||||
|
|
||||||
|
# Shim to satisfy CMake looking for "ssl.a"
|
||||||
|
compatOpenSSL = pkgs.runCommand "openssl-compat" {} ''
|
||||||
|
mkdir -p \$out/lib
|
||||||
|
ln -s \${staticOpenSSL.out}/lib/libssl.a \$out/lib/ssl.a
|
||||||
|
ln -s \${staticOpenSSL.out}/lib/libcrypto.a \$out/lib/crypto.a
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
packages = [
|
||||||
|
pkgs.cmake
|
||||||
|
pkgs.clang-tools
|
||||||
|
pkgs.pkg-config
|
||||||
|
pkgs.mosquitto
|
||||||
|
|
||||||
|
staticOpenSSL
|
||||||
|
compatOpenSSL
|
||||||
|
];
|
||||||
|
# Explicitly add lib paths so linker finds -lssl AND ssl.a
|
||||||
|
env.LIBRARY_PATH = "\${staticOpenSSL.out}/lib:\${compatOpenSSL}/lib";
|
||||||
|
env.CPATH = "\${staticOpenSSL.dev}/include";
|
||||||
|
|
||||||
|
languages.cplusplus.enable = true;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_go_files() {
|
||||||
|
cat <<EOF >devenv.nix
|
||||||
|
{pkgs, ...}: {
|
||||||
|
languages.go = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_init_base() {
|
||||||
|
local name="$1"
|
||||||
|
local func="$2"
|
||||||
|
shift 2
|
||||||
|
local ignores=("$@")
|
||||||
|
echo "Initializing $name devenv..."
|
||||||
|
|
||||||
|
# 1. Init devenv
|
||||||
|
_hr_init_devenv
|
||||||
|
|
||||||
|
# 2. Replace devenv.nix
|
||||||
|
"$func"
|
||||||
|
|
||||||
|
# 3. Add to local git exclude
|
||||||
|
IGNORES=(
|
||||||
|
".devenv*"
|
||||||
|
".direnv"
|
||||||
|
"devenv.nix"
|
||||||
|
"devenv.yaml"
|
||||||
|
"devenv.lock"
|
||||||
|
".envrc"
|
||||||
|
"${ignores[@]}"
|
||||||
|
)
|
||||||
|
_hr_add_ignores "${IGNORES[@]}"
|
||||||
|
|
||||||
|
direnv allow
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_init_py() {
|
||||||
|
IGNORES=(
|
||||||
|
"uv.lock"
|
||||||
|
"uv.toml"
|
||||||
|
)
|
||||||
|
_hr_init_base "Python" _hr_py_files "${IGNORES[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_init_rs() {
|
||||||
|
_hr_init_base "Rust" _hr_rs_files
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_init_cpp() {
|
||||||
|
_hr_init_base "C++" _hr_cpp_files
|
||||||
|
mkdir -p build &&
|
||||||
|
cd build &&
|
||||||
|
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Release .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
cp compile_commands.json ..
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_init_go() {
|
||||||
|
_hr_init_base "Go" _hr_go_files
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_freeze() {
|
||||||
|
local extra_index_url="https://europe-west1-python.pkg.dev/mk2-prod/python-packages/simple/"
|
||||||
|
|
||||||
|
# Install the auth plugin and keyring CLI
|
||||||
|
uv pip install keyrings.google-artifactregistry-auth==1.1.2 keyring
|
||||||
|
|
||||||
|
# Install project dependencies using the subprocess keyring provider
|
||||||
|
uv pip install --no-cache -e ".[test]" --extra-index-url "${extra_index_url}" --keyring-provider subprocess
|
||||||
|
|
||||||
|
# Generate requirements.txt
|
||||||
|
echo "--extra-index-url ${extra_index_url}" >requirements.txt
|
||||||
|
uv pip freeze --exclude-editable >>requirements.txt
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_add_json_field() {
|
||||||
|
local json="$1"
|
||||||
|
local key="$2"
|
||||||
|
local value="$3"
|
||||||
|
local jq_opt="--arg"
|
||||||
|
|
||||||
|
# Check if explicit boolean
|
||||||
|
if [[ "$value" == "true" || "$value" == "false" ]]; then
|
||||||
|
jq_opt="--argjson"
|
||||||
|
# Check if number (integer or float, no leading zeros unless just 0)
|
||||||
|
elif [[ "$value" =~ ^-?(0|[1-9][0-9]*)(\.[0-9]+)?$ ]]; then
|
||||||
|
jq_opt="--argjson"
|
||||||
|
# Check if object or array
|
||||||
|
elif [[ "$value" == "["* || "$value" == "{"* ]]; then
|
||||||
|
if echo "$value" | jq empty >/dev/null 2>&1; then
|
||||||
|
jq_opt="--argjson"
|
||||||
|
else
|
||||||
|
# Warn to stderr, but proceed as string
|
||||||
|
echo "Warning: Value for '$key' looks like JSON but is invalid. Treating as string." >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply the value at the path defined by the key (dot-notation supported)
|
||||||
|
# paths like items.0.id are converted to ["items", 0, "id"]
|
||||||
|
echo "$json" | jq --arg k "$key" $jq_opt v "$value" \
|
||||||
|
'setpath($k | split(".") | map(if test("^[0-9]+$") then tonumber else . end); $v)'
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_call() {
|
||||||
|
local route_arg="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [[ -z "$route_arg" ]]; then
|
||||||
|
echo "Usage: hr call <route-name>[/path] <options>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local service_name
|
||||||
|
local url_path
|
||||||
|
|
||||||
|
if [[ "$route_arg" == */* ]]; then
|
||||||
|
service_name="${route_arg%%/*}"
|
||||||
|
url_path="/${route_arg#*/}"
|
||||||
|
else
|
||||||
|
service_name="$route_arg"
|
||||||
|
url_path=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
local project_number
|
||||||
|
if [[ "$PROJECT_ID" == "mk2-prod" ]]; then
|
||||||
|
project_number="1013087376822"
|
||||||
|
else
|
||||||
|
project_number="322048751601"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq >/dev/null; then
|
||||||
|
echo "Error: jq is required but not installed."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local json_payload="{}"
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
if [[ "$1" == -* ]]; then
|
||||||
|
local key="${1#-}"
|
||||||
|
if [[ -z "$2" || "$2" == -* ]]; then
|
||||||
|
echo "Error: Missing value for option $key"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
local value="$2"
|
||||||
|
|
||||||
|
json_payload=$(_hr_add_json_field "$json_payload" "$key" "$value")
|
||||||
|
shift 2
|
||||||
|
else
|
||||||
|
echo "Error: Unexpected argument '$1'"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
local url="https://${service_name}-${project_number}.europe-west1.run.app${url_path}"
|
||||||
|
|
||||||
|
echo "Calling $url..."
|
||||||
|
echo "$json_payload"
|
||||||
|
|
||||||
|
curl "$url" \
|
||||||
|
-H "Authorization: bearer $(gcloud auth print-identity-token)" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$json_payload"
|
||||||
|
}
|
||||||
|
|
||||||
|
_hr_cf() {
|
||||||
|
local function_name="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [[ -z "$function_name" ]]; then
|
||||||
|
echo "Usage: hr cf <function-name> <options>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq >/dev/null; then
|
||||||
|
echo "Error: jq is required but not installed."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local json_payload="{}"
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
if [[ "$1" == -* ]]; then
|
||||||
|
local key="${1#-}"
|
||||||
|
if [[ -z "$2" || "$2" == -* ]]; then
|
||||||
|
echo "Error: Missing value for option $key"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
local value="$2"
|
||||||
|
|
||||||
|
json_payload=$(_hr_add_json_field "$json_payload" "$key" "$value")
|
||||||
|
shift 2
|
||||||
|
else
|
||||||
|
echo "Error: Unexpected argument '$1'"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
local url="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/${function_name}"
|
||||||
|
|
||||||
|
echo "Calling $url..."
|
||||||
|
echo "$json_payload"
|
||||||
|
|
||||||
|
curl "$url" \
|
||||||
|
-H "Authorization: bearer $(gcloud auth print-identity-token)" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$json_payload"
|
||||||
|
}
|
||||||
|
|
||||||
|
hr() {
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
_hr_usage
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local command="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [[ "$command" == "switch" ]]; then
|
||||||
|
if [[ -z "$1" ]]; then
|
||||||
|
# Toggle between test and prod
|
||||||
|
if [[ "$PROJECT_ID" == "mk2-test" ]]; then
|
||||||
|
export PROJECT_ID="mk2-prod"
|
||||||
|
echo "Switched PROJECT_ID to mk2-prod"
|
||||||
|
else
|
||||||
|
export PROJECT_ID="mk2-test"
|
||||||
|
echo "Switched PROJECT_ID to mk2-test"
|
||||||
|
fi
|
||||||
|
elif [[ "$1" == "test" ]]; then
|
||||||
|
export PROJECT_ID="mk2-test"
|
||||||
|
echo "Set PROJECT_ID to mk2-test"
|
||||||
|
elif [[ "$1" == "prod" ]]; then
|
||||||
|
export PROJECT_ID="mk2-prod"
|
||||||
|
echo "Set PROJECT_ID to mk2-prod"
|
||||||
|
else
|
||||||
|
echo "Usage: hr switch [test|prod]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run original logic in a subshell to preserve set -e behavior without affecting current shell
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
# Restore arguments for processing
|
||||||
|
set -- "$command" "$@"
|
||||||
|
|
||||||
|
if [ "$1" = "init" ] && [ "$2" = "py" ]; then
|
||||||
|
_hr_init_py
|
||||||
|
elif [ "$1" = "init" ] && [ "$2" = "rs" ]; then
|
||||||
|
_hr_init_rs
|
||||||
|
elif [ "$1" = "init" ] && [ "$2" = "go" ]; then
|
||||||
|
_hr_init_go
|
||||||
|
elif [ "$1" = "init" ] && [ "$2" = "cpp" ]; then
|
||||||
|
_hr_init_cpp
|
||||||
|
elif [ "$1" = "freeze" ]; then
|
||||||
|
_hr_freeze
|
||||||
|
elif [ "$1" = "call" ]; then
|
||||||
|
shift
|
||||||
|
_hr_call "$@"
|
||||||
|
elif [ "$1" = "cf" ]; then
|
||||||
|
shift
|
||||||
|
_hr_cf "$@"
|
||||||
|
else
|
||||||
|
_hr_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
}
|
||||||
79
modules/home/terminal/nushell.nix
Normal file
79
modules/home/terminal/nushell.nix
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
cfg = config.mods.terminal;
|
||||||
|
|
||||||
|
aliases = {
|
||||||
|
la = "ls -la";
|
||||||
|
".." = "cd ..";
|
||||||
|
"..." = "cd ../..";
|
||||||
|
"...." = "cd ../../..";
|
||||||
|
"....." = "cd ../../../..";
|
||||||
|
"......" = "cd ../../../../..";
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
options.mods.terminal.nushell.enable = lib.mkEnableOption "enables nushell";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.nushell.enable {
|
||||||
|
programs.nushell = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
shellAliases = aliases;
|
||||||
|
|
||||||
|
# vi mode + sensible defaults via flat assignments (avoids clobbering other modules)
|
||||||
|
settings = {
|
||||||
|
show_banner = false;
|
||||||
|
edit_mode = "vi";
|
||||||
|
cursor_shape = {
|
||||||
|
vi_insert = "line";
|
||||||
|
vi_normal = "block";
|
||||||
|
};
|
||||||
|
history = {
|
||||||
|
max_size = 2097152;
|
||||||
|
sync_on_enter = true;
|
||||||
|
file_format = "sqlite";
|
||||||
|
isolation = false;
|
||||||
|
};
|
||||||
|
completions = {
|
||||||
|
case_sensitive = false;
|
||||||
|
quick = true;
|
||||||
|
partial = true;
|
||||||
|
algorithm = "fuzzy";
|
||||||
|
};
|
||||||
|
table.mode = "rounded";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Append the / keybinding after all integrations (including atuin) are sourced,
|
||||||
|
# so _atuin_search_cmd is defined when this runs.
|
||||||
|
extraConfig = lib.mkAfter ''
|
||||||
|
$env.config = (
|
||||||
|
$env.config | upsert keybindings (
|
||||||
|
$env.config.keybindings | append {
|
||||||
|
name: atuin_search_vi_normal
|
||||||
|
modifier: none
|
||||||
|
keycode: char_/
|
||||||
|
mode: vi_normal
|
||||||
|
event: { send: executehostcommand cmd: (_atuin_search_cmd) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Carry over zsh session variables
|
||||||
|
extraEnv = lib.optionalString config.mods.terminal.development.enable ''
|
||||||
|
$env.EDITOR = "nvim"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Starship prompt (same as zsh)
|
||||||
|
programs.starship.enable = true;
|
||||||
|
|
||||||
|
# direnv nushell integration
|
||||||
|
programs.direnv = lib.mkIf config.mods.terminal.development.enable {
|
||||||
|
enableNushellIntegration = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ in {
|
||||||
imports = [
|
imports = [
|
||||||
inputs.nvf.homeManagerModules.default
|
inputs.nvf.homeManagerModules.default
|
||||||
./obsidian.nix
|
./obsidian.nix
|
||||||
|
./octo.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
config = lib.mkIf config.mods.nvim.enable {
|
config = lib.mkIf config.mods.nvim.enable {
|
||||||
|
|
@ -60,6 +61,13 @@ in {
|
||||||
action = "<cmd>lua vim.lsp.buf.definition()<CR>";
|
action = "<cmd>lua vim.lsp.buf.definition()<CR>";
|
||||||
desc = "Go to Definition";
|
desc = "Go to Definition";
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
key = "<C-k>";
|
||||||
|
mode = ["n"];
|
||||||
|
action = "<cmd>FzfLua combine pickers=keymaps;commands<CR>";
|
||||||
|
silent = true;
|
||||||
|
desc = "FzfLua keymaps and commands";
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
languages = {
|
languages = {
|
||||||
|
|
@ -93,6 +101,7 @@ in {
|
||||||
|
|
||||||
statusline.lualine.enable = true;
|
statusline.lualine.enable = true;
|
||||||
telescope.enable = true;
|
telescope.enable = true;
|
||||||
|
fzf-lua.enable = true;
|
||||||
autocomplete.nvim-cmp.enable = true;
|
autocomplete.nvim-cmp.enable = true;
|
||||||
autopairs.nvim-autopairs.enable = true;
|
autopairs.nvim-autopairs.enable = true;
|
||||||
tabline.nvimBufferline.enable = true;
|
tabline.nvimBufferline.enable = true;
|
||||||
|
|
@ -103,6 +112,7 @@ in {
|
||||||
clipboard = {
|
clipboard = {
|
||||||
enable = true;
|
enable = true;
|
||||||
providers.xclip.enable = true;
|
providers.xclip.enable = true;
|
||||||
|
registers = "unnamed,unnamedplus";
|
||||||
};
|
};
|
||||||
|
|
||||||
mini = {
|
mini = {
|
||||||
|
|
|
||||||
54
modules/home/terminal/nvim/octo.nix
Normal file
54
modules/home/terminal/nvim/octo.nix
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.mods.octo.enable =
|
||||||
|
lib.mkEnableOption "enables octo";
|
||||||
|
|
||||||
|
config = lib.mkIf config.mods.octo.enable {
|
||||||
|
programs.nvf.settings.vim.lazy.plugins."octo.nvim" = {
|
||||||
|
package = pkgs.vimPlugins.octo-nvim;
|
||||||
|
setupModule = "octo";
|
||||||
|
setupOpts = {
|
||||||
|
picker = "telescope";
|
||||||
|
enable_builtin = true;
|
||||||
|
};
|
||||||
|
cmd = ["Octo"];
|
||||||
|
keys = [
|
||||||
|
{
|
||||||
|
key = "<leader>oi";
|
||||||
|
mode = "n";
|
||||||
|
action = "<CMD>Octo issue list<CR>";
|
||||||
|
desc = "List GitHub Issues";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "<leader>op";
|
||||||
|
mode = "n";
|
||||||
|
action = "<CMD>Octo pr list<CR>";
|
||||||
|
desc = "List GitHub PullRequests";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "<leader>od";
|
||||||
|
mode = "n";
|
||||||
|
action = "<CMD>Octo discussion list<CR>";
|
||||||
|
desc = "List GitHub Discussions";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "<leader>on";
|
||||||
|
mode = "n";
|
||||||
|
action = "<CMD>Octo notification list<CR>";
|
||||||
|
desc = "List GitHub Notifications";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "<leader>os";
|
||||||
|
mode = "n";
|
||||||
|
action = "function() require('octo.utils').create_base_search_command { include_current_repo = true } end";
|
||||||
|
lua = true;
|
||||||
|
desc = "Search GitHub";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
38
modules/home/terminal/opencode/dcg.nix
Normal file
38
modules/home/terminal/opencode/dcg.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchFromGitHub,
|
||||||
|
rustPlatform,
|
||||||
|
openssl,
|
||||||
|
pkg-config,
|
||||||
|
git,
|
||||||
|
}:
|
||||||
|
rustPlatform.buildRustPackage (finalAttrs: {
|
||||||
|
pname = "dcg";
|
||||||
|
version = "v0.4.0";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "Dicklesworthstone";
|
||||||
|
repo = "destructive_command_guard";
|
||||||
|
tag = finalAttrs.version;
|
||||||
|
hash = "sha256-tkjHhSMoLRV56AwUa0DkoDMoEj6gUZx/ih0VTC9C+4o=";
|
||||||
|
};
|
||||||
|
|
||||||
|
cargoHash = "sha256-G6cOjl5tLdjBg7A+Itnk/t6tLzoU7gKYOTYlZm3HSlA=";
|
||||||
|
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkg-config
|
||||||
|
openssl
|
||||||
|
openssl.dev
|
||||||
|
git
|
||||||
|
];
|
||||||
|
PKG_CONFIG_PATH = "${openssl.dev}/lib/pkgconfig";
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "A high-performance hook for AI coding agents that blocks destructive commands before they execute, protecting your work from accidental deletion";
|
||||||
|
homepage = "https://github.com/Dicklesworthstone/destructive_command_guard";
|
||||||
|
license = lib.licenses.mit;
|
||||||
|
maintainers = [];
|
||||||
|
};
|
||||||
|
})
|
||||||
38
modules/home/terminal/opencode/default.nix
Normal file
38
modules/home/terminal/opencode/default.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.mods.opencode.enable = lib.mkEnableOption "enables opencode";
|
||||||
|
|
||||||
|
# imports = [
|
||||||
|
# ./package.nix
|
||||||
|
# ./dcg.nix
|
||||||
|
# ];
|
||||||
|
|
||||||
|
config = lib.mkIf config.mods.opencode.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
(callPackage ./dcg.nix {})
|
||||||
|
];
|
||||||
|
|
||||||
|
programs.opencode = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
"plugin" = ["opencode-gemini-auth"];
|
||||||
|
|
||||||
|
"permission" = {
|
||||||
|
"bash" = {
|
||||||
|
"*" = "ask";
|
||||||
|
"rm *" = "deny";
|
||||||
|
"rmdir *" = "deny";
|
||||||
|
"unlink *" = "deny";
|
||||||
|
"*rm *" = "ask";
|
||||||
|
"*rmdir *" = "ask";
|
||||||
|
"*unlink *" = "ask";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ in {
|
||||||
|
|
||||||
programs.zsh = lib.mkIf cfg.zsh.enable {
|
programs.zsh = lib.mkIf cfg.zsh.enable {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
dotDir = "${config.xdg.configHome}/zsh";
|
||||||
enableCompletion = true;
|
enableCompletion = true;
|
||||||
autosuggestion.enable = true;
|
autosuggestion.enable = true;
|
||||||
syntaxHighlighting.enable = true;
|
syntaxHighlighting.enable = true;
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ in
|
||||||
atuin = {
|
atuin = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableZshIntegration = true;
|
enableZshIntegration = true;
|
||||||
|
enableNushellIntegration = true;
|
||||||
flags = ["--disable-up-arrow"];
|
flags = ["--disable-up-arrow"];
|
||||||
settings = {
|
settings = {
|
||||||
sync_frequency = "5m";
|
sync_frequency = "5m";
|
||||||
|
|
|
||||||
599
modules/home/terminal/wezterm.nix
Normal file
599
modules/home/terminal/wezterm.nix
Normal file
|
|
@ -0,0 +1,599 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
cfg = config.mods.terminal;
|
||||||
|
color = config.lib.stylix.colors.withHashtag;
|
||||||
|
|
||||||
|
# Shell to use inside wezterm
|
||||||
|
shell =
|
||||||
|
if cfg.nushell.enable
|
||||||
|
then lib.getExe pkgs.nushell
|
||||||
|
else if cfg.zsh.enable
|
||||||
|
then lib.getExe pkgs.zsh
|
||||||
|
else null;
|
||||||
|
|
||||||
|
# ── Lua codegen helpers ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
luaKey = {
|
||||||
|
key,
|
||||||
|
mods ? null,
|
||||||
|
action,
|
||||||
|
indent ? " ",
|
||||||
|
}: let
|
||||||
|
modsStr = lib.optionalString (mods != null) ", mods = \"${mods}\"";
|
||||||
|
in "${indent}{ key = \"${key}\"${modsStr}, action = ${action} },\n";
|
||||||
|
|
||||||
|
# vi directions: key, arrow alias, wezterm direction name
|
||||||
|
viDirs = [
|
||||||
|
{
|
||||||
|
key = "h";
|
||||||
|
arrow = "LeftArrow";
|
||||||
|
dir = "Left";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "j";
|
||||||
|
arrow = "DownArrow";
|
||||||
|
dir = "Down";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "k";
|
||||||
|
arrow = "UpArrow";
|
||||||
|
dir = "Up";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "l";
|
||||||
|
arrow = "RightArrow";
|
||||||
|
dir = "Right";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# hjkl + arrow equivalents; mkAction :: dir -> lua-action-string
|
||||||
|
viDirKeys = {
|
||||||
|
mods ? null,
|
||||||
|
indent ? " ",
|
||||||
|
mkAction,
|
||||||
|
}:
|
||||||
|
lib.concatMapStrings (d:
|
||||||
|
luaKey {
|
||||||
|
inherit mods indent;
|
||||||
|
key = d.key;
|
||||||
|
action = mkAction d.dir;
|
||||||
|
}
|
||||||
|
+ luaKey {
|
||||||
|
inherit mods indent;
|
||||||
|
key = d.arrow;
|
||||||
|
action = mkAction d.dir;
|
||||||
|
})
|
||||||
|
viDirs;
|
||||||
|
|
||||||
|
# 1-9 tab-jump bindings
|
||||||
|
tabJumpKeys = {
|
||||||
|
mods ? null,
|
||||||
|
indent ? " ",
|
||||||
|
}:
|
||||||
|
lib.concatStrings (builtins.genList (i:
|
||||||
|
luaKey {
|
||||||
|
inherit mods indent;
|
||||||
|
key = toString (i + 1);
|
||||||
|
action = "act.ActivateTab(${toString i})";
|
||||||
|
})
|
||||||
|
9);
|
||||||
|
|
||||||
|
# hjkl + arrows for AdjustPaneSize at a given step
|
||||||
|
resizeDirKeys = {
|
||||||
|
step,
|
||||||
|
indent ? " ",
|
||||||
|
}:
|
||||||
|
lib.concatMapStrings (d:
|
||||||
|
luaKey {
|
||||||
|
inherit indent;
|
||||||
|
key = d.key;
|
||||||
|
action = "act.AdjustPaneSize({ \"${d.dir}\", ${toString step} })";
|
||||||
|
}
|
||||||
|
+ luaKey {
|
||||||
|
inherit indent;
|
||||||
|
key = d.arrow;
|
||||||
|
action = "act.AdjustPaneSize({ \"${d.dir}\", ${toString step} })";
|
||||||
|
})
|
||||||
|
viDirs;
|
||||||
|
|
||||||
|
# Uppercase HJKL fine-tune resize
|
||||||
|
resizeShiftKeys = {
|
||||||
|
step,
|
||||||
|
indent ? " ",
|
||||||
|
}:
|
||||||
|
lib.concatMapStrings (d:
|
||||||
|
luaKey {
|
||||||
|
inherit indent;
|
||||||
|
key = lib.toUpper d.key;
|
||||||
|
action = "act.AdjustPaneSize({ \"${d.dir}\", ${toString step} })";
|
||||||
|
})
|
||||||
|
viDirs;
|
||||||
|
|
||||||
|
# Wrap a lua action string so it also pops the key table (return to locked)
|
||||||
|
andPop = action: "act.Multiple({ ${action}, act.PopKeyTable })";
|
||||||
|
|
||||||
|
# Standard exit bindings, given the mode's own pop key
|
||||||
|
exitKeys = {
|
||||||
|
selfKey,
|
||||||
|
indent ? " ",
|
||||||
|
}:
|
||||||
|
lib.concatStrings [
|
||||||
|
(luaKey {
|
||||||
|
inherit indent;
|
||||||
|
key = selfKey;
|
||||||
|
action = "act.PopKeyTable";
|
||||||
|
})
|
||||||
|
(luaKey {
|
||||||
|
inherit indent;
|
||||||
|
key = "Escape";
|
||||||
|
action = "act.PopKeyTable";
|
||||||
|
})
|
||||||
|
(luaKey {
|
||||||
|
inherit indent;
|
||||||
|
key = "Enter";
|
||||||
|
action = "act.PopKeyTable";
|
||||||
|
})
|
||||||
|
(luaKey {
|
||||||
|
inherit indent;
|
||||||
|
key = "Space";
|
||||||
|
mods = "ALT";
|
||||||
|
action = "act.PopKeyTable";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# ── Status bar ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Per-mode accent colour (base16) and hint string shown in the status bar
|
||||||
|
# Hints use nerd font glyphs: separators, icons, key labels
|
||||||
|
modes = {
|
||||||
|
locked = {
|
||||||
|
fg = color.base03;
|
||||||
|
hint = "⌥: ⌥hl: ^ud: ⌥1-9: ⌥n: ⌥s: ⌥w: ⌥t: ⌥p:";
|
||||||
|
};
|
||||||
|
normal = {
|
||||||
|
fg = color.base0D;
|
||||||
|
hint = "t: x: r: c: s: esc:";
|
||||||
|
};
|
||||||
|
resize = {
|
||||||
|
fg = color.base0A;
|
||||||
|
hint = "hjkl: HJKL: esc:";
|
||||||
|
};
|
||||||
|
copy_mode = {
|
||||||
|
fg = color.base0E;
|
||||||
|
hint = "hjkl: v: V: ^v: y: /: n/p: esc:";
|
||||||
|
};
|
||||||
|
search_mode = {
|
||||||
|
fg = color.base08;
|
||||||
|
hint = "type: ^n/^p: ^r: ↵/esc:";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Lua table literal mapping mode name -> { fg, hint }
|
||||||
|
modeTableEntries = lib.concatStringsSep "\n " (lib.mapAttrsToList (name: m: ''
|
||||||
|
["${name}"] = { fg = "${m.fg}", hint = "${m.hint}" },
|
||||||
|
'')
|
||||||
|
modes);
|
||||||
|
in {
|
||||||
|
options.mods.terminal.wezterm.enable = lib.mkEnableOption "enables wezterm";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.wezterm.enable {
|
||||||
|
programs.wezterm = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
extraConfig = ''
|
||||||
|
local wezterm = require("wezterm")
|
||||||
|
local act = wezterm.action
|
||||||
|
|
||||||
|
-- ─── Helpers ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
-- move_focus_or_tab: mirrors Zellij's MoveFocusOrTab.
|
||||||
|
-- Move focus in direction; if at the edge, switch to the adjacent tab.
|
||||||
|
local function move_focus_or_tab(direction)
|
||||||
|
return wezterm.action_callback(function(window, pane)
|
||||||
|
local neighbour = pane:tab():get_pane_direction(direction)
|
||||||
|
if neighbour ~= nil then
|
||||||
|
window:perform_action(act.ActivatePaneDirection(direction), pane)
|
||||||
|
else
|
||||||
|
if direction == "Left" then
|
||||||
|
window:perform_action(act.ActivateTabRelative(-1), pane)
|
||||||
|
elseif direction == "Right" then
|
||||||
|
window:perform_action(act.ActivateTabRelative(1), pane)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- scroll_or_passthrough: Ctrl+key scrolls at the shell prompt but passes
|
||||||
|
-- the key through when a program has taken the alt screen (vim, less, fzf…).
|
||||||
|
local function scroll_or_passthrough(key, pages)
|
||||||
|
return wezterm.action_callback(function(window, pane)
|
||||||
|
if pane:is_alt_screen_active() then
|
||||||
|
window:perform_action(act.SendKey({ key = key, mods = "CTRL" }), pane)
|
||||||
|
else
|
||||||
|
window:perform_action(act.ScrollByPage(pages), pane)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- tab_is_zoomed: true if any pane in the current tab is zoomed.
|
||||||
|
-- Used by move_vertical to decide whether to carry zoom forward.
|
||||||
|
local function tab_is_zoomed(pane)
|
||||||
|
for _, info in ipairs(pane:tab():panes_with_info()) do
|
||||||
|
if info.is_zoomed then return true end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- move_vertical: move focus Up/Down.
|
||||||
|
-- If any pane in the tab is currently zoomed (zoom-mode is "on" for this
|
||||||
|
-- tab), zoom the destination pane too — stacked-panel behaviour.
|
||||||
|
-- Otherwise just move focus plainly.
|
||||||
|
local function move_vertical(direction)
|
||||||
|
return wezterm.action_callback(function(window, pane)
|
||||||
|
local neighbour = pane:tab():get_pane_direction(direction)
|
||||||
|
if neighbour == nil then return end
|
||||||
|
if tab_is_zoomed(pane) then
|
||||||
|
-- unzoom_on_switch_pane unzooms the current pane when we move;
|
||||||
|
-- then SetPaneZoomState(true) zooms the newly active pane.
|
||||||
|
window:perform_action(
|
||||||
|
act.Multiple({
|
||||||
|
act.ActivatePaneDirection(direction),
|
||||||
|
act.SetPaneZoomState(true),
|
||||||
|
}),
|
||||||
|
pane
|
||||||
|
)
|
||||||
|
else
|
||||||
|
window:perform_action(act.ActivatePaneDirection(direction), pane)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ─── Status bar ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
-- Per-mode accent colour and hint text, generated from Nix/stylix palette
|
||||||
|
local mode_info = {
|
||||||
|
${modeTableEntries}
|
||||||
|
}
|
||||||
|
|
||||||
|
local bg_bar = "${color.base01}"
|
||||||
|
local fg_text = "${color.base05}"
|
||||||
|
local fg_dim = "${color.base03}"
|
||||||
|
local bg_main = "${color.base00}"
|
||||||
|
|
||||||
|
-- Render hints with the key in the mode accent colour and the icon dimmed.
|
||||||
|
-- Each hint token is "key:icon"; we colour them individually.
|
||||||
|
local function render_hints(hint, accent)
|
||||||
|
local cells = {}
|
||||||
|
for token in hint:gmatch("%S+") do
|
||||||
|
local key, icon = token:match("^(.-):(.)$")
|
||||||
|
if key and icon then
|
||||||
|
table.insert(cells, { Background = { Color = bg_bar } })
|
||||||
|
table.insert(cells, { Foreground = { Color = accent } })
|
||||||
|
table.insert(cells, { Text = key })
|
||||||
|
table.insert(cells, { Foreground = { Color = fg_text } })
|
||||||
|
table.insert(cells, { Text = ":" .. icon .. " " })
|
||||||
|
else
|
||||||
|
table.insert(cells, { Background = { Color = bg_bar } })
|
||||||
|
table.insert(cells, { Foreground = { Color = fg_dim } })
|
||||||
|
table.insert(cells, { Text = token .. " " })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return cells
|
||||||
|
end
|
||||||
|
|
||||||
|
wezterm.on("format-window-title", function(tab, _pane, _tabs, _panes, _config)
|
||||||
|
local ok, win = pcall(function() return wezterm.mux.get_window(tab.window_id) end)
|
||||||
|
if ok and win then
|
||||||
|
local ws = win:get_workspace()
|
||||||
|
if ws ~= "default" then
|
||||||
|
return ws .. " — " .. tab.active_pane.title
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tab.active_pane.title
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- format-tab-title: show "rank/total title" when the active tab is in
|
||||||
|
-- stacked (zoom) mode; otherwise show plain " title ".
|
||||||
|
-- Returning a cell table gives us explicit padding and colours;
|
||||||
|
-- returning a plain string loses the retro tab bar's built-in spacing.
|
||||||
|
local tab_bg_active = "${color.base0D}"
|
||||||
|
local tab_fg_active = "${color.base00}"
|
||||||
|
local tab_bg_inactive = "${color.base01}"
|
||||||
|
local tab_fg_inactive = "${color.base03}"
|
||||||
|
|
||||||
|
wezterm.on("format-tab-title", function(tab, _tabs, panes, _config, _hover, _max_width)
|
||||||
|
local title = (tab.tab_title and tab.tab_title ~= "") and tab.tab_title or tab.active_pane.title
|
||||||
|
local bg = tab.is_active and tab_bg_active or tab_bg_inactive
|
||||||
|
local fg = tab.is_active and tab_fg_active or tab_fg_inactive
|
||||||
|
|
||||||
|
-- Only compute stack position for the active tab.
|
||||||
|
-- The `panes` event parameter only contains the active pane snapshot
|
||||||
|
-- and lacks `top`, so we use wezterm.mux.get_tab():panes_with_info()
|
||||||
|
-- which returns full PaneInformation including top/is_zoomed/is_active.
|
||||||
|
if tab.is_active then
|
||||||
|
local mux_tab = wezterm.mux.get_tab(tab.tab_id)
|
||||||
|
if mux_tab then
|
||||||
|
local infos = mux_tab:panes_with_info()
|
||||||
|
table.sort(infos, function(a, b) return a.top < b.top end)
|
||||||
|
|
||||||
|
local any_zoomed = false
|
||||||
|
local active_rank, total = 0, 0
|
||||||
|
for _, p in ipairs(infos) do
|
||||||
|
total = total + 1
|
||||||
|
if p.is_active then active_rank = total end
|
||||||
|
if p.is_zoomed then any_zoomed = true end
|
||||||
|
end
|
||||||
|
|
||||||
|
if any_zoomed and total > 1 and active_rank > 0 then
|
||||||
|
title = active_rank .. "/" .. total .. " " .. title
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
{ Background = { Color = bg } },
|
||||||
|
{ Foreground = { Color = fg } },
|
||||||
|
{ Text = " " .. title .. " " },
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
wezterm.on("update-status", function(window, _pane)
|
||||||
|
local kt = window:active_key_table()
|
||||||
|
local mode = kt or "locked"
|
||||||
|
local info = mode_info[mode] or mode_info["locked"]
|
||||||
|
|
||||||
|
window:set_left_status("")
|
||||||
|
|
||||||
|
-- Right: coloured hints then mode badge
|
||||||
|
local cells = { { Text = " " } }
|
||||||
|
for _, c in ipairs(render_hints(info.hint, info.fg)) do
|
||||||
|
table.insert(cells, c)
|
||||||
|
end
|
||||||
|
table.insert(cells, "ResetAttributes")
|
||||||
|
table.insert(cells, { Background = { Color = info.fg } })
|
||||||
|
table.insert(cells, { Foreground = { Color = bg_bar } })
|
||||||
|
table.insert(cells, { Text = "" })
|
||||||
|
table.insert(cells, { Foreground = { Color = bg_main } })
|
||||||
|
table.insert(cells, { Attribute = { Intensity = "Bold" } })
|
||||||
|
table.insert(cells, { Text = " " .. mode:upper() .. " " })
|
||||||
|
table.insert(cells, "ResetAttributes")
|
||||||
|
window:set_right_status(wezterm.format(cells))
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ─── Appearance ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
local config = wezterm.config_builder()
|
||||||
|
|
||||||
|
-- Stylix sets the color scheme via its wezterm integration;
|
||||||
|
-- this is a fallback in case it is not active.
|
||||||
|
config.color_scheme = "Synthwave (Gogh)"
|
||||||
|
|
||||||
|
config.font = wezterm.font("CommitMono Nerd Font")
|
||||||
|
config.font_size = 12.0
|
||||||
|
|
||||||
|
config.window_padding = { left = 6, right = 6, top = 6, bottom = 6 }
|
||||||
|
|
||||||
|
config.default_cursor_style = "BlinkingBar"
|
||||||
|
config.hide_tab_bar_if_only_one_tab = false
|
||||||
|
config.use_fancy_tab_bar = false
|
||||||
|
config.tab_max_width = 24
|
||||||
|
|
||||||
|
config.colors = {
|
||||||
|
tab_bar = {
|
||||||
|
background = "${color.base01}",
|
||||||
|
active_tab = { bg_color = "${color.base0D}", fg_color = "${color.base00}", intensity = "Bold" },
|
||||||
|
inactive_tab = { bg_color = "${color.base01}", fg_color = "${color.base03}" },
|
||||||
|
inactive_tab_hover = { bg_color = "${color.base02}", fg_color = "${color.base04}" },
|
||||||
|
new_tab = { bg_color = "${color.base01}", fg_color = "${color.base03}" },
|
||||||
|
new_tab_hover = { bg_color = "${color.base02}", fg_color = "${color.base04}" },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
config.tab_bar_at_bottom = false
|
||||||
|
|
||||||
|
-- ─── SSH Domains ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
config.ssh_domains = {
|
||||||
|
{
|
||||||
|
name = "muho",
|
||||||
|
remote_address = "muho",
|
||||||
|
username = "muon",
|
||||||
|
default_prog = { "nu" },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- ─── Shell ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
${lib.optionalString (shell != null) ''
|
||||||
|
config.default_prog = { "${shell}" }
|
||||||
|
''}
|
||||||
|
|
||||||
|
-- ─── Scrollback ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
config.scrollback_lines = 10000
|
||||||
|
|
||||||
|
-- ─── Stacked panes ─────────────────────────────────────────────────────────
|
||||||
|
-- When switching away from a zoomed pane, unzoom it automatically.
|
||||||
|
-- Paired with stack_focus (Alt+j/k) this gives Zellij-style stacked panels.
|
||||||
|
config.unzoom_on_switch_pane = true
|
||||||
|
|
||||||
|
-- ─── Key bindings ──────────────────────────────────────────────────────────
|
||||||
|
--
|
||||||
|
-- Default mode = "locked" (all keys pass through to the shell).
|
||||||
|
-- Alt+Space enters "normal" mode.
|
||||||
|
-- From normal: t→new tab x→close tab p/n→split r→resize mode
|
||||||
|
-- Esc / Enter / Alt+Space → back to locked from any mode.
|
||||||
|
|
||||||
|
config.disable_default_key_bindings = true
|
||||||
|
|
||||||
|
config.keys = {
|
||||||
|
-- Alt+h/l: move focus or switch tab at edge (Zellij MoveFocusOrTab)
|
||||||
|
-- Alt+j/k: initial bindings (overridden below by stacked-focus variants)
|
||||||
|
${viDirKeys {
|
||||||
|
mods = "ALT";
|
||||||
|
indent = " ";
|
||||||
|
mkAction = d:
|
||||||
|
if d == "Left" || d == "Right"
|
||||||
|
then "move_focus_or_tab(\"${d}\")"
|
||||||
|
else "act.ActivatePaneDirection(\"${d}\")";
|
||||||
|
}}
|
||||||
|
-- Alt+1-9: jump to tab by number
|
||||||
|
${tabJumpKeys {
|
||||||
|
mods = "ALT";
|
||||||
|
indent = " ";
|
||||||
|
}}
|
||||||
|
-- Alt+n: new pane (split right)
|
||||||
|
{ key = "n", mods = "ALT", action = act.SplitHorizontal({ domain = "CurrentPaneDomain" }) },
|
||||||
|
-- Alt+s: split below, then zoom the new pane so stacked mode starts.
|
||||||
|
-- Two separate perform_action calls: the split runs first and focuses
|
||||||
|
-- the new pane, then the second call zooms window:active_pane() which
|
||||||
|
-- is now the new pane (not the original `pane` argument).
|
||||||
|
{ key = "s", mods = "ALT", action = wezterm.action_callback(function(window, pane)
|
||||||
|
window:perform_action(act.SplitVertical({ domain = "CurrentPaneDomain" }), pane)
|
||||||
|
window:perform_action(act.SetPaneZoomState(true), window:active_pane())
|
||||||
|
end)
|
||||||
|
},
|
||||||
|
-- Alt+j/k: move_vertical — plain focus move normally, stacked zoom
|
||||||
|
-- when any pane in the tab is already zoomed (mirrors Alt+f state).
|
||||||
|
{ key = "j", mods = "ALT", action = move_vertical("Down") },
|
||||||
|
{ key = "k", mods = "ALT", action = move_vertical("Up") },
|
||||||
|
{ key = "DownArrow", mods = "ALT", action = move_vertical("Down") },
|
||||||
|
{ key = "UpArrow", mods = "ALT", action = move_vertical("Up") },
|
||||||
|
-- Alt+f: toggle zoom
|
||||||
|
{ key = "f", mods = "ALT", action = act.TogglePaneZoomState },
|
||||||
|
-- Alt+[/]: rotate panes
|
||||||
|
{ key = "[", mods = "ALT", action = act.RotatePanes("CounterClockwise") },
|
||||||
|
{ key = "]", mods = "ALT", action = act.RotatePanes("Clockwise") },
|
||||||
|
-- Alt++/-/=: font size
|
||||||
|
{ key = "+", mods = "ALT", action = act.IncreaseFontSize },
|
||||||
|
{ key = "-", mods = "ALT", action = act.DecreaseFontSize },
|
||||||
|
{ key = "=", mods = "ALT", action = act.ResetFontSize },
|
||||||
|
-- Alt+i/o: reorder tabs
|
||||||
|
{ key = "i", mods = "ALT", action = act.MoveTabRelative(-1) },
|
||||||
|
{ key = "o", mods = "ALT", action = act.MoveTabRelative(1) },
|
||||||
|
-- Alt+w: close current pane; if tab was in stacked (zoom) mode, re-zoom
|
||||||
|
-- the new active pane so zoom mode persists across close.
|
||||||
|
-- confirm=false because the callback must run synchronously after close;
|
||||||
|
-- a confirm dialog would make the zoom fire before the user answers.
|
||||||
|
-- Guard: only re-zoom when there will still be panes left after close.
|
||||||
|
{ key = "w", mods = "ALT", action = wezterm.action_callback(function(window, pane)
|
||||||
|
local panes = pane:tab():panes()
|
||||||
|
local was_zoomed = tab_is_zoomed(pane)
|
||||||
|
window:perform_action(act.CloseCurrentPane({ confirm = false }), pane)
|
||||||
|
if was_zoomed and #panes > 1 then
|
||||||
|
window:perform_action(act.SetPaneZoomState(true), window:active_pane())
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
},
|
||||||
|
-- Alt+p: command palette
|
||||||
|
{ key = "p", mods = "ALT", action = act.ActivateCommandPalette },
|
||||||
|
-- Alt+t: tab navigator (searchable tab list)
|
||||||
|
{ key = "t", mods = "ALT", action = act.ShowTabNavigator },
|
||||||
|
-- Alt+q: quit
|
||||||
|
{ key = "q", mods = "ALT", action = act.QuitApplication },
|
||||||
|
-- Ctrl+U/D: scroll half page when at the shell prompt; pass through
|
||||||
|
-- to the running program when it is using the alt screen (vim, less,
|
||||||
|
-- fzf, etc. switch to the alt screen and need the raw key).
|
||||||
|
{ key = "u", mods = "CTRL", action = scroll_or_passthrough("u", -0.5) },
|
||||||
|
{ key = "d", mods = "CTRL", action = scroll_or_passthrough("d", 0.5) },
|
||||||
|
-- Copy / paste
|
||||||
|
{ key = "c", mods = "CTRL|SHIFT", action = act.CopyTo("Clipboard") },
|
||||||
|
{ key = "v", mods = "CTRL|SHIFT", action = act.PasteFrom("Clipboard") },
|
||||||
|
-- Enter normal mode
|
||||||
|
{ key = "Space", mods = "ALT", action = act.ActivateKeyTable({ name = "normal", one_shot = false }) },
|
||||||
|
}
|
||||||
|
|
||||||
|
config.key_tables = {
|
||||||
|
|
||||||
|
-- ── NORMAL ─────────────────────────────────────────────────────────────
|
||||||
|
normal = {
|
||||||
|
{ key = "t", action = ${andPop "act.SpawnTab(\"CurrentPaneDomain\")"} },
|
||||||
|
{ key = "x", action = ${andPop "act.CloseCurrentTab({ confirm = true })"} },
|
||||||
|
{ key = "r", action = act.ActivateKeyTable({ name = "resize", one_shot = false }) },
|
||||||
|
{ key = "c", action = ${andPop "act.ActivateCopyMode"} },
|
||||||
|
{ key = "s", action = ${andPop "act.Search({ CaseSensitiveString = \"\" })"} },
|
||||||
|
${exitKeys {selfKey = "Escape";}} },
|
||||||
|
|
||||||
|
-- ── RESIZE ─────────────────────────────────────────────────────────────
|
||||||
|
resize = {
|
||||||
|
${resizeDirKeys {step = 5;}}${resizeShiftKeys {step = 1;}}
|
||||||
|
{ key = "+", action = act.AdjustPaneSize({ "Right", 5 }) },
|
||||||
|
{ key = "-", action = act.AdjustPaneSize({ "Left", 5 }) },
|
||||||
|
{ key = "=", action = act.AdjustPaneSize({ "Right", 5 }) },
|
||||||
|
${exitKeys {selfKey = "r";}} },
|
||||||
|
|
||||||
|
-- ── COPY MODE ──────────────────────────────────────────────────────────
|
||||||
|
copy_mode = {
|
||||||
|
-- movement
|
||||||
|
{ key = "h", action = act.CopyMode("MoveLeft") },
|
||||||
|
{ key = "j", action = act.CopyMode("MoveDown") },
|
||||||
|
{ key = "k", action = act.CopyMode("MoveUp") },
|
||||||
|
{ key = "l", action = act.CopyMode("MoveRight") },
|
||||||
|
{ key = "LeftArrow", action = act.CopyMode("MoveLeft") },
|
||||||
|
{ key = "DownArrow", action = act.CopyMode("MoveDown") },
|
||||||
|
{ key = "UpArrow", action = act.CopyMode("MoveUp") },
|
||||||
|
{ key = "RightArrow", action = act.CopyMode("MoveRight") },
|
||||||
|
{ key = "w", action = act.CopyMode("MoveForwardWord") },
|
||||||
|
{ key = "b", action = act.CopyMode("MoveBackwardWord") },
|
||||||
|
{ key = "e", action = act.CopyMode("MoveForwardWordEnd") },
|
||||||
|
{ key = "0", action = act.CopyMode("MoveToStartOfLine") },
|
||||||
|
{ key = "^", action = act.CopyMode("MoveToStartOfLineContent") },
|
||||||
|
{ key = "$", action = act.CopyMode("MoveToEndOfLineContent") },
|
||||||
|
{ key = "g", action = act.CopyMode("MoveToScrollbackTop") },
|
||||||
|
{ key = "G", action = act.CopyMode("MoveToScrollbackBottom") },
|
||||||
|
{ key = "Enter", action = act.CopyMode("MoveToStartOfNextLine") },
|
||||||
|
{ key = "u", mods = "CTRL", action = act.CopyMode({ MoveByPage = -0.5 }) },
|
||||||
|
{ key = "d", mods = "CTRL", action = act.CopyMode({ MoveByPage = 0.5 }) },
|
||||||
|
{ key = "b", mods = "CTRL", action = act.CopyMode("PageUp") },
|
||||||
|
{ key = "f", mods = "CTRL", action = act.CopyMode("PageDown") },
|
||||||
|
{ key = "PageUp", action = act.CopyMode("PageUp") },
|
||||||
|
{ key = "PageDown", action = act.CopyMode("PageDown") },
|
||||||
|
-- selection
|
||||||
|
{ key = "v", action = act.CopyMode({ SetSelectionMode = "Cell" }) },
|
||||||
|
{ key = "V", action = act.CopyMode({ SetSelectionMode = "Line" }) },
|
||||||
|
{ key = "v", mods = "CTRL", action = act.CopyMode({ SetSelectionMode = "Block" }) },
|
||||||
|
{ key = "o", action = act.CopyMode("MoveToSelectionOtherEnd") },
|
||||||
|
{ key = "O", action = act.CopyMode("MoveToSelectionOtherEndHoriz") },
|
||||||
|
-- yank and exit
|
||||||
|
{ key = "y", action = act.Multiple({
|
||||||
|
act.CopyTo("ClipboardAndPrimarySelection"),
|
||||||
|
act.Multiple({ act.ScrollToBottom, act.CopyMode("Close") }),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
-- search within copy mode
|
||||||
|
{ key = "/", action = act.Search({ CaseSensitiveString = "" }) },
|
||||||
|
{ key = "n", action = act.CopyMode("NextMatch") },
|
||||||
|
{ key = "p", action = act.CopyMode("PriorMatch") },
|
||||||
|
-- exit
|
||||||
|
{ key = "q", action = act.Multiple({ act.ScrollToBottom, act.CopyMode("Close") }) },
|
||||||
|
{ key = "Escape", action = act.Multiple({ act.ScrollToBottom, act.CopyMode("Close") }) },
|
||||||
|
{ key = "c", mods = "CTRL", action = act.Multiple({ act.ScrollToBottom, act.CopyMode("Close") }) },
|
||||||
|
},
|
||||||
|
|
||||||
|
-- ── SEARCH MODE ────────────────────────────────────────────────────────
|
||||||
|
search_mode = {
|
||||||
|
-- navigate matches
|
||||||
|
{ key = "Enter", action = act.CopyMode("AcceptPattern") },
|
||||||
|
{ key = "n", mods = "CTRL", action = act.CopyMode("NextMatch") },
|
||||||
|
{ key = "p", mods = "CTRL", action = act.CopyMode("PriorMatch") },
|
||||||
|
{ key = "PageUp", action = act.CopyMode("PriorMatchPage") },
|
||||||
|
{ key = "PageDown", action = act.CopyMode("NextMatchPage") },
|
||||||
|
{ key = "UpArrow", action = act.CopyMode("PriorMatch") },
|
||||||
|
{ key = "DownArrow", action = act.CopyMode("NextMatch") },
|
||||||
|
-- cycle match type (case-sensitive / insensitive / regex)
|
||||||
|
{ key = "r", mods = "CTRL", action = act.CopyMode("CycleMatchType") },
|
||||||
|
-- clear search input
|
||||||
|
{ key = "u", mods = "CTRL", action = act.CopyMode("ClearPattern") },
|
||||||
|
-- Escape: dismiss search bar, return to copy mode at current match
|
||||||
|
{ key = "Escape", action = act.CopyMode("AcceptPattern") },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ in with lib; {
|
||||||
config = mkIf cfg.tools.enable {
|
config = mkIf cfg.tools.enable {
|
||||||
programs.yazi = {
|
programs.yazi = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
shellWrapperName = "y";
|
||||||
settings = {
|
settings = {
|
||||||
manager = {
|
manager = {
|
||||||
ratio = [ 1 4 3 ];
|
ratio = [ 1 4 3 ];
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,15 @@ in
|
||||||
10.0.0.2 muon
|
10.0.0.2 muon
|
||||||
10.0.0.3 muho
|
10.0.0.3 muho
|
||||||
10.0.0.4 muop
|
10.0.0.4 muop
|
||||||
|
127.0.0.1 word.local
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Wildcard DNS: *.word.local -> 127.0.0.1 via NetworkManager's built-in dnsmasq
|
||||||
|
networking.networkmanager.dns = "dnsmasq";
|
||||||
|
# Force resolv.conf to use local dnsmasq so wildcard DNS is actually queried
|
||||||
|
networking.resolvconf.useLocalResolver = true;
|
||||||
|
environment.etc."NetworkManager/dnsmasq.d/word-local.conf".text = ''
|
||||||
|
address=/.word.local/127.0.0.1
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# gateway =
|
# gateway =
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
inputs.nix-alien.packages.${system}.nix-alien
|
inputs.nix-alien.packages.${system}.nix-alien
|
||||||
|
inputs.home-manager.packages.${system}.home-manager
|
||||||
colmena
|
colmena
|
||||||
];
|
];
|
||||||
programs.nix-ld.enable = true;
|
programs.nix-ld.enable = true;
|
||||||
|
|
|
||||||
|
|
@ -22,5 +22,6 @@ in
|
||||||
xdg.portal.extraPortals = [
|
xdg.portal.extraPortals = [
|
||||||
pkgs.xdg-desktop-portal
|
pkgs.xdg-desktop-portal
|
||||||
];
|
];
|
||||||
|
xdg.portal.config.common.default = "*";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
{ pkgs, lib, ... }: {
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
imports = [
|
imports = [
|
||||||
./containers
|
./containers
|
||||||
./gaming
|
./gaming
|
||||||
|
|
@ -25,5 +29,6 @@
|
||||||
./lemmy.nix
|
./lemmy.nix
|
||||||
./audio.nix
|
./audio.nix
|
||||||
./atuin.nix
|
./atuin.nix
|
||||||
|
./murmur.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
modules/nixos/server/murmur.nix
Normal file
25
modules/nixos/server/murmur.nix
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
cfg = config.mods.server.murmur;
|
||||||
|
in
|
||||||
|
with lib; {
|
||||||
|
options.mods.server = {
|
||||||
|
murmur = {
|
||||||
|
enable = mkEnableOption {
|
||||||
|
default = false;
|
||||||
|
description = "enables murmur server";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
services.murmur = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
{ pkgs, lib, config, ... }:
|
{
|
||||||
let
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
inherit (lib) types mkOption mkEnableOption;
|
inherit (lib) types mkOption mkEnableOption;
|
||||||
cfg = config.mods.server.search;
|
cfg = config.mods.server.search;
|
||||||
port = config.mods.server.nginx.ports.search;
|
port = config.mods.server.nginx.ports.search;
|
||||||
|
|
@ -24,18 +28,19 @@ in {
|
||||||
hostnames.remove = ["(.*.)?facebook.com$"];
|
hostnames.remove = ["(.*.)?facebook.com$"];
|
||||||
hostnames.replace = {
|
hostnames.replace = {
|
||||||
# Self-hosted
|
# Self-hosted
|
||||||
"(.*.)?reddit.com$" = "reddit.muon.host";
|
# "(.*.)?reddit.com$" = "reddit.muon.host";
|
||||||
# "(.*.)?youtube.com$" = "videos.muon.host"; # TODO not working
|
# "(.*.)?youtube.com$" = "videos.muon.host"; # TODO not working
|
||||||
|
|
||||||
# External
|
# External
|
||||||
"(.*.)?youtube.com$" = "invidious.nerdvpn.de";
|
"(.*.)?reddit.com$" = "old.reddit.com";
|
||||||
"(.*.)?imdb.com$" = "libremdb.iket.me";
|
# "(.*.)?youtube.com$" = "invidious.nerdvpn.de";
|
||||||
"(.*.)?imgur.com$" = "rimgo.privacyredirect.com";
|
# "(.*.)?imdb.com$" = "libremdb.iket.me";
|
||||||
"(.*.)?twitch.com$" = "safetwitch.privacyredirect.com";
|
# "(.*.)?imgur.com$" = "rimgo.privacyredirect.com";
|
||||||
"(.*.)?wikipedia.com$" = "wikiless.privacyredirect.com";
|
# "(.*.)?twitch.com$" = "safetwitch.privacyredirect.com";
|
||||||
"(.*.)?medium.com$" = "scribe.privacyredirect.com";
|
# "(.*.)?wikipedia.com$" = "wikiless.privacyredirect.com";
|
||||||
"(.*.)?stackoverflow.com$" = "anonymousoverflow.privacyredirect.com";
|
# "(.*.)?medium.com$" = "scribe.privacyredirect.com";
|
||||||
"(.*.)?github.com$" = "gothub.privacyredirect.com";
|
# "(.*.)?stackoverflow.com$" = "anonymousoverflow.privacyredirect.com";
|
||||||
|
# "(.*.)?github.com$" = "gothub.privacyredirect.com";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ in {
|
||||||
stylix = {
|
stylix = {
|
||||||
enable = true;
|
enable = true;
|
||||||
autoEnable = true;
|
autoEnable = true;
|
||||||
base16Scheme = cfg.scheme;
|
# base16Scheme = cfg.scheme;
|
||||||
|
base16Scheme = ./synthwave84.yaml;
|
||||||
image = cfg.wallpaper;
|
image = cfg.wallpaper;
|
||||||
cursor = {
|
cursor = {
|
||||||
name = "phinger-cursors-light";
|
name = "phinger-cursors-light";
|
||||||
|
|
|
||||||
24
modules/nixos/theme/synthwave84.yaml
Normal file
24
modules/nixos/theme/synthwave84.yaml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
system: "base16"
|
||||||
|
name: "synthwave84"
|
||||||
|
slug: "synthwave84"
|
||||||
|
author: "Someone"
|
||||||
|
variant: "dark"
|
||||||
|
palette:
|
||||||
|
base00: "2a2139"
|
||||||
|
base01: "241b2f"
|
||||||
|
base02: "34294f"
|
||||||
|
base03: "8e6fe4"
|
||||||
|
base04: "c1c3e6"
|
||||||
|
base05: "f5f5ff"
|
||||||
|
base06: "ffffff"
|
||||||
|
base07: "fffdf8"
|
||||||
|
base08: "f92aad"
|
||||||
|
base09: "f97e72"
|
||||||
|
base0A: "ffe261"
|
||||||
|
base0B: "72f1b8"
|
||||||
|
base0C: "78dcff"
|
||||||
|
base0D: "36f9f6"
|
||||||
|
base0E: "ff7edb"
|
||||||
|
base0F: "bb8977"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
{ pkgs, lib, config, ... }:
|
{
|
||||||
let cfg = config.mods.unfree.nvidia;
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
cfg = config.mods.unfree.nvidia;
|
||||||
in {
|
in {
|
||||||
options.mods.unfree.nvidia = {
|
options.mods.unfree.nvidia = {
|
||||||
enable = lib.mkEnableOption {
|
enable = lib.mkEnableOption {
|
||||||
|
|
@ -23,7 +28,7 @@ in {
|
||||||
# enable32Bit = true;
|
# enable32Bit = true;
|
||||||
# };
|
# };
|
||||||
|
|
||||||
services.xserver.videoDrivers = [ "nvidia" "nvidia-dkms" ];
|
services.xserver.videoDrivers = ["nvidia"];
|
||||||
|
|
||||||
hardware.nvidia = {
|
hardware.nvidia = {
|
||||||
modesetting.enable = true;
|
modesetting.enable = true;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
{pkgs ? import <nixpkgs> {}, ...}: {
|
{pkgs ? import <nixpkgs> {}, ...}: {
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
NIX_CONFIG =
|
NIX_CONFIG = "extra-experimental-features = nix-command flakes ca-derivations";
|
||||||
"extra-experimental-features = nix-command flakes ca-derivations";
|
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
nix
|
nix
|
||||||
git
|
git
|
||||||
|
|
|
||||||
42
utils.nix
42
utils.nix
|
|
@ -1,4 +1,7 @@
|
||||||
{ inputs, system, sources, ... }: {
|
{ inputs, system, sources, ... }:
|
||||||
|
let
|
||||||
|
pkgs = import inputs.nixpkgs { inherit system; };
|
||||||
|
in {
|
||||||
mkHost = host:
|
mkHost = host:
|
||||||
inputs.nixpkgs.lib.nixosSystem {
|
inputs.nixpkgs.lib.nixosSystem {
|
||||||
specialArgs = { inherit inputs system sources; };
|
specialArgs = { inherit inputs system sources; };
|
||||||
|
|
@ -11,4 +14,41 @@
|
||||||
inputs.impermanence.nixosModules.impermanence
|
inputs.impermanence.nixosModules.impermanence
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Build a standalone HM configuration for a given host NixOS config and
|
||||||
|
# home.nix file. osConfig is injected as a specialArg so all modules that
|
||||||
|
# reference it continue to work.
|
||||||
|
mkHome = { hostConfig, homeFile, username ? "muon" }:
|
||||||
|
inputs.home-manager.lib.homeManagerConfiguration {
|
||||||
|
inherit pkgs;
|
||||||
|
extraSpecialArgs = {
|
||||||
|
inherit inputs system sources;
|
||||||
|
osConfig = hostConfig.config;
|
||||||
|
};
|
||||||
|
modules = [
|
||||||
|
homeFile
|
||||||
|
inputs.self.outputs.homeManagerModules.default
|
||||||
|
inputs.stylix.homeManagerModules.stylix
|
||||||
|
({ osConfig, ... }: {
|
||||||
|
home.username = username;
|
||||||
|
home.homeDirectory = "/home/${username}";
|
||||||
|
# Mirror the stylix settings from the NixOS config so the standalone
|
||||||
|
# HM build has the same theme without re-declaring it.
|
||||||
|
stylix = {
|
||||||
|
enable = osConfig.stylix.enable;
|
||||||
|
autoEnable = osConfig.stylix.autoEnable;
|
||||||
|
base16Scheme = osConfig.stylix.base16Scheme;
|
||||||
|
image = osConfig.stylix.image;
|
||||||
|
cursor = osConfig.stylix.cursor;
|
||||||
|
# Forward individual font options; stylix derives fonts.packages
|
||||||
|
# internally as read-only so we must not forward that attr.
|
||||||
|
fonts.monospace = osConfig.stylix.fonts.monospace;
|
||||||
|
fonts.sansSerif = osConfig.stylix.fonts.sansSerif;
|
||||||
|
fonts.serif = osConfig.stylix.fonts.serif;
|
||||||
|
fonts.emoji = osConfig.stylix.fonts.emoji;
|
||||||
|
fonts.sizes = osConfig.stylix.fonts.sizes;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue