+16
flake.lock
+16
flake.lock
···
48
48
"type": "github"
49
49
}
50
50
},
51
+
"easy-hosts": {
52
+
"locked": {
53
+
"lastModified": 1755470564,
54
+
"narHash": "sha256-KB1ZryVDoQcbIsItOf4WtxkHhh3ppj+XwMpSnt/2QHc=",
55
+
"owner": "tgirlcloud",
56
+
"repo": "easy-hosts",
57
+
"rev": "d0422bc7b3db26268982aa15d07e60370e76ee1d",
58
+
"type": "github"
59
+
},
60
+
"original": {
61
+
"owner": "tgirlcloud",
62
+
"repo": "easy-hosts",
63
+
"type": "github"
64
+
}
65
+
},
51
66
"fenix": {
52
67
"inputs": {
53
68
"nixpkgs": [
···
585
600
"root": {
586
601
"inputs": {
587
602
"catppuccin": "catppuccin",
603
+
"easy-hosts": "easy-hosts",
588
604
"flake-parts": "flake-parts",
589
605
"ghostty": "ghostty",
590
606
"helix": "helix",
+54
-46
flake.nix
+54
-46
flake.nix
···
46
46
inputs.nixpkgs.follows = "nixpkgs";
47
47
};
48
48
flake-parts.url = "github:hercules-ci/flake-parts";
49
+
easy-hosts.url = "github:tgirlcloud/easy-hosts";
49
50
};
50
-
outputs = {
51
-
self,
52
-
nixpkgs,
53
-
flake-parts,
54
-
...
55
-
} @ inputs:
56
-
flake-parts.lib.mkFlake {inherit inputs;} (
57
-
{withSystem, ...}: {
51
+
outputs =
52
+
{
53
+
self,
54
+
nixpkgs,
55
+
flake-parts,
56
+
...
57
+
}@inputs:
58
+
flake-parts.lib.mkFlake { inherit inputs; } (
59
+
{ withSystem, config, ... }:
60
+
{
58
61
systems = [
59
62
"x86_64-linux"
60
63
"aarch64-linux"
61
64
];
62
65
63
-
perSystem = {pkgs, ...}: {
64
-
packages = {
65
-
pokego = pkgs.callPackage ./pkgs/pokego.nix {};
66
-
http-nu = pkgs.callPackage ./pkgs/http-nu.nix {};
67
-
topiary-nu = pkgs.callPackage ./pkgs/topiary-nu.nix {
68
-
inherit (inputs) tree-sitter-nu topiary-nushell;
66
+
imports = [ ./systems/default.nix ];
67
+
68
+
perSystem =
69
+
{ pkgs, ... }:
70
+
{
71
+
packages = {
72
+
pokego = pkgs.callPackage ./pkgs/pokego.nix { };
73
+
http-nu = pkgs.callPackage ./pkgs/http-nu.nix { };
74
+
topiary-nu = pkgs.callPackage ./pkgs/topiary-nu.nix {
75
+
inherit (inputs) tree-sitter-nu topiary-nushell;
76
+
};
77
+
78
+
wakuna-image = self.lib.sdImageFromSystem self.nixosConfigurations.wakuna;
69
79
};
70
-
71
-
wakuna-image = self.lib.sdImageFromSystem self.nixosConfigurations.wakuna;
80
+
formatter = pkgs.nixfmt-rfc-style;
72
81
};
73
-
formatter = pkgs.alejandra;
74
-
};
75
82
76
-
flake = let
77
-
inherit (nixpkgs) lib;
78
-
in {
79
-
lib = {
80
-
sdImageFromSystem = system: system.config.system.build.sdImage;
83
+
flake =
84
+
let
85
+
inherit (nixpkgs) lib;
86
+
in
87
+
{
88
+
lib = {
89
+
sdImageFromSystem = system: system.config.system.build.sdImage;
81
90
82
-
mkSystem' = system: hostname:
83
-
withSystem system (
84
-
{
85
-
inputs',
86
-
self',
87
-
...
88
-
}:
91
+
mkSystem' =
92
+
system: hostname:
93
+
withSystem system (
94
+
{ inputs', self', ... }:
89
95
lib.nixosSystem {
90
96
specialArgs = {
91
97
inherit
···
96
102
;
97
103
};
98
104
modules = [
99
-
{networking.hostName = hostname;}
105
+
{ networking.hostName = hostname; }
100
106
./modules/core.nix
101
107
./modules/nixos
102
108
./hosts/${hostname}
109
+
config.flake.nixosModules.dev
110
+
config.flake.nixosModules.desktop
103
111
];
104
112
}
105
-
);
113
+
);
106
114
107
-
mkSystem = system: hostname: {${hostname} = self.lib.mkSystem' system hostname;};
108
-
mkSystems = system: hosts: lib.mergeAttrsList (map (self.lib.mkSystem system) hosts);
109
-
};
115
+
mkSystem = system: hostname: { ${hostname} = self.lib.mkSystem' system hostname; };
116
+
mkSystems = system: hosts: lib.mergeAttrsList (map (self.lib.mkSystem system) hosts);
117
+
};
110
118
111
-
nixosConfigurations = inputs.nixpkgs.lib.concatMapAttrs self.lib.mkSystems {
112
-
"x86_64-linux" = [
113
-
"ozen"
114
-
"kiwi"
115
-
"reg"
116
-
"belaf"
117
-
];
118
-
"aarch64-linux" = ["wakuna"];
119
+
overlays.default = import ./overlays;
120
+
121
+
homeModules = {
122
+
dev = import ./modules/dev/home.nix;
123
+
desktop = import ./modules/desktop/home.nix;
124
+
};
125
+
126
+
nixosModules = {
127
+
dev = import ./modules/dev/nixos.nix;
128
+
desktop = import ./modules/desktop/nixos.nix;
129
+
};
119
130
};
120
-
121
-
overlays.default = import ./overlays;
122
-
};
123
131
}
124
132
);
125
133
nixConfig = {
+5
-56
hosts/belaf/default.nix
+5
-56
hosts/belaf/default.nix
···
1
+
{ pkgs, ... }:
1
2
{
2
-
pkgs,
3
-
lib,
4
-
inputs,
5
-
...
6
-
}: {
7
-
imports = [
8
-
inputs.lanzaboote.nixosModules.lanzaboote
9
-
inputs.catppuccin.nixosModules.catppuccin
10
-
../../modules/home
11
-
./hardware.nix
12
-
];
13
-
catppuccin = {
14
-
enable = true;
15
-
flavor = "macchiato";
16
-
};
17
-
time.timeZone = "Europe/Paris";
18
-
desktop.enable = true;
3
+
imports = [ ./hardware.nix ];
19
4
system.stateVersion = "25.11";
20
5
21
6
boot = {
22
-
loader.systemd-boot = {
23
-
enable = lib.mkForce false;
24
-
25
-
configurationLimit = 10;
26
-
};
27
-
lanzaboote = {
28
-
enable = true;
29
-
pkiBundle = "/etc/secureboot";
30
-
};
31
-
supportedFilesystems = ["bcachefs"];
7
+
supportedFilesystems = [ "bcachefs" ];
32
8
kernelPackages = pkgs.linuxPackages_latest;
33
9
};
34
10
35
-
networking.networkmanager.enable = true;
36
-
37
-
services = {
38
-
tailscale.enable = true;
39
-
tailscale.useRoutingFeatures = "client";
40
-
touchegg.enable = true;
41
-
auto-cpufreq.enable = true;
42
-
blueman.enable = true;
43
-
udev.packages = [pkgs.via];
44
-
};
45
-
46
-
hardware.keyboard.qmk.enable = true;
47
-
48
-
security = {
49
-
sudo.wheelNeedsPassword = false;
50
-
rtkit.enable = true;
51
-
};
52
-
53
-
environment = with pkgs; {
54
-
systemPackages = [
55
-
sbctl
56
-
];
57
-
};
58
-
59
-
virtualisation.docker = {
60
-
enable = true;
61
-
daemon.settings = {
62
-
data-root = "/docker";
63
-
};
11
+
virtualisation.docker.daemon.settings = {
12
+
data-root = "/docker";
64
13
};
65
14
}
+7
-6
hosts/belaf/hardware.nix
+7
-6
hosts/belaf/hardware.nix
···
6
6
lib,
7
7
modulesPath,
8
8
...
9
-
}: {
10
-
imports = [(modulesPath + "/installer/scan/not-detected.nix")];
9
+
}:
10
+
{
11
+
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
11
12
12
13
boot.initrd.availableKernelModules = [
13
14
"xhci_pci"
···
17
18
"usbhid"
18
19
"sd_mod"
19
20
];
20
-
boot.initrd.kernelModules = [];
21
-
boot.kernelModules = ["kvm-intel"];
22
-
boot.extraModulePackages = [];
21
+
boot.initrd.kernelModules = [ ];
22
+
boot.kernelModules = [ "kvm-intel" ];
23
+
boot.extraModulePackages = [ ];
23
24
24
25
fileSystems."/" = {
25
26
device = "UUID=d584e71f-2c5d-41e2-95e7-ed41f0833e25";
···
36
37
fsType = "ext4";
37
38
};
38
39
39
-
swapDevices = [];
40
+
swapDevices = [ ];
40
41
41
42
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
42
43
# (the default) this is the recommended approach. When using systemd-networkd it's
+16
-43
hosts/kiwi/default.nix
+16
-43
hosts/kiwi/default.nix
···
1
1
{
2
-
inputs,
3
-
pkgs,
4
2
config,
3
+
pkgs,
4
+
lib,
5
5
...
6
-
}: {
7
-
imports = [
8
-
inputs.catppuccin.nixosModules.catppuccin
9
-
../../modules/home
10
-
./hardware.nix
11
-
];
6
+
}:
7
+
{
8
+
imports = [ ./hardware.nix ];
12
9
13
-
yubikey.enable = true;
14
-
catppuccin = {
15
-
enable = true;
16
-
flavor = "macchiato";
17
-
};
18
-
time.timeZone = "Europe/Paris";
19
-
desktop.enable = true;
20
10
system.stateVersion = "25.11";
21
11
22
-
home-manager.users.${config.my.username}.imports = [
23
-
./home-upf.nix
24
-
./desktop.nix
25
-
];
12
+
home-manager.users.${config.my.username} = {
13
+
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "hayase" ];
14
+
15
+
home.packages = [
16
+
pkgs.signal-desktop-bin
17
+
pkgs.obs-studio
18
+
pkgs.hayase
19
+
];
20
+
21
+
programs.waybar.settings.mainBar.battery.bat = lib.mkForce "BAT0";
22
+
};
26
23
27
24
boot = {
28
25
# https://gitlab.freedesktop.org/drm/amd/-/issues/3925
···
34
31
configurationLimit = 10;
35
32
};
36
33
};
37
-
38
-
hardware.keyboard.qmk.enable = true;
39
-
40
-
networking.networkmanager.enable = true;
41
-
42
-
services = {
43
-
tailscale = {
44
-
enable = true;
45
-
useRoutingFeatures = "client";
46
-
};
47
-
touchegg.enable = true;
48
-
blueman.enable = true;
49
-
auto-cpufreq.enable = true;
50
-
udev.packages = [pkgs.via];
51
-
};
52
-
53
-
security = {
54
-
sudo.wheelNeedsPassword = false;
55
-
rtkit.enable = true;
56
-
};
57
-
58
-
virtualisation.docker.enable = true;
59
-
60
-
programs._1password.enable = true;
61
34
}
-39
hosts/kiwi/desktop.nix
-39
hosts/kiwi/desktop.nix
···
1
-
{
2
-
lib,
3
-
pkgs,
4
-
...
5
-
}: {
6
-
nixpkgs.config.allowUnfreePredicate = pkg:
7
-
builtins.elem (lib.getName pkg) [
8
-
"hayase"
9
-
];
10
-
home.packages = [
11
-
pkgs.signal-desktop-bin
12
-
pkgs.obs-studio
13
-
pkgs.hayase
14
-
];
15
-
16
-
programs = {
17
-
waybar.settings.mainBar.battery.bat = lib.mkForce "BAT0";
18
-
opencode.settings.mcp = {
19
-
linear = {
20
-
type = "remote";
21
-
url = "https://mcp.linear.app/mcp";
22
-
enabled = true;
23
-
headers = {
24
-
Authorization = "Bearer {env:LINEAR_API_KEY}";
25
-
};
26
-
};
27
-
sentry = {
28
-
type = "local";
29
-
enabled = true;
30
-
command = [
31
-
"${pkgs.bun}/bin/bun"
32
-
"x"
33
-
"mcp-remote@latest"
34
-
"https://mcp.sentry.dev/mcp"
35
-
];
36
-
};
37
-
};
38
-
};
39
-
}
+7
-6
hosts/kiwi/hardware.nix
+7
-6
hosts/kiwi/hardware.nix
···
6
6
lib,
7
7
modulesPath,
8
8
...
9
-
}: {
10
-
imports = [(modulesPath + "/installer/scan/not-detected.nix")];
9
+
}:
10
+
{
11
+
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
11
12
12
13
boot.initrd.availableKernelModules = [
13
14
"nvme"
···
17
18
"usbhid"
18
19
"sd_mod"
19
20
];
20
-
boot.initrd.kernelModules = [];
21
-
boot.kernelModules = ["kvm-amd"];
22
-
boot.extraModulePackages = [];
21
+
boot.initrd.kernelModules = [ ];
22
+
boot.kernelModules = [ "kvm-amd" ];
23
+
boot.extraModulePackages = [ ];
23
24
24
25
fileSystems."/" = {
25
26
device = "/dev/disk/by-uuid/8039878e-c1a8-4b46-924a-0d42d4e49d24";
···
35
36
];
36
37
};
37
38
38
-
swapDevices = [];
39
+
swapDevices = [ ];
39
40
40
41
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
41
42
# (the default) this is the recommended approach. When using systemd-networkd it's
-10
hosts/kiwi/home-upf.nix
-10
hosts/kiwi/home-upf.nix
···
1
-
_: {
2
-
# [includeIf "hasconfig:remote.*.url:git+ssh://git@github/upfluence/**"]
3
-
# path = "~/upf/.gitconfig"
4
-
xdg.configFile."git/config".text = ''
5
-
[includeIf "hasconfig:remote.*.url:git+ssh://git@github.com/upfluence/**"]
6
-
path = "~/upf/.gitconfig"
7
-
[includeIf "hasconfig:remote.*.url:git@github.com:upfluence/**"]
8
-
path = "~/upf/.gitconfig"
9
-
'';
10
-
}
+5
-14
hosts/ozen/default.nix
+5
-14
hosts/ozen/default.nix
···
1
1
{
2
-
inputs,
3
2
pkgs,
4
3
lib,
5
4
config,
6
5
...
7
-
}: let
6
+
}:
7
+
let
8
8
inherit (lib) mkForce;
9
-
in {
9
+
in
10
+
{
10
11
my.username = "nixos";
11
12
12
-
imports = [
13
-
inputs.catppuccin.nixosModules.catppuccin
14
-
inputs.nixos-wsl.nixosModules.default
15
-
../../modules/home
16
-
];
17
-
18
-
catppuccin = {
19
-
enable = true;
20
-
flavor = "macchiato";
21
-
};
22
13
wsl.enable = true;
23
14
wsl.defaultUser = config.my.username;
24
15
system.stateVersion = "25.11";
···
40
31
41
32
environment = {
42
33
variables.BROWSER = mkForce "wsl-open";
43
-
systemPackages = [pkgs.wsl-open];
34
+
systemPackages = [ pkgs.wsl-open ];
44
35
};
45
36
46
37
nixpkgs.hostPlatform = "x86_64-linux";
+8
-14
hosts/reg/default.nix
+8
-14
hosts/reg/default.nix
···
3
3
pkgs,
4
4
inputs,
5
5
...
6
-
}: {
6
+
}:
7
+
{
7
8
my.username = "root";
8
9
9
10
imports = [
···
15
16
16
17
boot.tmp.cleanOnBoot = true;
17
18
zramSwap.enable = true;
18
-
sops.age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"];
19
-
services = {
20
-
tailscale.enable = true;
21
-
tailscale.useRoutingFeatures = "server";
22
-
openssh.enable = true;
23
-
24
-
atuin = {
25
-
enable = true;
26
-
host = "0.0.0.0";
27
-
};
19
+
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
20
+
services.atuin = {
21
+
enable = true;
22
+
host = "0.0.0.0";
28
23
};
29
24
30
25
users.users = {
31
-
${config.my.username}.openssh.authorizedKeys.keyFiles = [inputs.ssh-keys];
26
+
${config.my.username}.openssh.authorizedKeys.keyFiles = [ inputs.ssh-keys ];
32
27
};
33
28
34
-
environment.systemPackages = with pkgs; [helix];
35
-
server = true;
29
+
environment.systemPackages = with pkgs; [ helix ];
36
30
37
31
system.stateVersion = "25.05";
38
32
}
+4
-3
hosts/reg/hardware.nix
+4
-3
hosts/reg/hardware.nix
···
1
-
{modulesPath, ...}: {
2
-
imports = [(modulesPath + "/profiles/qemu-guest.nix")];
1
+
{ modulesPath, ... }:
2
+
{
3
+
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
3
4
boot.loader.grub = {
4
5
efiSupport = true;
5
6
efiInstallAsRemovable = true;
···
15
16
"xen_blkfront"
16
17
"vmw_pvscsi"
17
18
];
18
-
boot.initrd.kernelModules = ["nvme"];
19
+
boot.initrd.kernelModules = [ "nvme" ];
19
20
fileSystems."/" = {
20
21
device = "/dev/sda1";
21
22
fsType = "ext4";
+7
-9
hosts/reg/pds-backup.nix
+7
-9
hosts/reg/pds-backup.nix
···
1
-
{
2
-
config,
3
-
pkgs,
4
-
...
5
-
}: let
1
+
{ config, pkgs, ... }:
2
+
let
6
3
restoreScript = pkgs.writeShellScriptBin "pds-restore" ''
7
4
set -e
8
5
···
74
71
75
72
echo "$(date): Backup completed." >> "$LOG_FILE"
76
73
'';
77
-
in {
74
+
in
75
+
{
78
76
sops.secrets.s3 = {
79
77
format = "dotenv";
80
78
sopsFile = ../../secrets/pds-backup-s3.env;
81
79
};
82
80
83
-
environment.systemPackages = [restoreScript];
81
+
environment.systemPackages = [ restoreScript ];
84
82
85
83
systemd.services.pds-backup = {
86
84
description = "Backup PDS data to S3";
···
98
96
"TAR_CMD=${pkgs.gnutar}/bin/tar"
99
97
"AWS_CMD=${pkgs.awscli2}/bin/aws"
100
98
];
101
-
EnvironmentFile = [config.sops.secrets.s3.path];
99
+
EnvironmentFile = [ config.sops.secrets.s3.path ];
102
100
User = "root";
103
101
Type = "oneshot";
104
102
};
105
103
};
106
104
107
105
systemd.timers.pds-backup = {
108
-
wantedBy = ["timers.target"];
106
+
wantedBy = [ "timers.target" ];
109
107
timerConfig = {
110
108
OnCalendar = "daily";
111
109
Persistent = true;
+15
-36
hosts/reg/pds.nix
+15
-36
hosts/reg/pds.nix
···
1
-
{config, ...}: {
1
+
{ config, ... }:
2
+
{
3
+
imports = [ ../../modules/nixos/services/acme-nginx.nix ];
2
4
sops = {
3
5
secrets.pds = {
4
6
format = "dotenv";
5
7
sopsFile = ../../secrets/pds.env;
6
-
restartUnits = ["bluesky-pds.service"];
8
+
restartUnits = [ "bluesky-pds.service" ];
7
9
};
8
10
secrets.cloudflare-api = {
9
11
format = "dotenv";
···
16
18
settings = {
17
19
PDS_HOSTNAME = "0xf.fr";
18
20
};
19
-
environmentFiles = [config.sops.secrets.pds.path];
21
+
environmentFiles = [ config.sops.secrets.pds.path ];
20
22
};
21
23
22
-
networking.firewall.allowedTCPPorts = [
23
-
80
24
-
443
25
-
];
26
-
27
-
security.acme = {
28
-
defaults.email = "netop@0xf.fr";
29
-
acceptTerms = true;
30
-
31
-
certs."0xf.fr" = {
32
-
dnsProvider = "cloudflare";
33
-
credentialsFile = config.sops.secrets.cloudflare-api.path;
34
-
inherit (config.services.nginx) group;
35
-
36
-
domain = "0xf.fr";
37
-
extraDomainNames = ["*.0xf.fr"];
38
-
reloadServices = ["nginx"];
39
-
};
40
-
};
41
-
42
-
services.nginx = let
43
-
pass = {
44
-
useACMEHost = "0xf.fr";
45
-
forceSSL = true;
46
-
locations."/" = {
47
-
proxyPass = "http://127.0.0.1:${toString config.services.bluesky-pds.settings.PDS_PORT}";
48
-
proxyWebsockets = true;
49
-
};
50
-
};
51
-
in {
24
+
services.acme-nginx = {
52
25
enable = true;
53
-
recommendedProxySettings = true;
54
-
recommendedTlsSettings = true;
55
-
virtualHosts."~(.*)\\.0xf\\.fr$" = pass;
26
+
email = "netop@0xf.fr";
27
+
credentialsFile = config.sops.secrets.cloudflare-api.path;
28
+
hosts = [
29
+
{
30
+
domain = "0xf.fr";
31
+
extraDomainNames = [ "*.0xf.fr" ];
32
+
proxyPort = config.services.bluesky-pds.settings.PDS_PORT;
33
+
}
34
+
];
56
35
};
57
36
}
+6
-11
hosts/wakuna/default.nix
+6
-11
hosts/wakuna/default.nix
···
2
2
inputs,
3
3
lib,
4
4
modulesPath,
5
+
config,
5
6
...
6
-
}: {
7
+
}:
8
+
{
7
9
imports = [
8
10
(modulesPath + "/installer/sd-card/sd-image-aarch64-installer.nix")
9
11
./torrent.nix
10
12
];
11
13
12
14
sdImage.compressImage = false;
13
-
15
+
my.username = "root";
14
16
nixpkgs.hostPlatform = "aarch64-linux";
15
17
system.stateVersion = "24.11";
16
18
···
23
25
];
24
26
};
25
27
26
-
users.users.root.openssh.authorizedKeys.keyFiles = [inputs.ssh-keys];
27
-
services.openssh = {
28
-
enable = true;
29
-
settings.PermitRootLogin = "yes";
30
-
};
28
+
users.users.${config.my.username}.openssh.authorizedKeys.keyFiles = [ inputs.ssh-keys ];
31
29
32
-
services.tailscale = {
33
-
enable = true;
34
-
useRoutingFeatures = "server";
35
-
};
30
+
services.openssh.settings.PermitRootLogin = "yes";
36
31
}
+3
-2
hosts/wakuna/torrent.nix
+3
-2
hosts/wakuna/torrent.nix
+14
-1
modules/core.nix
+14
-1
modules/core.nix
···
1
-
{lib, ...}: {
1
+
{ lib, config, ... }:
2
+
{
2
3
options.my.username = lib.mkOption {
3
4
type = lib.types.str;
4
5
description = "The username for the current user.";
5
6
default = "kar";
7
+
};
8
+
9
+
config = lib.mkIf (config.my.username != "root") {
10
+
users.users.${config.my.username} = {
11
+
home = "/home/${config.my.username}";
12
+
isNormalUser = true;
13
+
extraGroups = [
14
+
"networkmanager"
15
+
"docker"
16
+
"wheel"
17
+
];
18
+
};
6
19
};
7
20
}
+13
modules/desktop/apps/browser.nix
+13
modules/desktop/apps/browser.nix
+6
modules/desktop/apps/default.nix
+6
modules/desktop/apps/default.nix
+4
modules/desktop/apps/discord.nix
+4
modules/desktop/apps/discord.nix
+6
modules/desktop/audio/default.nix
+6
modules/desktop/audio/default.nix
+9
modules/desktop/audio/easyeffects.nix
+9
modules/desktop/audio/easyeffects.nix
+18
modules/desktop/default.nix
+18
modules/desktop/default.nix
···
1
+
{ config, self, ... }:
2
+
{
3
+
imports = [
4
+
self.nixosModules.desktop
5
+
self.nixosModules.dev
6
+
../locale.nix
7
+
../nixos/desktop-common.nix
8
+
../hardware/peripherals.nix
9
+
];
10
+
11
+
desktop.enable = true;
12
+
dev.enable = true;
13
+
14
+
home-manager.users.${config.my.username}.imports = [
15
+
self.homeModules.desktop
16
+
self.homeModules.dev
17
+
];
18
+
}
+47
modules/desktop/home.nix
+47
modules/desktop/home.nix
···
1
+
{
2
+
lib,
3
+
osConfig ? { },
4
+
pkgs,
5
+
...
6
+
}:
7
+
let
8
+
inherit (lib) mkEnableOption mkOption types;
9
+
in
10
+
{
11
+
config.desktop = {
12
+
inherit (osConfig.desktop or { })
13
+
enable
14
+
wm
15
+
terminal
16
+
audio
17
+
apps
18
+
;
19
+
};
20
+
options.desktop = {
21
+
enable = mkEnableOption "all desktop tools";
22
+
23
+
wm.enable = mkEnableOption "window manager and interface tools";
24
+
terminal.enable = mkEnableOption "terminal tools";
25
+
audio.enable = mkEnableOption "audio tools";
26
+
apps.enable = mkEnableOption "desktop applications";
27
+
browser.default = mkOption {
28
+
description = "default browser xdg file";
29
+
default = "firefox-devedition.desktop";
30
+
type = types.str;
31
+
};
32
+
wallpaper = lib.mkOption {
33
+
default = pkgs.fetchurl {
34
+
url = "https://raw.githubusercontent.com/HoulFloof/wallpapers/f23c1010b93cb97baa7ad7c94fd552f7601496d2/misc/waves_right_colored.png";
35
+
hash = "sha256-NqqE+pGnCIWAitH86sxu1EudVEEaSO82y3NqbhtDh9k=";
36
+
};
37
+
type = lib.types.path;
38
+
description = "the wallpaper to use";
39
+
};
40
+
};
41
+
imports = [
42
+
./wm
43
+
./terminal
44
+
./audio
45
+
./apps
46
+
];
47
+
}
+33
modules/desktop/ipcam.nix
+33
modules/desktop/ipcam.nix
···
1
+
{
2
+
config,
3
+
lib,
4
+
pkgs,
5
+
...
6
+
}:
7
+
{
8
+
config = lib.mkIf config.desktop.ipcam.enable {
9
+
boot = {
10
+
extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ];
11
+
kernelModules = [ "v4l2loopback" ];
12
+
extraModprobeConfig = ''
13
+
options v4l2loopback video_nr=9 card_label=IP-Webcam exclusive_caps=1
14
+
'';
15
+
};
16
+
17
+
environment.systemPackages =
18
+
let
19
+
port = 9696;
20
+
ipcam = pkgs.writeShellScriptBin "ipcam" ''
21
+
${lib.getExe' pkgs.android-tools "adb"} wait-for-usb-device
22
+
${lib.getExe' pkgs.android-tools "adb"} forward tcp:${toString port} tcp:8080
23
+
${lib.getExe pkgs.ffmpeg} -i http://localhost:${toString port}/video -vf format=yuv420p -f v4l2 /dev/video9
24
+
${lib.getExe' pkgs.android-tools "adb"} forward --remove tcp:${toString port}
25
+
'';
26
+
in
27
+
[
28
+
pkgs.ffmpeg
29
+
pkgs.android-tools
30
+
ipcam
31
+
];
32
+
};
33
+
}
+37
modules/desktop/nixos.nix
+37
modules/desktop/nixos.nix
···
1
+
{ config, lib, ... }:
2
+
let
3
+
cfg = config.desktop;
4
+
inherit (lib) mkIf mkEnableOption;
5
+
in
6
+
{
7
+
options.desktop = {
8
+
enable = mkEnableOption "all desktop tools";
9
+
10
+
wm.enable = mkEnableOption "window manager and interface tools";
11
+
terminal.enable = mkEnableOption "terminal tools";
12
+
audio.enable = mkEnableOption "audio tools";
13
+
apps.enable = mkEnableOption "desktop applications";
14
+
ipcam.enable = mkEnableOption "IP camera support";
15
+
yubikey.enable = mkEnableOption "YubiKey support";
16
+
locale.enable = mkEnableOption "locale and timezone settings";
17
+
};
18
+
19
+
imports = [
20
+
./desktop.nix
21
+
./sound.nix
22
+
./yubikey.nix
23
+
./fonts.nix
24
+
./locale.nix
25
+
./ipcam.nix
26
+
];
27
+
28
+
config = {
29
+
desktop.wm.enable = mkIf cfg.enable true;
30
+
desktop.terminal.enable = mkIf cfg.enable true;
31
+
desktop.audio.enable = mkIf cfg.enable true;
32
+
desktop.apps.enable = mkIf cfg.enable true;
33
+
desktop.ipcam.enable = mkIf cfg.enable true;
34
+
desktop.yubikey.enable = mkIf cfg.enable true;
35
+
desktop.locale.enable = mkIf cfg.enable true;
36
+
};
37
+
}
+1
modules/desktop/terminal/default.nix
+1
modules/desktop/terminal/default.nix
···
1
+
{ imports = [ ./ghostty.nix ]; }
+4
modules/desktop/wm/dunst.nix
+4
modules/desktop/wm/dunst.nix
+9
modules/desktop/wm/fuzzel.nix
+9
modules/desktop/wm/fuzzel.nix
+12
modules/desktop/wm/hyprpaper.nix
+12
modules/desktop/wm/hyprpaper.nix
+265
modules/desktop/wm/niri.nix
+265
modules/desktop/wm/niri.nix
···
1
+
{
2
+
config,
3
+
lib,
4
+
pkgs,
5
+
...
6
+
}:
7
+
{
8
+
config = lib.mkIf config.desktop.wm.enable {
9
+
home.packages = [ pkgs.nautilus ]; # xdg-desktop-portal-gnome wants it
10
+
programs.niri = {
11
+
settings = {
12
+
environment = {
13
+
NIXOS_OZONE_WL = "1";
14
+
ELECTRON_OZONE_PLATFORM_HINT = "auto";
15
+
QT_QPA_PLATFORMTHEME = "qt5ct";
16
+
QT_QPA_PLATFORM = "wayland";
17
+
DISPLAY = ":0";
18
+
GTK_IM_MODULE = "simple";
19
+
};
20
+
21
+
screenshot-path = null;
22
+
prefer-no-csd = true;
23
+
24
+
input = {
25
+
focus-follows-mouse = {
26
+
enable = true;
27
+
max-scroll-amount = "80%";
28
+
};
29
+
keyboard = {
30
+
repeat-delay = 300;
31
+
repeat-rate = 5;
32
+
xkb = {
33
+
layout = "us";
34
+
variant = "intl";
35
+
};
36
+
};
37
+
38
+
mouse = {
39
+
accel-profile = "flat";
40
+
accel-speed = 0.5;
41
+
};
42
+
43
+
touchpad = {
44
+
tap = true;
45
+
dwt = true;
46
+
natural-scroll = true;
47
+
click-method = "clickfinger";
48
+
};
49
+
};
50
+
51
+
spawn-at-startup = [ { command = [ "systemctl --user restart waybar.service" ]; } ];
52
+
53
+
layout = {
54
+
gaps = 16;
55
+
always-center-single-column = true;
56
+
empty-workspace-above-first = true;
57
+
default-column-width = {
58
+
proportion = 0.5;
59
+
};
60
+
};
61
+
62
+
window-rules = [
63
+
{
64
+
geometry-corner-radius =
65
+
let
66
+
radius = 8.0;
67
+
in
68
+
{
69
+
bottom-left = radius;
70
+
bottom-right = radius;
71
+
top-left = radius;
72
+
top-right = radius;
73
+
};
74
+
clip-to-geometry = true;
75
+
}
76
+
{
77
+
matches = [ { title = "Picture-in-Picture"; } ];
78
+
open-floating = true;
79
+
default-floating-position = {
80
+
x = 16;
81
+
y = 16;
82
+
relative-to = "bottom-right";
83
+
};
84
+
}
85
+
];
86
+
87
+
outputs = rec {
88
+
eDP-1 = {
89
+
mode = null;
90
+
position = {
91
+
x = HDMI-A-1.mode.width;
92
+
y = 0;
93
+
};
94
+
};
95
+
HDMI-A-1 = {
96
+
mode = {
97
+
width = 2560;
98
+
height = 1440;
99
+
};
100
+
position = {
101
+
x = 0;
102
+
y = 0;
103
+
};
104
+
};
105
+
};
106
+
107
+
binds =
108
+
with config.lib.niri.actions;
109
+
let
110
+
# programs.niri.settings.binds."Mod+Q".action.close-window = []
111
+
toAction =
112
+
act: dir:
113
+
(lib.mapAttrs' (
114
+
argName: argValue:
115
+
lib.nameValuePair "${argName}+${dir.name}" {
116
+
action = {
117
+
"${argValue}-${dir.value}" = [ ];
118
+
};
119
+
}
120
+
) act);
121
+
windowMoves = lib.mergeAttrsList (
122
+
(map
123
+
(toAction {
124
+
"Mod" = "focus";
125
+
"Mod+Ctrl" = "move";
126
+
})
127
+
(
128
+
lib.attrsToList {
129
+
"Up" = "window-up";
130
+
"k" = "window-up";
131
+
"Down" = "window-down";
132
+
"j" = "window-down";
133
+
"Left" = "column-left";
134
+
"h" = "column-left";
135
+
"Right" = "column-right";
136
+
"l" = "column-right";
137
+
"I" = "workspace-down";
138
+
"U" = "workspace-up";
139
+
}
140
+
)
141
+
)
142
+
++ (map
143
+
(toAction {
144
+
"Mod+Shift" = "focus";
145
+
"Mod+Ctrl+Shift" = "move-window-to";
146
+
})
147
+
(
148
+
lib.attrsToList {
149
+
"Up" = "monitor-up";
150
+
"K" = "monitor-up";
151
+
"Down" = "monitor-down";
152
+
"J" = "monitor-down";
153
+
"Left" = "monitor-left";
154
+
"H" = "monitor-left";
155
+
"Right" = "monitor-right";
156
+
"L" = "monitor-right";
157
+
"I" = "workspace-down";
158
+
"U" = "workspace-up";
159
+
}
160
+
)
161
+
)
162
+
);
163
+
in
164
+
{
165
+
"Mod+O".action = show-hotkey-overlay;
166
+
"Mod+Q".action.spawn = "${lib.getExe pkgs.ghostty}";
167
+
"Mod+R".action.spawn = "${lib.getExe pkgs.fuzzel}";
168
+
"Mod+C".action.close-window = [ ];
169
+
170
+
"Mod+Comma".action = consume-window-into-column;
171
+
"Mod+Period".action = expel-window-from-column;
172
+
173
+
"Mod+T".action = switch-preset-column-width;
174
+
"Mod+F".action = maximize-column;
175
+
"Mod+Shift+F".action = fullscreen-window;
176
+
"Mod+D".action = center-column;
177
+
"Mod+B".action = toggle-window-floating;
178
+
179
+
"Mod+Minus".action = set-column-width "-10%";
180
+
"Mod+Equal".action = set-column-width "+10%";
181
+
"Mod+Shift+Minus".action = set-window-height "-10%";
182
+
"Mod+Shift+Equal".action = set-window-height "+10%";
183
+
184
+
"Mod+Shift+Escape".action = toggle-keyboard-shortcuts-inhibit;
185
+
"Mod+Shift+E".action = quit;
186
+
"Mod+Shift+P".action = power-off-monitors;
187
+
"Mod+Shift+Ctrl+T".action = toggle-debug-tint;
188
+
189
+
"Mod+Shift+WheelScrollDown".action = focus-workspace-down;
190
+
"Mod+Shift+WheelScrollUp".action = focus-workspace-up;
191
+
"Mod+WheelScrollDown".action = focus-column-right;
192
+
"Mod+WheelScrollUp".action = focus-column-left;
193
+
194
+
"Mod+Shift+S".action.spawn = [
195
+
(lib.getExe pkgs.bash)
196
+
"-c"
197
+
''${lib.getExe pkgs.slurp} -d | ${lib.getExe pkgs.grim} -t ppm -g - - | ${lib.getExe pkgs.satty} -f - --copy-command=${lib.getExe' pkgs.wl-clipboard "wl-copy"} --actions-on-escape="save-to-clipboard,exit"''
198
+
];
199
+
"Mod+S".action.screenshot = { };
200
+
201
+
"XF86MonBrightnessDown".action.spawn = [
202
+
(lib.getExe pkgs.brightnessctl)
203
+
"set"
204
+
"5%-"
205
+
];
206
+
"XF86MonBrightnessUp".action.spawn = [
207
+
(lib.getExe pkgs.brightnessctl)
208
+
"set"
209
+
"+5%"
210
+
];
211
+
"XF86AudioLowerVolume".action.spawn = [
212
+
(lib.getExe' pkgs.wireplumber "wpctl")
213
+
"set-volume"
214
+
"@DEFAULT_AUDIO_SINK@"
215
+
"2%-"
216
+
];
217
+
"XF86AudioRaiseVolume".action.spawn = [
218
+
(lib.getExe' pkgs.wireplumber "wpctl")
219
+
"set-volume"
220
+
"@DEFAULT_AUDIO_SINK@"
221
+
"2%+"
222
+
];
223
+
}
224
+
// windowMoves;
225
+
226
+
animations =
227
+
let
228
+
vm = {
229
+
kind.spring = {
230
+
damping-ratio = 0.75;
231
+
stiffness = 200;
232
+
epsilon = 0.0001;
233
+
};
234
+
};
235
+
in
236
+
{
237
+
horizontal-view-movement = vm;
238
+
workspace-switch = vm;
239
+
window-resize = vm;
240
+
241
+
window-open = {
242
+
kind.easing = {
243
+
duration-ms = 200;
244
+
curve = "linear";
245
+
};
246
+
custom-shader = ''
247
+
vec4 open_color(vec3 coords_geo, vec3 size_geo) {
248
+
vec3 coords_tex = niri_geo_to_tex * coords_geo;
249
+
vec4 color = texture2D(niri_tex, coords_tex.st);
250
+
251
+
vec2 coords = (coords_geo.xy - vec2(0.5, 0.5)) * size_geo.xy * 2.0;
252
+
coords = coords / length(size_geo.xy);
253
+
float p = niri_clamped_progress;
254
+
if (p * p <= dot(coords, coords))
255
+
color = vec4(0.0);
256
+
257
+
return color;
258
+
}
259
+
'';
260
+
};
261
+
};
262
+
};
263
+
};
264
+
};
265
+
}
+55
modules/desktop/wm/xdg.nix
+55
modules/desktop/wm/xdg.nix
···
1
+
{ config, lib, ... }:
2
+
{
3
+
config = lib.mkIf config.desktop.wm.enable {
4
+
xdg.mimeApps =
5
+
let
6
+
editor = "Helix.desktop";
7
+
browser = config.desktop.browser.default;
8
+
in
9
+
{
10
+
enable = true;
11
+
defaultApplications = {
12
+
"x-scheme-handler/http " = browser;
13
+
"x-scheme-handler/https" = browser;
14
+
"x-scheme-handler/chrome" = browser;
15
+
"text/html" = browser;
16
+
"binary/octet-stream" = browser;
17
+
"image/jpeg" = browser;
18
+
"application/x-extension-htm" = browser;
19
+
"application/x-extension-html" = browser;
20
+
"application/x-extension-shtml" = browser;
21
+
"application/xhtml+xml" = browser;
22
+
"application/x-extension-xhtml" = browser;
23
+
"application/x-extension-xht" = browser;
24
+
"x-scheme-handler/about" = browser;
25
+
"x-scheme-handler/unknown" = browser;
26
+
"x-scheme-handler/discord" = "legcord.desktop";
27
+
"text/markdown" = editor;
28
+
"text/plain" = editor;
29
+
};
30
+
associations = {
31
+
added = {
32
+
"x-scheme-handler/http" = browser;
33
+
"x-scheme-handler/https" = browser;
34
+
"text/html" = browser;
35
+
"binary/octet-stream" = browser;
36
+
"image/jpeg" = browser;
37
+
}
38
+
// lib.mergeAttrsList (
39
+
map
40
+
(lang: {
41
+
"text/x-${lang}" = editor;
42
+
"application/x-${lang}" = editor;
43
+
})
44
+
[
45
+
"python"
46
+
"go"
47
+
"mod"
48
+
"ruby"
49
+
"yaml"
50
+
]
51
+
);
52
+
};
53
+
};
54
+
};
55
+
}
+1
modules/dev/editor/default.nix
+1
modules/dev/editor/default.nix
···
1
+
{ imports = [ ./helix.nix ]; }
+556
modules/dev/editor/helix.nix
+556
modules/dev/editor/helix.nix
···
1
+
{
2
+
lib,
3
+
pkgs,
4
+
inputs',
5
+
self',
6
+
config,
7
+
...
8
+
}:
9
+
let
10
+
jj-patch = pkgs.fetchurl {
11
+
url = "https://patch-diff.githubusercontent.com/raw/helix-editor/helix/pull/14519.patch";
12
+
hash = "sha256-e4xaKcOhAKKYbJXhYHbjdFk6CwLubmCp+m7y//MmQFw=";
13
+
};
14
+
helix = inputs'.helix.packages.default.overrideAttrs (_: {
15
+
patches = jj-patch;
16
+
});
17
+
global-tools = with pkgs; [
18
+
nixfmt-rfc-style
19
+
biome
20
+
golangci-lint
21
+
gotools
22
+
gopls
23
+
sql-formatter
24
+
nodePackages.prettier
25
+
];
26
+
in
27
+
lib.mkIf config.dev.editor.enable {
28
+
home.packages = global-tools;
29
+
programs.helix = {
30
+
enable = true;
31
+
defaultEditor = true;
32
+
package = helix;
33
+
extraPackages =
34
+
with pkgs;
35
+
[
36
+
golangci-lint-langserver
37
+
nixd
38
+
marksman
39
+
nodePackages.typescript-language-server
40
+
vscode-langservers-extracted
41
+
yaml-language-server
42
+
typos-lsp
43
+
nil
44
+
]
45
+
++ global-tools;
46
+
47
+
ignores = [
48
+
".zig-cache"
49
+
"node_modules"
50
+
".direnv"
51
+
"!/notes"
52
+
];
53
+
54
+
settings = {
55
+
keys =
56
+
let
57
+
plusMenu = {
58
+
g = ''
59
+
:sh ${pkgs.nushell}/bin/nu -c '
60
+
let line = ("%{selection_line_start}" | default "%{cursor_line}")
61
+
let line_end = (if ("%{selection_line_end}" | is-not-empty) {$"-L%{selection_line_end}"} else "")
62
+
let root = (${pkgs.jujutsu}/bin/jj workspace root | str trim)
63
+
let rel_path = ("%{file_path_absolute}" | path relative-to $root)
64
+
let ref = (${pkgs.jujutsu}/bin/jj log -r `heads(::@ & bookmarks())` -T `remote_bookmarks` | parse -r `(?<branch>[^\s]+)@(?<remote>[^\s]+)` | sort-by remote -r | get branch.0)
65
+
let remote_url = (${pkgs.jujutsu}/bin/jj git remote list | parse "{remote} {url}" | where remote == origin | get url.0 | if ($in | str contains '://') {$in} else $"https://($in | str replace ':' '/')" | url parse)
66
+
let url = $"https://($remote_url.host)($remote_url.path | str replace ".git" "")/blob/($ref)/($rel_path)#L($line)($line_end)"
67
+
$url | ${pkgs.wl-clipboard}/bin/wl-copy
68
+
'
69
+
'';
70
+
b = ":echo %sh{git blame -L %{cursor_line},+1 %{buffer_name}}";
71
+
p = ":sh echo %{buffer_name} | ${pkgs.wl-clipboard}/bin/wl-copy";
72
+
};
73
+
goMenu = {
74
+
"8" = [
75
+
"move_prev_word_start"
76
+
"move_next_word_end"
77
+
];
78
+
"c" = caseMenu;
79
+
};
80
+
caseMenu = {
81
+
p = ":pipe ${lib.getExe pkgs.sttr} pascal";
82
+
c = ":pipe ${lib.getExe pkgs.sttr} camel";
83
+
k = ":pipe ${lib.getExe pkgs.sttr} kebab";
84
+
K = ":pipe ${lib.getExe pkgs.sttr} kebab | ${lib.getExe pkgs.sttr} upper";
85
+
s = ":pipe ${lib.getExe pkgs.sttr} snake";
86
+
S = ":pipe ${lib.getExe pkgs.sttr} snake | ${lib.getExe pkgs.sttr} upper";
87
+
t = ":pipe ${lib.getExe pkgs.sttr} title";
88
+
};
89
+
runMenu = {
90
+
f = [
91
+
":sh golangci-lint run --issues-exit-code=0 --fix %{buffer_name}"
92
+
":reload"
93
+
];
94
+
};
95
+
scrollFast = {
96
+
"C-j" = lib.replicate 5 "move_visual_line_down";
97
+
"C-k" = lib.replicate 5 "move_visual_line_up";
98
+
};
99
+
in
100
+
{
101
+
normal = {
102
+
"+" = plusMenu;
103
+
"-" = runMenu;
104
+
"g" = goMenu;
105
+
}
106
+
// scrollFast;
107
+
select = {
108
+
"+" = plusMenu;
109
+
"-" = runMenu;
110
+
"." = goMenu;
111
+
}
112
+
// scrollFast;
113
+
};
114
+
115
+
editor = {
116
+
scrolloff = 10;
117
+
text-width = 120;
118
+
rulers = [ 120 ];
119
+
bufferline = "multiple";
120
+
color-modes = true;
121
+
auto-format = true;
122
+
auto-save = true;
123
+
lsp = {
124
+
snippets = true;
125
+
display-color-swatches = true;
126
+
display-messages = true;
127
+
};
128
+
soft-wrap = {
129
+
enable = true;
130
+
};
131
+
statusline = {
132
+
left = [
133
+
"mode"
134
+
"spacer"
135
+
"diagnostics"
136
+
"version-control"
137
+
"file-name"
138
+
"read-only-indicator"
139
+
"file-modification-indicator"
140
+
"spinner"
141
+
];
142
+
right = [
143
+
"file-encoding"
144
+
"file-type"
145
+
"selections"
146
+
"position"
147
+
];
148
+
};
149
+
gutters = [
150
+
"line-numbers"
151
+
"diagnostics"
152
+
"diff"
153
+
];
154
+
end-of-line-diagnostics = "hint";
155
+
inline-diagnostics = {
156
+
cursor-line = "warning"; # show warnings and errors on the cursorline inline
157
+
};
158
+
cursor-shape = {
159
+
insert = "bar";
160
+
normal = "block";
161
+
select = "underline";
162
+
};
163
+
whitespace.render.tab = "all";
164
+
indent-guides = {
165
+
render = true;
166
+
character = "┊";
167
+
skip-levels = 1;
168
+
};
169
+
};
170
+
};
171
+
172
+
languages = {
173
+
language-server = {
174
+
biome = {
175
+
command = "biome";
176
+
args = [ "lsp-proxy" ];
177
+
};
178
+
nu-lsp = {
179
+
command = "nu";
180
+
args = [
181
+
"--lsp"
182
+
"--no-config-file"
183
+
];
184
+
};
185
+
typos = {
186
+
command = "typos-lsp";
187
+
config = {
188
+
diagnosticSeverity = "Warning";
189
+
};
190
+
};
191
+
yaml-language-server = {
192
+
config = {
193
+
enabled = true;
194
+
enabledForFilesGlob = "*.{yaml,yml}";
195
+
diagnosticsLimit = 50;
196
+
showDiagnosticsDirectly = false;
197
+
config = {
198
+
schemas = {
199
+
kubernetes = "templates/**";
200
+
};
201
+
completion = true;
202
+
hover = true;
203
+
};
204
+
};
205
+
};
206
+
golangci-lint-lsp = {
207
+
command = "golangci-lint-langserver";
208
+
config = {
209
+
command = [
210
+
"nu"
211
+
"-c"
212
+
''
213
+
let args = [
214
+
--output.json.path=stdout
215
+
--path-mode=abs
216
+
--issues-exit-code=1
217
+
--show-stats=false
218
+
]
219
+
220
+
if ($env.GOLANGCI_LINT_CONFIG? | is-not-empty) {
221
+
golangci-lint run --config $env.GOLANGCI_LINT_CONFIG ...$args
222
+
} else {
223
+
golangci-lint run ...$args
224
+
}
225
+
''
226
+
];
227
+
};
228
+
};
229
+
rubocop = {
230
+
command = "rubocop";
231
+
args = [ "--lsp" ];
232
+
};
233
+
ruby-lsp = {
234
+
command = "ruby-lsp";
235
+
config = {
236
+
diagnostics = true;
237
+
formatting = true;
238
+
config = {
239
+
initializationOptions = {
240
+
enabledFeatures = {
241
+
codeActions = true;
242
+
codeLens = true;
243
+
completion = true;
244
+
definition = true;
245
+
diagnostics = true;
246
+
documentHighlights = true;
247
+
documentLink = true;
248
+
documentSymbols = true;
249
+
foldingRanges = true;
250
+
formatting = true;
251
+
hover = true;
252
+
inlayHint = true;
253
+
onTypeFormatting = true;
254
+
selectionRanges = true;
255
+
semanticHighlighting = true;
256
+
signatureHelp = true;
257
+
typeHierarchy = true;
258
+
workspaceSymbol = true;
259
+
};
260
+
featuresConfiguration = {
261
+
inlayHint = {
262
+
implicitHashValue = true;
263
+
implicitRescue = true;
264
+
};
265
+
};
266
+
};
267
+
};
268
+
};
269
+
};
270
+
thriftls = {
271
+
command = "thriftls";
272
+
except-features = [ "format" ];
273
+
};
274
+
};
275
+
276
+
language =
277
+
let
278
+
defaults = [ "typos" ];
279
+
in
280
+
map
281
+
(
282
+
lang:
283
+
lang
284
+
// {
285
+
language-servers = if lang ? language-servers then lang.language-servers ++ defaults else defaults;
286
+
}
287
+
)
288
+
(
289
+
[
290
+
{
291
+
name = "nix";
292
+
language-servers = [
293
+
"nixd"
294
+
"nil"
295
+
];
296
+
formatter = {
297
+
command = "nixfmt";
298
+
args = [
299
+
"-s"
300
+
"-w"
301
+
"120"
302
+
];
303
+
};
304
+
auto-format = true;
305
+
}
306
+
{
307
+
name = "go";
308
+
language-servers = [
309
+
"gopls"
310
+
"golangci-lint-lsp"
311
+
];
312
+
formatter = {
313
+
command = "goimports";
314
+
};
315
+
auto-format = true;
316
+
}
317
+
{
318
+
name = "ruby";
319
+
language-servers = [
320
+
"ruby-lsp"
321
+
"rubocop"
322
+
];
323
+
auto-format = true;
324
+
}
325
+
{
326
+
name = "html";
327
+
language-servers = [ "vscode-html-language-server" ];
328
+
formatter = {
329
+
command = "prettier";
330
+
args = [
331
+
"--stdin-filepath"
332
+
"file.html"
333
+
];
334
+
};
335
+
auto-format = true;
336
+
}
337
+
{
338
+
name = "javascript";
339
+
language-servers = [
340
+
{
341
+
name = "typescript-language-server";
342
+
except-features = [ "format" ];
343
+
}
344
+
"biome"
345
+
];
346
+
auto-format = true;
347
+
}
348
+
{
349
+
name = "json";
350
+
language-servers = [
351
+
{
352
+
name = "vscode-json-language-server";
353
+
except-features = [ "format" ];
354
+
}
355
+
"biome"
356
+
];
357
+
formatter = {
358
+
command = "biome";
359
+
args = [
360
+
"format"
361
+
"--stdin-file-path"
362
+
"file.json"
363
+
];
364
+
};
365
+
auto-format = true;
366
+
}
367
+
{
368
+
name = "graphql";
369
+
formatter = {
370
+
command = "biome";
371
+
args = [
372
+
"format"
373
+
"--stdin-file-path"
374
+
"file.gql"
375
+
];
376
+
};
377
+
auto-format = true;
378
+
}
379
+
{
380
+
name = "jsonc";
381
+
language-servers = [
382
+
{
383
+
name = "vscode-json-language-server";
384
+
except-features = [ "format" ];
385
+
}
386
+
"biome"
387
+
];
388
+
formatter = {
389
+
command = "biome";
390
+
args = [
391
+
"format"
392
+
"--stdin-file-path"
393
+
"file.jsonc"
394
+
];
395
+
};
396
+
file-types = [
397
+
"jsonc"
398
+
"hujson"
399
+
];
400
+
auto-format = true;
401
+
}
402
+
{
403
+
name = "jsx";
404
+
language-servers = [
405
+
{
406
+
name = "typescript-language-server";
407
+
except-features = [ "format" ];
408
+
}
409
+
"biome"
410
+
];
411
+
formatter = {
412
+
command = "biome";
413
+
args = [
414
+
"format"
415
+
"--stdin-file-path"
416
+
"file.jsx"
417
+
];
418
+
};
419
+
auto-format = true;
420
+
}
421
+
{
422
+
name = "tsx";
423
+
language-servers = [
424
+
{
425
+
name = "typescript-language-server";
426
+
except-features = [ "format" ];
427
+
}
428
+
"biome"
429
+
];
430
+
formatter = {
431
+
command = "biome";
432
+
args = [
433
+
"format"
434
+
"--stdin-file-path"
435
+
"file.tsx"
436
+
];
437
+
};
438
+
auto-format = true;
439
+
}
440
+
{
441
+
name = "typescript";
442
+
language-servers = [
443
+
{
444
+
name = "typescript-language-server";
445
+
except-features = [ "format" ];
446
+
}
447
+
"biome"
448
+
];
449
+
formatter = {
450
+
command = "biome";
451
+
args = [
452
+
"format"
453
+
"--stdin-file-path"
454
+
"file.ts"
455
+
];
456
+
};
457
+
auto-format = true;
458
+
}
459
+
{
460
+
name = "yaml";
461
+
language-servers = [ "yaml-language-server" ];
462
+
formatter = {
463
+
command = "prettier";
464
+
args = [
465
+
"--stdin-filepath"
466
+
"file.yaml"
467
+
];
468
+
};
469
+
auto-format = true;
470
+
}
471
+
{
472
+
name = "helm";
473
+
language-servers = [ "helm_ls" ];
474
+
}
475
+
{
476
+
name = "typst";
477
+
language-servers = [ "tinymist" ];
478
+
}
479
+
{
480
+
name = "markdown";
481
+
language-servers = [
482
+
"marksman"
483
+
# "vale-ls"
484
+
];
485
+
text-width = 100;
486
+
rulers = [ 100 ];
487
+
soft-wrap = {
488
+
enable = true;
489
+
wrap-at-text-width = true;
490
+
};
491
+
formatter = {
492
+
command = "prettier";
493
+
args = [
494
+
"--stdin-filepath"
495
+
"file.md"
496
+
];
497
+
};
498
+
auto-format = true;
499
+
}
500
+
{
501
+
name = "sql";
502
+
formatter = {
503
+
command = "sql-formatter";
504
+
args = [
505
+
"-c"
506
+
(builtins.toJSON {
507
+
keywordCase = "upper";
508
+
functionCase = "upper";
509
+
dataTypeCase = "upper";
510
+
identifierCase = "lower";
511
+
language = "postgresql";
512
+
expressionWidth = 80;
513
+
tabWidth = 2;
514
+
})
515
+
];
516
+
};
517
+
auto-format = false;
518
+
}
519
+
{
520
+
name = "nu";
521
+
language-servers = [ "nu-lsp" ];
522
+
formatter = {
523
+
command = "${lib.getExe self'.packages.topiary-nu}";
524
+
args = [
525
+
"format"
526
+
"--language"
527
+
"nu"
528
+
];
529
+
};
530
+
auto-format = true;
531
+
}
532
+
{
533
+
name = "thrift";
534
+
language-servers = [ "thriftls" ];
535
+
formatter = {
536
+
command = "thriftls";
537
+
args = [
538
+
"format"
539
+
"-indent"
540
+
"2space"
541
+
];
542
+
};
543
+
auto-format = true;
544
+
}
545
+
]
546
+
++ map (lang: { name = lang; }) [
547
+
"git-attributes"
548
+
"git-commit"
549
+
"git-config"
550
+
"git-ignore"
551
+
"git-rebase"
552
+
]
553
+
);
554
+
};
555
+
};
556
+
}
+25
modules/dev/home.nix
+25
modules/dev/home.nix
···
1
+
{
2
+
osConfig ? { },
3
+
lib,
4
+
...
5
+
}:
6
+
let
7
+
inherit (lib) mkEnableOption;
8
+
in
9
+
{
10
+
config.dev = osConfig.dev or { };
11
+
options.dev = {
12
+
enable = mkEnableOption "all development tools";
13
+
14
+
shell.enable = mkEnableOption "shell-related tools";
15
+
editor.enable = mkEnableOption "editor tools";
16
+
vcs.enable = mkEnableOption "version control tools";
17
+
tools.enable = mkEnableOption "development utilities";
18
+
};
19
+
imports = [
20
+
./shell
21
+
./editor
22
+
./vcs
23
+
./tools
24
+
];
25
+
}
+32
modules/dev/nixos.nix
+32
modules/dev/nixos.nix
···
1
+
{
2
+
config,
3
+
lib,
4
+
pkgs,
5
+
...
6
+
}:
7
+
let
8
+
cfg = config.dev;
9
+
inherit (lib) mkIf mkEnableOption mkDefault;
10
+
in
11
+
{
12
+
options.dev = {
13
+
enable = mkEnableOption "all development tools";
14
+
15
+
shell.enable = mkEnableOption "shell-related tools";
16
+
editor.enable = mkEnableOption "editor tools";
17
+
vcs.enable = mkEnableOption "version control tools";
18
+
tools.enable = mkEnableOption "development utilities";
19
+
};
20
+
21
+
config = {
22
+
dev.shell.enable = mkIf cfg.enable true;
23
+
dev.editor.enable = mkIf cfg.enable true;
24
+
dev.vcs.enable = mkIf cfg.enable true;
25
+
dev.tools.enable = mkIf cfg.enable true;
26
+
27
+
users.defaultUserShell = mkIf (cfg.enable || cfg.shell.enable) pkgs.nushell;
28
+
environment.shells = mkIf (cfg.enable || cfg.shell.enable) [ pkgs.nushell ];
29
+
30
+
programs.nano.enable = mkDefault (!(cfg.enable || cfg.editor.enable));
31
+
};
32
+
}
+14
modules/dev/shell/atuin.nix
+14
modules/dev/shell/atuin.nix
···
1
+
{ config, lib, ... }:
2
+
{
3
+
config = lib.mkIf config.dev.shell.enable {
4
+
programs.atuin = {
5
+
enable = true;
6
+
flags = [ "--disable-up-arrow" ];
7
+
settings = {
8
+
enter_accept = false;
9
+
style = "compact";
10
+
sync_address = "http://reg.dolly-ruffe.ts.net:8888";
11
+
};
12
+
};
13
+
};
14
+
}
+8
modules/dev/shell/default.nix
+8
modules/dev/shell/default.nix
+39
modules/dev/shell/nushell.nix
+39
modules/dev/shell/nushell.nix
···
1
+
{
2
+
config,
3
+
lib,
4
+
pkgs,
5
+
...
6
+
}:
7
+
{
8
+
config = lib.mkIf config.dev.shell.enable {
9
+
programs.nushell = {
10
+
enable = true;
11
+
shellAliases = {
12
+
k = "kubectl";
13
+
fg = "job unfreeze";
14
+
nn = "exec $env.EDITOR ~/notes";
15
+
};
16
+
configFile.text = ''
17
+
$env.config = {
18
+
show_banner: false,
19
+
}
20
+
21
+
if ("~/.profile.nu" | path exists) {
22
+
source-env "~/.profile.nu"
23
+
}
24
+
25
+
${lib.meta.getExe pkgs.pokego} -l french
26
+
'';
27
+
28
+
extraLogin = ''
29
+
bash -c ". /etc/profile && env"
30
+
| parse "{n}={v}"
31
+
| where n not-in $env or v != ($env | get $it.n)
32
+
| where n not-in ["_", "LAST_EXIT_CODE", "DIRS_POSITION"]
33
+
| transpose --header-row
34
+
| into record
35
+
| load-env
36
+
'';
37
+
};
38
+
};
39
+
}
+108
modules/dev/shell/starship.nix
+108
modules/dev/shell/starship.nix
···
1
+
{
2
+
config,
3
+
inputs',
4
+
lib,
5
+
...
6
+
}:
7
+
{
8
+
config = lib.mkIf config.dev.shell.enable {
9
+
xdg.configFile."starship-jj/starship-jj.toml".text = ''
10
+
"$schema"="https://gitlab.com/Lanastara/lanastara_foss/-/raw/v0.3.0/schema.json?ref_type=tags"
11
+
module_separator = " "
12
+
timeout = 1000
13
+
[bookmarks]
14
+
search_depth = 100
15
+
exclude = []
16
+
17
+
[[module]]
18
+
type = "Commit"
19
+
empty_text = ""
20
+
[module.change]
21
+
fg = "magenta"
22
+
23
+
[[module]]
24
+
type = "Bookmarks"
25
+
separator = " "
26
+
color = "Magenta"
27
+
behind_symbol = "⇡"
28
+
29
+
[[module]]
30
+
type = "State"
31
+
separator = " "
32
+
33
+
[module.conflict]
34
+
disabled = true
35
+
text = "(CONFLICT)"
36
+
color = "Red"
37
+
38
+
[module.divergent]
39
+
disabled = true
40
+
text = "(DIVERGENT)"
41
+
color = "Cyan"
42
+
43
+
[module.empty]
44
+
disabled = false
45
+
text = "(EMPTY)"
46
+
color = "Yellow"
47
+
48
+
[module.immutable]
49
+
disabled = false
50
+
text = "(IMMUTABLE)"
51
+
color = "Yellow"
52
+
53
+
[module.hidden]
54
+
disabled = false
55
+
text = "(HIDDEN)"
56
+
color = "Yellow"
57
+
58
+
[[module]]
59
+
type = "Metrics"
60
+
template = "[{changed} {added}{removed}]"
61
+
color = "Magenta"
62
+
63
+
[module.changed_files]
64
+
prefix = ""
65
+
suffix = ""
66
+
color = "Cyan"
67
+
68
+
[module.added_lines]
69
+
prefix = "+"
70
+
suffix = ""
71
+
color = "Green"
72
+
73
+
[module.removed_lines]
74
+
prefix = "-"
75
+
suffix = ""
76
+
color = "Red"
77
+
'';
78
+
programs.starship = {
79
+
enable = true;
80
+
settings = {
81
+
format = lib.concatMapStrings (s: s) [
82
+
"$directory"
83
+
"$nix_shell"
84
+
"$custom"
85
+
"$cmd_duration"
86
+
"$line_break"
87
+
"$character"
88
+
];
89
+
nix_shell = {
90
+
format = "[$symbol]($style)";
91
+
};
92
+
custom = {
93
+
jj = {
94
+
command = ''${lib.getExe' inputs'.starship-jj.packages.default "starship-jj"} --ignore-working-copy starship prompt'';
95
+
format = "[$symbol](blue bold) $output";
96
+
symbol = "";
97
+
when = "jj root --ignore-working-copy";
98
+
};
99
+
git_branch = {
100
+
when = true;
101
+
command = "jj root >/dev/null 2>&1 || starship module git_branch";
102
+
description = "Only show git_branch if we're not in a jj repo";
103
+
};
104
+
};
105
+
};
106
+
};
107
+
};
108
+
}
+36
modules/dev/tools/default.nix
+36
modules/dev/tools/default.nix
···
1
+
{
2
+
config,
3
+
lib,
4
+
pkgs,
5
+
...
6
+
}:
7
+
{
8
+
config = lib.mkIf config.dev.tools.enable {
9
+
home.packages = [
10
+
pkgs.sd
11
+
pkgs.fd
12
+
pkgs.uutils-coreutils-noprefix
13
+
];
14
+
15
+
programs = {
16
+
zoxide.enable = true;
17
+
carapace.enable = true;
18
+
19
+
ripgrep.enable = true;
20
+
bat.enable = true;
21
+
less = {
22
+
enable = true;
23
+
config = ''
24
+
#env
25
+
LESS = -S -R -i
26
+
'';
27
+
};
28
+
};
29
+
};
30
+
31
+
imports = [
32
+
./direnv.nix
33
+
./opencode.nix
34
+
./yazi.nix
35
+
];
36
+
}
+25
modules/dev/tools/direnv.nix
+25
modules/dev/tools/direnv.nix
···
1
+
{ config, lib, ... }:
2
+
{
3
+
config = lib.mkIf config.dev.tools.enable {
4
+
programs.direnv = {
5
+
enable = true;
6
+
nix-direnv.enable = true;
7
+
silent = true;
8
+
stdlib = ''
9
+
alias() {
10
+
if [ ! $PWD/.direnv/bin ]; then
11
+
mkdir $PWD/.direnv/bin
12
+
fi
13
+
14
+
echo "#!/usr/bin/env sh
15
+
$2 \$@" > "$PWD/.direnv/bin/$1"
16
+
chmod +x "$PWD/.direnv/bin/$1"
17
+
}
18
+
'';
19
+
};
20
+
21
+
programs.nushell.extraConfig = ''
22
+
$env.DIRENV_LOG_FORMAT = ""
23
+
'';
24
+
};
25
+
}
+72
modules/dev/tools/opencode.nix
+72
modules/dev/tools/opencode.nix
···
1
+
{
2
+
config,
3
+
lib,
4
+
pkgs,
5
+
...
6
+
}:
7
+
{
8
+
config = lib.mkIf config.dev.tools.enable {
9
+
programs.opencode =
10
+
let
11
+
opencodePkg = pkgs.symlinkJoin {
12
+
name = "opencode-wrapped";
13
+
paths = [
14
+
pkgs.opencode
15
+
pkgs.nixd
16
+
pkgs.alejandra
17
+
];
18
+
buildInputs = [ pkgs.makeWrapper ];
19
+
postBuild = ''
20
+
wrapProgram $out/bin/opencode \
21
+
--set SHELL ${pkgs.bash}/bin/bash
22
+
'';
23
+
};
24
+
in
25
+
{
26
+
enable = true;
27
+
package = opencodePkg;
28
+
enableMcpIntegration = true;
29
+
settings = {
30
+
theme = "catppuccin-macchiato";
31
+
formatter = {
32
+
alejandra = {
33
+
command = [ "alejandra" ];
34
+
extensions = [ ".nix" ];
35
+
};
36
+
};
37
+
agent = {
38
+
stack-analyst = {
39
+
description = "Analyzes stack traces to map errors to code paths and identify root causes";
40
+
prompt = "You are a stack trace analyst. Analyze the provided stack trace to identify the root cause and suggest fixes.";
41
+
mode = "primary";
42
+
tools = {
43
+
read = true;
44
+
glob = true;
45
+
grep = true;
46
+
write = true;
47
+
edit = false;
48
+
bash = true;
49
+
};
50
+
permissions = {
51
+
bash = {
52
+
"git status" = "allow";
53
+
"git log" = "allow";
54
+
"*" = "ask";
55
+
};
56
+
};
57
+
};
58
+
};
59
+
mcp = {
60
+
gopls = {
61
+
type = "local";
62
+
enabled = true;
63
+
command = [
64
+
"gopls"
65
+
"mcp"
66
+
];
67
+
};
68
+
};
69
+
};
70
+
};
71
+
};
72
+
}
+8
modules/dev/tools/yazi.nix
+8
modules/dev/tools/yazi.nix
+82
modules/dev/vcs/git.nix
+82
modules/dev/vcs/git.nix
···
1
+
{
2
+
config,
3
+
lib,
4
+
pkgs,
5
+
...
6
+
}:
7
+
{
8
+
config = lib.mkIf config.dev.vcs.enable {
9
+
home.packages = [ pkgs.gh ];
10
+
programs.git = {
11
+
enable = true;
12
+
ignores = [
13
+
"/notes"
14
+
"/tmp"
15
+
".direnv"
16
+
".envrc"
17
+
];
18
+
19
+
signing = {
20
+
key = "~/.ssh/id_ed25519.pub";
21
+
signByDefault = true;
22
+
};
23
+
24
+
settings = {
25
+
user = {
26
+
name = "karitham";
27
+
email = "kar@karitham.dev";
28
+
};
29
+
30
+
alias = {
31
+
co = "checkout";
32
+
ci = "commit";
33
+
st = "status";
34
+
br = "branch";
35
+
hist = "log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short";
36
+
type = "cat-file -t";
37
+
dump = "cat-file -p";
38
+
dft = "difftool";
39
+
};
40
+
41
+
init.defaultBranch = "main";
42
+
merge.stat = true;
43
+
pull.rebase = true;
44
+
45
+
push = {
46
+
autoSetupRemote = true;
47
+
default = "current";
48
+
};
49
+
50
+
url."ssh://git@github.com/".insteadOf = "https://github.com/";
51
+
52
+
gpg = {
53
+
format = "ssh";
54
+
ssh.defaultKeyCommand = "ssh-add -L";
55
+
};
56
+
57
+
core = {
58
+
editor = config.home.sessionVariables.EDITOR;
59
+
whitespace = "fix,-indent-with-non-tab,trailing-space,cr-at-eol";
60
+
};
61
+
62
+
pager.difftool = true;
63
+
diff.tool = "difftastic";
64
+
difftool = {
65
+
prompt = false;
66
+
difftastic.cmd = "${pkgs.difftastic}/bin/difft --color auto --background light --display side-by-side \"$LOCAL\" \"$REMOTE\"";
67
+
};
68
+
69
+
rebase = {
70
+
autoSquash = true;
71
+
autoStash = true;
72
+
updateRefs = true;
73
+
};
74
+
75
+
rerere = {
76
+
enabled = true;
77
+
autoUpdate = true;
78
+
};
79
+
};
80
+
};
81
+
};
82
+
}
+52
modules/dev/vcs/jj.nix
+52
modules/dev/vcs/jj.nix
···
1
+
{ config, lib, ... }:
2
+
{
3
+
config = lib.mkIf config.dev.vcs.enable {
4
+
programs.jujutsu = {
5
+
enable = true;
6
+
7
+
settings = {
8
+
user = {
9
+
email = "kar@karitham.dev";
10
+
name = "karitham";
11
+
};
12
+
signing = {
13
+
behavior = "own";
14
+
backend = "ssh";
15
+
key = "~/.ssh/id_ed25519.pub";
16
+
};
17
+
git = {
18
+
write-change-id-header = true;
19
+
track-default-bookmark-on-clone = true;
20
+
};
21
+
remotes."origin".auto-track-bookmarks = "glob:*";
22
+
revsets = {
23
+
log = "..@ | branches | curbranch::@ | @::nextbranch | downstream(@, branchesandheads)";
24
+
};
25
+
revset-aliases = {
26
+
"immutable_heads()" = "builtin_immutable_heads() | (trunk().. & ~mine())";
27
+
"downstream(x,y)" = "(x::y) & y";
28
+
"branches" = "downstream(trunk(), bookmarks()) & mine()";
29
+
"branchesandheads" = "branches | (heads(trunk()::) & mine())";
30
+
"curbranch" = "latest(branches::@- & branches)";
31
+
"nextbranch" = "roots(@:: & branchesandheads)";
32
+
};
33
+
ui = {
34
+
default-command = [
35
+
"log"
36
+
"--no-pager"
37
+
"-n"
38
+
"10"
39
+
];
40
+
movement.edit = true;
41
+
editor = "hx";
42
+
};
43
+
};
44
+
};
45
+
46
+
programs.delta = {
47
+
enable = true;
48
+
enableJujutsuIntegration = true;
49
+
enableGitIntegration = true;
50
+
};
51
+
};
52
+
}
+6
modules/hardware/peripherals.nix
+6
modules/hardware/peripherals.nix
+17
-25
modules/home/default.nix
+17
-25
modules/home/default.nix
···
5
5
self,
6
6
self',
7
7
...
8
-
}: {
9
-
imports = [inputs.home-manager.nixosModules.default];
10
-
users.users.${config.my.username} =
11
-
if config.my.username != "root"
12
-
then {
13
-
home = "/home/${config.my.username}";
14
-
isNormalUser = true;
15
-
extraGroups = [
16
-
"networkmanager"
17
-
"docker"
18
-
"wheel"
19
-
];
20
-
}
21
-
else {};
8
+
}:
9
+
{
10
+
imports = [
11
+
inputs.home-manager.nixosModules.default
12
+
inputs.catppuccin.nixosModules.catppuccin
13
+
];
14
+
15
+
catppuccin = {
16
+
enable = true;
17
+
flavor = "macchiato";
18
+
};
22
19
23
20
home-manager = {
24
21
extraSpecialArgs = {
···
31
28
};
32
29
backupFileExtension = "bak";
33
30
users.${config.my.username} = {
34
-
home.username = config.my.username;
35
-
home.stateVersion = "25.11";
31
+
imports = [ inputs.catppuccin.homeModules.default ];
36
32
37
-
catppuccin = {
38
-
inherit (config.catppuccin) enable;
39
-
inherit (config.catppuccin) flavor;
33
+
home = {
34
+
inherit (config.my) username;
35
+
stateVersion = "25.11";
40
36
};
37
+
38
+
catppuccin = { inherit (config.catppuccin) flavor enable; };
41
39
42
40
nixpkgs.overlays = [
43
41
inputs.self.overlays.default
44
42
inputs.niri.overlays.niri
45
43
inputs.ghostty.overlays.default
46
44
inputs.knixpkgs.overlays.default
47
-
];
48
-
49
-
imports = [
50
-
inputs.catppuccin.homeModules.default
51
-
./desktop
52
-
./dev
53
45
];
54
46
};
55
47
};
-18
modules/home/desktop/browser.nix
-18
modules/home/desktop/browser.nix
···
1
-
{
2
-
lib,
3
-
osConfig,
4
-
pkgs,
5
-
...
6
-
}: {
7
-
options.browser.default = lib.mkOption {
8
-
description = "default browser xdg file";
9
-
default = "firefox-devedition.desktop";
10
-
type = lib.types.str;
11
-
};
12
-
13
-
config = lib.mkIf osConfig.desktop.enable {
14
-
home = {
15
-
packages = [pkgs.firefox-devedition];
16
-
};
17
-
};
18
-
}
+2
-5
modules/home/desktop/cursor.nix
modules/desktop/wm/cursor.nix
+2
-5
modules/home/desktop/cursor.nix
modules/desktop/wm/cursor.nix
+1
-6
modules/home/desktop/default.nix
modules/desktop/wm/default.nix
+1
-6
modules/home/desktop/default.nix
modules/desktop/wm/default.nix
-9
modules/home/desktop/discord.nix
-9
modules/home/desktop/discord.nix
-9
modules/home/desktop/dunst.nix
-9
modules/home/desktop/dunst.nix
-6
modules/home/desktop/easyeffects.nix
-6
modules/home/desktop/easyeffects.nix
modules/home/desktop/easyeffects/EarFun Pro Air 4 ANC ON.json
modules/desktop/audio/easyeffects/EarFun Pro Air 4 ANC ON.json
modules/home/desktop/easyeffects/EarFun Pro Air 4 ANC ON.json
modules/desktop/audio/easyeffects/EarFun Pro Air 4 ANC ON.json
modules/home/desktop/easyeffects/Logitech G Pro X.json
modules/desktop/audio/easyeffects/Logitech G Pro X.json
modules/home/desktop/easyeffects/Logitech G Pro X.json
modules/desktop/audio/easyeffects/Logitech G Pro X.json
-12
modules/home/desktop/fuzzel.nix
-12
modules/home/desktop/fuzzel.nix
modules/home/desktop/ghostty-shader.glsl
modules/desktop/terminal/ghostty-shader.glsl
modules/home/desktop/ghostty-shader.glsl
modules/desktop/terminal/ghostty-shader.glsl
+4
-2
modules/home/desktop/ghostty.nix
modules/desktop/terminal/ghostty.nix
+4
-2
modules/home/desktop/ghostty.nix
modules/desktop/terminal/ghostty.nix
+5
-3
modules/home/desktop/hyprlock.nix
modules/desktop/wm/hyprlock.nix
+5
-3
modules/home/desktop/hyprlock.nix
modules/desktop/wm/hyprlock.nix
···
1
1
{
2
2
lib,
3
3
osConfig,
4
+
config,
4
5
...
5
-
}: {
6
-
config = lib.mkIf osConfig.desktop.enable {
6
+
}:
7
+
{
8
+
config = lib.mkIf config.desktop.wm.enable {
7
9
services.hypridle = {
8
10
enable = true;
9
11
settings = {
···
43
45
44
46
background = {
45
47
monitor = "";
46
-
path = "${osConfig.desktop.wallpaper}";
48
+
path = "${config.desktop.wallpaper}";
47
49
blur_passes = 0;
48
50
color = "$base";
49
51
};
-15
modules/home/desktop/hyprpaper.nix
-15
modules/home/desktop/hyprpaper.nix
-270
modules/home/desktop/niri.nix
-270
modules/home/desktop/niri.nix
···
1
-
{
2
-
config,
3
-
osConfig,
4
-
lib,
5
-
pkgs,
6
-
...
7
-
}: {
8
-
config = lib.mkIf (osConfig.desktop.enable && osConfig.desktop.enable) {
9
-
home.packages = [pkgs.nautilus]; # xdg-desktop-portal-gnome wants it
10
-
programs.niri = {
11
-
settings = {
12
-
environment = {
13
-
NIXOS_OZONE_WL = "1";
14
-
ELECTRON_OZONE_PLATFORM_HINT = "auto";
15
-
QT_QPA_PLATFORMTHEME = "qt5ct";
16
-
QT_QPA_PLATFORM = "wayland";
17
-
DISPLAY = ":0";
18
-
GTK_IM_MODULE = "simple";
19
-
};
20
-
21
-
screenshot-path = null;
22
-
prefer-no-csd = true;
23
-
24
-
input = {
25
-
focus-follows-mouse = {
26
-
enable = true;
27
-
max-scroll-amount = "80%";
28
-
};
29
-
keyboard = {
30
-
repeat-delay = 300;
31
-
repeat-rate = 5;
32
-
xkb = {
33
-
layout = "us";
34
-
variant = "intl";
35
-
};
36
-
};
37
-
38
-
mouse = {
39
-
accel-profile = "flat";
40
-
accel-speed = 0.5;
41
-
};
42
-
43
-
touchpad = {
44
-
tap = true;
45
-
dwt = true;
46
-
natural-scroll = true;
47
-
click-method = "clickfinger";
48
-
};
49
-
};
50
-
51
-
spawn-at-startup = [
52
-
{
53
-
command = [
54
-
"systemctl --user restart waybar.service"
55
-
];
56
-
}
57
-
];
58
-
59
-
layout = {
60
-
gaps = 16;
61
-
always-center-single-column = true;
62
-
empty-workspace-above-first = true;
63
-
default-column-width = {
64
-
proportion = 0.5;
65
-
};
66
-
};
67
-
68
-
window-rules = [
69
-
{
70
-
geometry-corner-radius = let
71
-
radius = 8.0;
72
-
in {
73
-
bottom-left = radius;
74
-
bottom-right = radius;
75
-
top-left = radius;
76
-
top-right = radius;
77
-
};
78
-
clip-to-geometry = true;
79
-
}
80
-
{
81
-
matches = [
82
-
{
83
-
title = "Picture-in-Picture";
84
-
}
85
-
];
86
-
open-floating = true;
87
-
default-floating-position = {
88
-
x = 16;
89
-
y = 16;
90
-
relative-to = "bottom-right";
91
-
};
92
-
}
93
-
];
94
-
95
-
outputs = rec {
96
-
eDP-1 = {
97
-
mode = null;
98
-
position = {
99
-
x = HDMI-A-1.mode.width;
100
-
y = 0;
101
-
};
102
-
};
103
-
HDMI-A-1 = {
104
-
mode = {
105
-
width = 2560;
106
-
height = 1440;
107
-
};
108
-
position = {
109
-
x = 0;
110
-
y = 0;
111
-
};
112
-
};
113
-
};
114
-
115
-
binds = with config.lib.niri.actions; let
116
-
# programs.niri.settings.binds."Mod+Q".action.close-window = []
117
-
toAction = act: dir: (lib.mapAttrs' (
118
-
argName: argValue:
119
-
lib.nameValuePair "${argName}+${dir.name}" {
120
-
action = {
121
-
"${argValue}-${dir.value}" = [];
122
-
};
123
-
}
124
-
)
125
-
act);
126
-
windowMoves = lib.mergeAttrsList (
127
-
(
128
-
map
129
-
(toAction {
130
-
"Mod" = "focus";
131
-
"Mod+Ctrl" = "move";
132
-
})
133
-
(
134
-
lib.attrsToList {
135
-
"Up" = "window-up";
136
-
"k" = "window-up";
137
-
"Down" = "window-down";
138
-
"j" = "window-down";
139
-
"Left" = "column-left";
140
-
"h" = "column-left";
141
-
"Right" = "column-right";
142
-
"l" = "column-right";
143
-
"I" = "workspace-down";
144
-
"U" = "workspace-up";
145
-
}
146
-
)
147
-
)
148
-
++ (
149
-
map
150
-
(toAction {
151
-
"Mod+Shift" = "focus";
152
-
"Mod+Ctrl+Shift" = "move-window-to";
153
-
})
154
-
(
155
-
lib.attrsToList {
156
-
"Up" = "monitor-up";
157
-
"K" = "monitor-up";
158
-
"Down" = "monitor-down";
159
-
"J" = "monitor-down";
160
-
"Left" = "monitor-left";
161
-
"H" = "monitor-left";
162
-
"Right" = "monitor-right";
163
-
"L" = "monitor-right";
164
-
"I" = "workspace-down";
165
-
"U" = "workspace-up";
166
-
}
167
-
)
168
-
)
169
-
);
170
-
in
171
-
{
172
-
"Mod+O".action = show-hotkey-overlay;
173
-
"Mod+Q".action.spawn = "${lib.getExe pkgs.ghostty}";
174
-
"Mod+R".action.spawn = "${lib.getExe pkgs.fuzzel}";
175
-
"Mod+C".action.close-window = [];
176
-
177
-
"Mod+Comma".action = consume-window-into-column;
178
-
"Mod+Period".action = expel-window-from-column;
179
-
180
-
"Mod+T".action = switch-preset-column-width;
181
-
"Mod+F".action = maximize-column;
182
-
"Mod+Shift+F".action = fullscreen-window;
183
-
"Mod+D".action = center-column;
184
-
"Mod+B".action = toggle-window-floating;
185
-
186
-
"Mod+Minus".action = set-column-width "-10%";
187
-
"Mod+Equal".action = set-column-width "+10%";
188
-
"Mod+Shift+Minus".action = set-window-height "-10%";
189
-
"Mod+Shift+Equal".action = set-window-height "+10%";
190
-
191
-
"Mod+Shift+Escape".action = toggle-keyboard-shortcuts-inhibit;
192
-
"Mod+Shift+E".action = quit;
193
-
"Mod+Shift+P".action = power-off-monitors;
194
-
"Mod+Shift+Ctrl+T".action = toggle-debug-tint;
195
-
196
-
"Mod+Shift+WheelScrollDown".action = focus-workspace-down;
197
-
"Mod+Shift+WheelScrollUp".action = focus-workspace-up;
198
-
"Mod+WheelScrollDown".action = focus-column-right;
199
-
"Mod+WheelScrollUp".action = focus-column-left;
200
-
201
-
"Mod+Shift+S".action.spawn = [
202
-
(lib.getExe pkgs.bash)
203
-
"-c"
204
-
''${lib.getExe pkgs.slurp} -d | ${lib.getExe pkgs.grim} -t ppm -g - - | ${lib.getExe pkgs.satty} -f - --copy-command=${lib.getExe' pkgs.wl-clipboard "wl-copy"} --actions-on-escape="save-to-clipboard,exit"''
205
-
];
206
-
"Mod+S".action.screenshot = {};
207
-
208
-
"XF86MonBrightnessDown".action.spawn = [
209
-
(lib.getExe pkgs.brightnessctl)
210
-
"set"
211
-
"5%-"
212
-
];
213
-
"XF86MonBrightnessUp".action.spawn = [
214
-
(lib.getExe pkgs.brightnessctl)
215
-
"set"
216
-
"+5%"
217
-
];
218
-
"XF86AudioLowerVolume".action.spawn = [
219
-
(lib.getExe' pkgs.wireplumber "wpctl")
220
-
"set-volume"
221
-
"@DEFAULT_AUDIO_SINK@"
222
-
"2%-"
223
-
];
224
-
"XF86AudioRaiseVolume".action.spawn = [
225
-
(lib.getExe' pkgs.wireplumber "wpctl")
226
-
"set-volume"
227
-
"@DEFAULT_AUDIO_SINK@"
228
-
"2%+"
229
-
];
230
-
}
231
-
// windowMoves;
232
-
233
-
animations = let
234
-
vm = {
235
-
kind.spring = {
236
-
damping-ratio = 0.75;
237
-
stiffness = 200;
238
-
epsilon = 0.0001;
239
-
};
240
-
};
241
-
in {
242
-
horizontal-view-movement = vm;
243
-
workspace-switch = vm;
244
-
window-resize = vm;
245
-
246
-
window-open = {
247
-
kind.easing = {
248
-
duration-ms = 200;
249
-
curve = "linear";
250
-
};
251
-
custom-shader = ''
252
-
vec4 open_color(vec3 coords_geo, vec3 size_geo) {
253
-
vec3 coords_tex = niri_geo_to_tex * coords_geo;
254
-
vec4 color = texture2D(niri_tex, coords_tex.st);
255
-
256
-
vec2 coords = (coords_geo.xy - vec2(0.5, 0.5)) * size_geo.xy * 2.0;
257
-
coords = coords / length(size_geo.xy);
258
-
float p = niri_clamped_progress;
259
-
if (p * p <= dot(coords, coords))
260
-
color = vec4(0.0);
261
-
262
-
return color;
263
-
}
264
-
'';
265
-
};
266
-
};
267
-
};
268
-
};
269
-
};
270
-
}
+4
-3
modules/home/desktop/rnnoise.nix
modules/desktop/audio/rnnoise.nix
+4
-3
modules/home/desktop/rnnoise.nix
modules/desktop/audio/rnnoise.nix
···
1
1
{
2
-
osConfig,
2
+
config,
3
3
lib,
4
4
pkgs,
5
5
...
6
-
}: {
7
-
config = lib.mkIf osConfig.desktop.enable {
6
+
}:
7
+
{
8
+
config = lib.mkIf config.desktop.audio.enable {
8
9
xdg.configFile."pipewire/pipewire.conf.d/99-input-denoising.conf".text = builtins.toJSON {
9
10
"context.modules" = [
10
11
{
+39
-35
modules/home/desktop/waybar.nix
modules/desktop/wm/waybar.nix
+39
-35
modules/home/desktop/waybar.nix
modules/desktop/wm/waybar.nix
···
2
2
osConfig,
3
3
lib,
4
4
pkgs,
5
+
config,
5
6
...
6
-
}: {
7
-
config = lib.mkIf osConfig.desktop.enable {
7
+
}:
8
+
{
9
+
config = lib.mkIf config.desktop.wm.enable {
8
10
programs.waybar = {
9
11
enable = true;
10
12
systemd.enable = true;
···
21
23
"backlight"
22
24
];
23
25
24
-
modules-center = lib.optional osConfig.desktop.enable "niri/workspaces";
26
+
modules-center = lib.optional config.desktop.wm.enable "niri/workspaces";
25
27
26
28
modules-right = [
27
29
"pulseaudio"
···
60
62
critical-threshold = 80;
61
63
};
62
64
63
-
backlight = let
64
-
bctl = lib.meta.getExe pkgs.brightnessctl;
65
-
in {
66
-
device = "eDP-1";
67
-
max-length = "4";
68
-
format = "{icon} {percent}%";
69
-
format-icons = [
70
-
""
71
-
""
72
-
""
73
-
""
74
-
""
75
-
""
76
-
""
77
-
""
78
-
""
79
-
];
80
-
on-scroll-up = pkgs.writeShellScript "brightness.sh" ''
81
-
MIN_BRIGHTNESS=5
82
-
current_brightness=$(${bctl} g)
83
-
max_brightness=$(${bctl} m)
84
-
min_brightness_raw=$((max_brightness * MIN_BRIGHTNESS / 100))
85
-
scaling_factor=30
86
-
decrement=$((max_brightness / scaling_factor))
87
-
new_brightness_raw=$((current_brightness - decrement))
88
-
if [ "$new_brightness_raw" -lt "$min_brightness_raw" ]; then
89
-
new_brightness_raw=$min_brightness_raw
90
-
fi
91
-
${bctl} set "$new_brightness_raw"
92
-
'';
93
-
on-scroll-down = "${bctl} set +5%";
94
-
};
65
+
backlight =
66
+
let
67
+
bctl = lib.meta.getExe pkgs.brightnessctl;
68
+
in
69
+
{
70
+
device = "eDP-1";
71
+
max-length = "4";
72
+
format = "{icon} {percent}%";
73
+
format-icons = [
74
+
""
75
+
""
76
+
""
77
+
""
78
+
""
79
+
""
80
+
""
81
+
""
82
+
""
83
+
];
84
+
on-scroll-up = pkgs.writeShellScript "brightness.sh" ''
85
+
MIN_BRIGHTNESS=5
86
+
current_brightness=$(${bctl} g)
87
+
max_brightness=$(${bctl} m)
88
+
min_brightness_raw=$((max_brightness * MIN_BRIGHTNESS / 100))
89
+
scaling_factor=30
90
+
decrement=$((max_brightness / scaling_factor))
91
+
new_brightness_raw=$((current_brightness - decrement))
92
+
if [ "$new_brightness_raw" -lt "$min_brightness_raw" ]; then
93
+
new_brightness_raw=$min_brightness_raw
94
+
fi
95
+
${bctl} set "$new_brightness_raw"
96
+
'';
97
+
on-scroll-down = "${bctl} set +5%";
98
+
};
95
99
96
100
pulseaudio = {
97
101
format = "{icon} {volume}%";
-55
modules/home/desktop/xdg.nix
-55
modules/home/desktop/xdg.nix
···
1
-
{
2
-
config,
3
-
lib,
4
-
...
5
-
}: {
6
-
xdg.mimeApps = let
7
-
editor = "Helix.desktop";
8
-
browser = config.browser.default;
9
-
in {
10
-
enable = true;
11
-
defaultApplications = {
12
-
"x-scheme-handler/http " = browser;
13
-
"x-scheme-handler/https" = browser;
14
-
"x-scheme-handler/chrome" = browser;
15
-
"text/html" = browser;
16
-
"binary/octet-stream" = browser;
17
-
"image/jpeg" = browser;
18
-
"application/x-extension-htm" = browser;
19
-
"application/x-extension-html" = browser;
20
-
"application/x-extension-shtml" = browser;
21
-
"application/xhtml+xml" = browser;
22
-
"application/x-extension-xhtml" = browser;
23
-
"application/x-extension-xht" = browser;
24
-
"x-scheme-handler/about" = browser;
25
-
"x-scheme-handler/unknown" = browser;
26
-
"x-scheme-handler/discord" = "legcord.desktop";
27
-
"text/markdown" = editor;
28
-
"text/plain" = editor;
29
-
};
30
-
associations = {
31
-
added =
32
-
{
33
-
"x-scheme-handler/http" = browser;
34
-
"x-scheme-handler/https" = browser;
35
-
"text/html" = browser;
36
-
"binary/octet-stream" = browser;
37
-
"image/jpeg" = browser;
38
-
}
39
-
// lib.mergeAttrsList (
40
-
map
41
-
(lang: {
42
-
"text/x-${lang}" = editor;
43
-
"application/x-${lang}" = editor;
44
-
})
45
-
[
46
-
"python"
47
-
"go"
48
-
"mod"
49
-
"ruby"
50
-
"yaml"
51
-
]
52
-
);
53
-
};
54
-
};
55
-
}
-13
modules/home/dev/atuin.nix
-13
modules/home/dev/atuin.nix
-16
modules/home/dev/default.nix
-16
modules/home/dev/default.nix
-22
modules/home/dev/direnv.nix
-22
modules/home/dev/direnv.nix
···
1
-
_: {
2
-
programs.direnv = {
3
-
enable = true;
4
-
nix-direnv.enable = true;
5
-
silent = true;
6
-
stdlib = ''
7
-
alias() {
8
-
if [ ! $PWD/.direnv/bin ]; then
9
-
mkdir $PWD/.direnv/bin
10
-
fi
11
-
12
-
echo "#!/usr/bin/env sh
13
-
$2 \$@" > "$PWD/.direnv/bin/$1"
14
-
chmod +x "$PWD/.direnv/bin/$1"
15
-
}
16
-
'';
17
-
};
18
-
19
-
programs.nushell.extraConfig = ''
20
-
$env.DIRENV_LOG_FORMAT = ""
21
-
'';
22
-
}
-78
modules/home/dev/git.nix
-78
modules/home/dev/git.nix
···
1
-
{
2
-
config,
3
-
pkgs,
4
-
...
5
-
}: {
6
-
home.packages = [pkgs.gh];
7
-
programs.git = {
8
-
enable = true;
9
-
ignores = [
10
-
"/notes"
11
-
"/tmp"
12
-
".direnv"
13
-
".envrc"
14
-
];
15
-
16
-
signing = {
17
-
key = "~/.ssh/id_ed25519.pub";
18
-
signByDefault = true;
19
-
};
20
-
21
-
settings = {
22
-
user = {
23
-
name = "karitham";
24
-
email = "kar@karitham.dev";
25
-
};
26
-
27
-
alias = {
28
-
co = "checkout";
29
-
ci = "commit";
30
-
st = "status";
31
-
br = "branch";
32
-
hist = "log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short";
33
-
type = "cat-file -t";
34
-
dump = "cat-file -p";
35
-
dft = "difftool";
36
-
};
37
-
38
-
init.defaultBranch = "main";
39
-
merge.stat = true;
40
-
pull.rebase = true;
41
-
42
-
push = {
43
-
autoSetupRemote = true;
44
-
default = "current";
45
-
};
46
-
47
-
url."ssh://git@github.com/".insteadOf = "https://github.com/";
48
-
49
-
gpg = {
50
-
format = "ssh";
51
-
ssh.defaultKeyCommand = "ssh-add -L";
52
-
};
53
-
54
-
core = {
55
-
editor = config.home.sessionVariables.EDITOR;
56
-
whitespace = "fix,-indent-with-non-tab,trailing-space,cr-at-eol";
57
-
};
58
-
59
-
pager.difftool = true;
60
-
diff.tool = "difftastic";
61
-
difftool = {
62
-
prompt = false;
63
-
difftastic.cmd = "${pkgs.difftastic}/bin/difft --color auto --background light --display side-by-side \"$LOCAL\" \"$REMOTE\"";
64
-
};
65
-
66
-
rebase = {
67
-
autoSquash = true;
68
-
autoStash = true;
69
-
updateRefs = true;
70
-
};
71
-
72
-
rerere = {
73
-
enabled = true;
74
-
autoUpdate = true;
75
-
};
76
-
};
77
-
};
78
-
}
-551
modules/home/dev/helix.nix
-551
modules/home/dev/helix.nix
···
1
-
{
2
-
lib,
3
-
pkgs,
4
-
inputs',
5
-
self',
6
-
...
7
-
}: let
8
-
jj-patch = pkgs.fetchurl {
9
-
url = "https://patch-diff.githubusercontent.com/raw/helix-editor/helix/pull/14519.patch";
10
-
hash = "sha256-e4xaKcOhAKKYbJXhYHbjdFk6CwLubmCp+m7y//MmQFw=";
11
-
};
12
-
helix = inputs'.helix.packages.default.overrideAttrs (_: {
13
-
patches = jj-patch;
14
-
});
15
-
global-tools = with pkgs; [
16
-
alejandra
17
-
biome
18
-
golangci-lint
19
-
gotools
20
-
gopls
21
-
sql-formatter
22
-
nodePackages.prettier
23
-
];
24
-
in {
25
-
home.packages = global-tools;
26
-
programs.helix = {
27
-
enable = true;
28
-
defaultEditor = true;
29
-
package = helix;
30
-
extraPackages = with pkgs;
31
-
[
32
-
golangci-lint-langserver
33
-
nixd
34
-
marksman
35
-
nodePackages.typescript-language-server
36
-
vscode-langservers-extracted
37
-
yaml-language-server
38
-
typos-lsp
39
-
nil
40
-
]
41
-
++ global-tools;
42
-
43
-
ignores = [
44
-
".zig-cache"
45
-
"node_modules"
46
-
".direnv"
47
-
"!/notes"
48
-
];
49
-
50
-
settings = {
51
-
keys = let
52
-
plusMenu = {
53
-
g = ''
54
-
:sh ${pkgs.nushell}/bin/nu -c '
55
-
let line = ("%{selection_line_start}" | default "%{cursor_line}")
56
-
let line_end = (if ("%{selection_line_end}" | is-not-empty) {$"-L%{selection_line_end}"} else "")
57
-
let root = (${pkgs.jujutsu}/bin/jj workspace root | str trim)
58
-
let rel_path = ("%{file_path_absolute}" | path relative-to $root)
59
-
let ref = (${pkgs.jujutsu}/bin/jj log -r `heads(::@ & bookmarks())` -T `remote_bookmarks` | parse -r `(?<branch>[^\s]+)@(?<remote>[^\s]+)` | sort-by remote -r | get branch.0)
60
-
let remote_url = (${pkgs.jujutsu}/bin/jj git remote list | parse "{remote} {url}" | where remote == origin | get url.0 | if ($in | str contains '://') {$in} else $"https://($in | str replace ':' '/')" | url parse)
61
-
let url = $"https://($remote_url.host)($remote_url.path | str replace ".git" "")/blob/($ref)/($rel_path)#L($line)($line_end)"
62
-
$url | ${pkgs.wl-clipboard}/bin/wl-copy
63
-
'
64
-
'';
65
-
b = ":echo %sh{git blame -L %{cursor_line},+1 %{buffer_name}}";
66
-
p = ":sh echo %{buffer_name} | ${pkgs.wl-clipboard}/bin/wl-copy";
67
-
};
68
-
goMenu = {
69
-
"8" = [
70
-
"move_prev_word_start"
71
-
"move_next_word_end"
72
-
];
73
-
"c" = caseMenu;
74
-
};
75
-
caseMenu = {
76
-
p = ":pipe ${lib.getExe pkgs.sttr} pascal";
77
-
c = ":pipe ${lib.getExe pkgs.sttr} camel";
78
-
k = ":pipe ${lib.getExe pkgs.sttr} kebab";
79
-
K = ":pipe ${lib.getExe pkgs.sttr} kebab | ${lib.getExe pkgs.sttr} upper";
80
-
s = ":pipe ${lib.getExe pkgs.sttr} snake";
81
-
S = ":pipe ${lib.getExe pkgs.sttr} snake | ${lib.getExe pkgs.sttr} upper";
82
-
t = ":pipe ${lib.getExe pkgs.sttr} title";
83
-
};
84
-
runMenu = {
85
-
f = [
86
-
":sh golangci-lint run --issues-exit-code=0 --fix %{buffer_name}"
87
-
":reload"
88
-
];
89
-
};
90
-
scrollFast = {
91
-
"C-j" = lib.replicate 5 "move_visual_line_down";
92
-
"C-k" = lib.replicate 5 "move_visual_line_up";
93
-
};
94
-
in {
95
-
normal =
96
-
{
97
-
"+" = plusMenu;
98
-
"-" = runMenu;
99
-
"g" = goMenu;
100
-
}
101
-
// scrollFast;
102
-
select =
103
-
{
104
-
"+" = plusMenu;
105
-
"-" = runMenu;
106
-
"." = goMenu;
107
-
}
108
-
// scrollFast;
109
-
};
110
-
111
-
editor = {
112
-
scrolloff = 10;
113
-
text-width = 120;
114
-
rulers = [120];
115
-
bufferline = "multiple";
116
-
color-modes = true;
117
-
auto-format = true;
118
-
auto-save = true;
119
-
lsp = {
120
-
snippets = true;
121
-
display-color-swatches = true;
122
-
display-messages = true;
123
-
};
124
-
soft-wrap = {
125
-
enable = true;
126
-
};
127
-
statusline = {
128
-
left = [
129
-
"mode"
130
-
"spacer"
131
-
"diagnostics"
132
-
"version-control"
133
-
"file-name"
134
-
"read-only-indicator"
135
-
"file-modification-indicator"
136
-
"spinner"
137
-
];
138
-
right = [
139
-
"file-encoding"
140
-
"file-type"
141
-
"selections"
142
-
"position"
143
-
];
144
-
};
145
-
gutters = [
146
-
"line-numbers"
147
-
"diagnostics"
148
-
"diff"
149
-
];
150
-
end-of-line-diagnostics = "hint";
151
-
inline-diagnostics = {
152
-
cursor-line = "warning"; # show warnings and errors on the cursorline inline
153
-
};
154
-
cursor-shape = {
155
-
insert = "bar";
156
-
normal = "block";
157
-
select = "underline";
158
-
};
159
-
whitespace.render.tab = "all";
160
-
indent-guides = {
161
-
render = true;
162
-
character = "┊";
163
-
skip-levels = 1;
164
-
};
165
-
};
166
-
};
167
-
168
-
languages = {
169
-
language-server = {
170
-
biome = {
171
-
command = "biome";
172
-
args = ["lsp-proxy"];
173
-
};
174
-
nu-lsp = {
175
-
command = "nu";
176
-
args = [
177
-
"--lsp"
178
-
"--no-config-file"
179
-
];
180
-
};
181
-
typos = {
182
-
command = "typos-lsp";
183
-
config = {
184
-
diagnosticSeverity = "Warning";
185
-
};
186
-
};
187
-
yaml-language-server = {
188
-
config = {
189
-
enabled = true;
190
-
enabledForFilesGlob = "*.{yaml,yml}";
191
-
diagnosticsLimit = 50;
192
-
showDiagnosticsDirectly = false;
193
-
config = {
194
-
schemas = {
195
-
kubernetes = "templates/**";
196
-
};
197
-
completion = true;
198
-
hover = true;
199
-
};
200
-
};
201
-
};
202
-
golangci-lint-lsp = {
203
-
command = "golangci-lint-langserver";
204
-
config = {
205
-
command = [
206
-
"nu"
207
-
"-c"
208
-
''
209
-
let args = [
210
-
--output.json.path=stdout
211
-
--path-mode=abs
212
-
--issues-exit-code=1
213
-
--show-stats=false
214
-
]
215
-
216
-
if ($env.GOLANGCI_LINT_CONFIG? | is-not-empty) {
217
-
golangci-lint run --config $env.GOLANGCI_LINT_CONFIG ...$args
218
-
} else {
219
-
golangci-lint run ...$args
220
-
}
221
-
''
222
-
];
223
-
};
224
-
};
225
-
rubocop = {
226
-
command = "rubocop";
227
-
args = ["--lsp"];
228
-
};
229
-
ruby-lsp = {
230
-
command = "ruby-lsp";
231
-
config = {
232
-
diagnostics = true;
233
-
formatting = true;
234
-
config = {
235
-
initializationOptions = {
236
-
enabledFeatures = {
237
-
codeActions = true;
238
-
codeLens = true;
239
-
completion = true;
240
-
definition = true;
241
-
diagnostics = true;
242
-
documentHighlights = true;
243
-
documentLink = true;
244
-
documentSymbols = true;
245
-
foldingRanges = true;
246
-
formatting = true;
247
-
hover = true;
248
-
inlayHint = true;
249
-
onTypeFormatting = true;
250
-
selectionRanges = true;
251
-
semanticHighlighting = true;
252
-
signatureHelp = true;
253
-
typeHierarchy = true;
254
-
workspaceSymbol = true;
255
-
};
256
-
featuresConfiguration = {
257
-
inlayHint = {
258
-
implicitHashValue = true;
259
-
implicitRescue = true;
260
-
};
261
-
};
262
-
};
263
-
};
264
-
};
265
-
};
266
-
thriftls = {
267
-
command = "thriftls";
268
-
except-features = ["format"];
269
-
};
270
-
};
271
-
272
-
language = let
273
-
defaults = [
274
-
"typos"
275
-
];
276
-
in
277
-
map
278
-
(
279
-
lang:
280
-
lang
281
-
// {
282
-
language-servers =
283
-
if lang ? language-servers
284
-
then lang.language-servers ++ defaults
285
-
else defaults;
286
-
}
287
-
)
288
-
(
289
-
[
290
-
{
291
-
name = "nix";
292
-
language-servers = [
293
-
"nixd"
294
-
"nil"
295
-
];
296
-
formatter = {
297
-
command = "alejandra";
298
-
};
299
-
auto-format = true;
300
-
}
301
-
{
302
-
name = "go";
303
-
language-servers = [
304
-
"gopls"
305
-
"golangci-lint-lsp"
306
-
];
307
-
formatter = {
308
-
command = "goimports";
309
-
};
310
-
auto-format = true;
311
-
}
312
-
{
313
-
name = "ruby";
314
-
language-servers = [
315
-
"ruby-lsp"
316
-
"rubocop"
317
-
];
318
-
auto-format = true;
319
-
}
320
-
{
321
-
name = "html";
322
-
language-servers = ["vscode-html-language-server"];
323
-
formatter = {
324
-
command = "prettier";
325
-
args = [
326
-
"--stdin-filepath"
327
-
"file.html"
328
-
];
329
-
};
330
-
auto-format = true;
331
-
}
332
-
{
333
-
name = "javascript";
334
-
language-servers = [
335
-
{
336
-
name = "typescript-language-server";
337
-
except-features = ["format"];
338
-
}
339
-
"biome"
340
-
];
341
-
auto-format = true;
342
-
}
343
-
{
344
-
name = "json";
345
-
language-servers = [
346
-
{
347
-
name = "vscode-json-language-server";
348
-
except-features = ["format"];
349
-
}
350
-
"biome"
351
-
];
352
-
formatter = {
353
-
command = "biome";
354
-
args = [
355
-
"format"
356
-
"--stdin-file-path"
357
-
"file.json"
358
-
];
359
-
};
360
-
auto-format = true;
361
-
}
362
-
{
363
-
name = "graphql";
364
-
formatter = {
365
-
command = "biome";
366
-
args = [
367
-
"format"
368
-
"--stdin-file-path"
369
-
"file.gql"
370
-
];
371
-
};
372
-
auto-format = true;
373
-
}
374
-
{
375
-
name = "jsonc";
376
-
language-servers = [
377
-
{
378
-
name = "vscode-json-language-server";
379
-
except-features = ["format"];
380
-
}
381
-
"biome"
382
-
];
383
-
formatter = {
384
-
command = "biome";
385
-
args = [
386
-
"format"
387
-
"--stdin-file-path"
388
-
"file.jsonc"
389
-
];
390
-
};
391
-
file-types = [
392
-
"jsonc"
393
-
"hujson"
394
-
];
395
-
auto-format = true;
396
-
}
397
-
{
398
-
name = "jsx";
399
-
language-servers = [
400
-
{
401
-
name = "typescript-language-server";
402
-
except-features = ["format"];
403
-
}
404
-
"biome"
405
-
];
406
-
formatter = {
407
-
command = "biome";
408
-
args = [
409
-
"format"
410
-
"--stdin-file-path"
411
-
"file.jsx"
412
-
];
413
-
};
414
-
auto-format = true;
415
-
}
416
-
{
417
-
name = "tsx";
418
-
language-servers = [
419
-
{
420
-
name = "typescript-language-server";
421
-
except-features = ["format"];
422
-
}
423
-
"biome"
424
-
];
425
-
formatter = {
426
-
command = "biome";
427
-
args = [
428
-
"format"
429
-
"--stdin-file-path"
430
-
"file.tsx"
431
-
];
432
-
};
433
-
auto-format = true;
434
-
}
435
-
{
436
-
name = "typescript";
437
-
language-servers = [
438
-
{
439
-
name = "typescript-language-server";
440
-
except-features = ["format"];
441
-
}
442
-
"biome"
443
-
];
444
-
formatter = {
445
-
command = "biome";
446
-
args = [
447
-
"format"
448
-
"--stdin-file-path"
449
-
"file.ts"
450
-
];
451
-
};
452
-
auto-format = true;
453
-
}
454
-
{
455
-
name = "yaml";
456
-
language-servers = ["yaml-language-server"];
457
-
formatter = {
458
-
command = "prettier";
459
-
args = [
460
-
"--stdin-filepath"
461
-
"file.yaml"
462
-
];
463
-
};
464
-
auto-format = true;
465
-
}
466
-
{
467
-
name = "helm";
468
-
language-servers = ["helm_ls"];
469
-
}
470
-
{
471
-
name = "typst";
472
-
language-servers = ["tinymist"];
473
-
}
474
-
{
475
-
name = "markdown";
476
-
language-servers = [
477
-
"marksman"
478
-
# "vale-ls"
479
-
];
480
-
text-width = 100;
481
-
rulers = [100];
482
-
soft-wrap = {
483
-
enable = true;
484
-
wrap-at-text-width = true;
485
-
};
486
-
formatter = {
487
-
command = "prettier";
488
-
args = [
489
-
"--stdin-filepath"
490
-
"file.md"
491
-
];
492
-
};
493
-
auto-format = true;
494
-
}
495
-
{
496
-
name = "sql";
497
-
formatter = {
498
-
command = "sql-formatter";
499
-
args = [
500
-
"-c"
501
-
(builtins.toJSON {
502
-
keywordCase = "upper";
503
-
functionCase = "upper";
504
-
dataTypeCase = "upper";
505
-
identifierCase = "lower";
506
-
language = "postgresql";
507
-
expressionWidth = 80;
508
-
tabWidth = 2;
509
-
})
510
-
];
511
-
};
512
-
auto-format = false;
513
-
}
514
-
{
515
-
name = "nu";
516
-
language-servers = ["nu-lsp"];
517
-
formatter = {
518
-
command = "${lib.getExe self'.packages.topiary-nu}";
519
-
args = [
520
-
"format"
521
-
"--language"
522
-
"nu"
523
-
];
524
-
};
525
-
auto-format = true;
526
-
}
527
-
{
528
-
name = "thrift";
529
-
language-servers = ["thriftls"];
530
-
formatter = {
531
-
command = "thriftls";
532
-
args = [
533
-
"format"
534
-
"-indent"
535
-
"2space"
536
-
];
537
-
};
538
-
auto-format = true;
539
-
}
540
-
]
541
-
++ map (lang: {name = lang;}) [
542
-
"git-attributes"
543
-
"git-commit"
544
-
"git-config"
545
-
"git-ignore"
546
-
"git-rebase"
547
-
]
548
-
);
549
-
};
550
-
};
551
-
}
-49
modules/home/dev/jj.nix
-49
modules/home/dev/jj.nix
···
1
-
_: {
2
-
programs.jujutsu = {
3
-
enable = true;
4
-
5
-
settings = {
6
-
user = {
7
-
email = "kar@karitham.dev";
8
-
name = "karitham";
9
-
};
10
-
signing = {
11
-
behavior = "own";
12
-
backend = "ssh";
13
-
key = "~/.ssh/id_ed25519.pub";
14
-
};
15
-
git = {
16
-
write-change-id-header = true;
17
-
track-default-bookmark-on-clone = true;
18
-
};
19
-
remotes."origin".auto-track-bookmarks = "glob:*";
20
-
revsets = {
21
-
log = "..@ | branches | curbranch::@ | @::nextbranch | downstream(@, branchesandheads)";
22
-
};
23
-
revset-aliases = {
24
-
"immutable_heads()" = "builtin_immutable_heads() | (trunk().. & ~mine())";
25
-
"downstream(x,y)" = "(x::y) & y";
26
-
"branches" = "downstream(trunk(), bookmarks()) & mine()";
27
-
"branchesandheads" = "branches | (heads(trunk()::) & mine())";
28
-
"curbranch" = "latest(branches::@- & branches)";
29
-
"nextbranch" = "roots(@:: & branchesandheads)";
30
-
};
31
-
ui = {
32
-
default-command = [
33
-
"log"
34
-
"--no-pager"
35
-
"-n"
36
-
"10"
37
-
];
38
-
movement.edit = true;
39
-
editor = "hx";
40
-
};
41
-
};
42
-
};
43
-
44
-
programs.delta = {
45
-
enable = true;
46
-
enableJujutsuIntegration = true;
47
-
enableGitIntegration = true;
48
-
};
49
-
}
-17
modules/home/dev/mise.nix
-17
modules/home/dev/mise.nix
···
1
-
{
2
-
lib,
3
-
config,
4
-
...
5
-
}: {
6
-
config = lib.mkIf config.programs.mise.enable {
7
-
programs.nushell = {
8
-
envFile.text = ''
9
-
let mise_path = $nu.default-config-dir | path join mise.nu
10
-
^mise activate nu | save $mise_path --force
11
-
'';
12
-
configFile.text = ''
13
-
use ($nu.default-config-dir | path join mise.nu)
14
-
'';
15
-
};
16
-
};
17
-
}
-35
modules/home/dev/nushell.nix
-35
modules/home/dev/nushell.nix
···
1
-
{
2
-
lib,
3
-
pkgs,
4
-
...
5
-
}: {
6
-
programs.nushell = {
7
-
enable = true;
8
-
shellAliases = {
9
-
k = "kubectl";
10
-
fg = "job unfreeze";
11
-
nn = "exec $env.EDITOR ~/notes";
12
-
};
13
-
configFile.text = ''
14
-
$env.config = {
15
-
show_banner: false,
16
-
}
17
-
18
-
if ("~/.profile.nu" | path exists) {
19
-
source-env "~/.profile.nu"
20
-
}
21
-
22
-
${lib.meta.getExe pkgs.pokego} -l french
23
-
'';
24
-
25
-
extraLogin = ''
26
-
bash -c ". /etc/profile && env"
27
-
| parse "{n}={v}"
28
-
| where n not-in $env or v != ($env | get $it.n)
29
-
| where n not-in ["_", "LAST_EXIT_CODE", "DIRS_POSITION"]
30
-
| transpose --header-row
31
-
| into record
32
-
| load-env
33
-
'';
34
-
};
35
-
}
-62
modules/home/dev/opencode.nix
-62
modules/home/dev/opencode.nix
···
1
-
{pkgs, ...}: {
2
-
programs.opencode = let
3
-
opencodePkg = pkgs.symlinkJoin {
4
-
name = "opencode-wrapped";
5
-
paths = [
6
-
pkgs.opencode
7
-
pkgs.nixd
8
-
pkgs.alejandra
9
-
];
10
-
buildInputs = [pkgs.makeWrapper];
11
-
postBuild = ''
12
-
wrapProgram $out/bin/opencode \
13
-
--set SHELL ${pkgs.bash}/bin/bash
14
-
'';
15
-
};
16
-
in {
17
-
enable = true;
18
-
package = opencodePkg;
19
-
enableMcpIntegration = true;
20
-
settings = {
21
-
theme = "catppuccin-macchiato";
22
-
formatter = {
23
-
alejandra = {
24
-
command = ["alejandra"];
25
-
extensions = [".nix"];
26
-
};
27
-
};
28
-
agent = {
29
-
stack-analyst = {
30
-
description = "Analyzes stack traces to map errors to code paths and identify root causes";
31
-
prompt = builtins.readFile ./opencode/stack-analyst.md;
32
-
mode = "primary";
33
-
tools = {
34
-
read = true;
35
-
glob = true;
36
-
grep = true;
37
-
write = true;
38
-
edit = false;
39
-
bash = true;
40
-
};
41
-
permissions = {
42
-
bash = {
43
-
"git status" = "allow";
44
-
"git log" = "allow";
45
-
"*" = "ask";
46
-
};
47
-
};
48
-
};
49
-
};
50
-
mcp = {
51
-
gopls = {
52
-
type = "local";
53
-
enabled = true;
54
-
command = [
55
-
"gopls"
56
-
"mcp"
57
-
];
58
-
};
59
-
};
60
-
};
61
-
};
62
-
}
-48
modules/home/dev/opencode/stack-analyst.md
-48
modules/home/dev/opencode/stack-analyst.md
···
1
-
You are the **Stack Trace & Debugging Specialist**, an advanced engineering agent dedicated to performing root cause analysis on software crashes, errors, and panics.
2
-
3
-
### Core Objective
4
-
Your goal is to take a stack trace (from text, a file, a URL, or an issue tracker) and provide a deterministic explanation of *why* the code failed, along with the specific inputs or state required to reproduce it.
5
-
6
-
### Capabilities & Tooling Strategy
7
-
1. **Code Intelligence (LSP) [Best Effort]:**
8
-
* **Primary Tool:** Attempt to use `gopls` (for Go) or `ruby-lsp` (for Ruby) to read and understand code.
9
-
* **Fallback:** If LSP tools fail to launch (e.g., due to missing gems/dependencies) or return errors, **immediately** switch to standard `grep`, `glob`, and `read` tools. Do not waste turns debugging the LSP setup itself.
10
-
* **Usage:** Use these tools to jump to definitions, view struct/class hierarchies, and inspect function signatures.
11
-
* **Why:** To accurately interpret types, interfaces, and shared logic that simple text searching might miss.
12
-
13
-
2. **Context Retrieval:**
14
-
* **Inputs:** You may receive stack traces as raw text, file paths, or URLs (e.g., Linear issues, GitHub issues, Pastebin).
15
-
* **Linear:** If provided a Linear link, use the `linear` tool to extract the crash report and context.
16
-
* **File System:** Use `read` and `glob` to ingest logs, config files, or local repro cases.
17
-
18
-
3. **Codebase Navigation:**
19
-
* Use `glob` to fuzzy-find files when stack trace paths are relative or truncated.
20
-
* Use `grep` to find where specific error messages or constants are generated.
21
-
22
-
### Analysis Protocol
23
-
24
-
**Phase 1: Ingestion & Parsing**
25
-
* Identify the panic message, error code, or exception type.
26
-
* Extract the stack trace frames. Distinguish between library/framework code (noise) and application code (signal).
27
-
28
-
**Phase 2: Mapping & Inspection**
29
-
* Locate the exact file and line number of the crash.
30
-
* **Crucial:** Use LSP tools to inspect the definitions of variables involved at the crash site.
31
-
* *Example:* If `user.Process()` panicked, check the definition of `user`. Is it a pointer? interface? nullable?
32
-
33
-
**Phase 3: Backward Execution Trace**
34
-
* Analyze the calling frames. How did execution reach the failure point?
35
-
* Identify "source" data. Where did the variables causing the crash originate? (e.g., HTTP request body, database row, config file).
36
-
37
-
**Phase 4: Root Cause & Reproduction**
38
-
* **Hypothesize:** Formulate a strict logical theory (e.g., "The `Context` object was canceled before the database transaction completed, but error checking was skipped").
39
-
* **Payload Reconstruction:** Define the specific JSON payload, environment variable, or sequence of events needed to trigger this path.
40
-
41
-
### Output Style
42
-
* **Direct & Analytical:** Start with the root cause.
43
-
* **Evidence-Based:** Cite specific file names, line numbers, and variable types.
44
-
* **Actionable:** Conclude with a specific code path fix or a reproduction payload.
45
-
46
-
### Constraints
47
-
* **Read-Only Analysis:** Your primary role is analysis and diagnosis. Do not run commands that modify the codebase (like `rails generate`, `npm install`, or writing files) unless explicitly asked to "fix" or "apply" the solution.
48
-
* **Safe Exploration:** You may run read-only commands (e.g., `grep`, `ls`, `cat`) freely.
-104
modules/home/dev/starship.nix
-104
modules/home/dev/starship.nix
···
1
-
{
2
-
inputs',
3
-
lib,
4
-
...
5
-
}: {
6
-
xdg.configFile."starship-jj/starship-jj.toml".text = ''
7
-
"$schema"="https://gitlab.com/Lanastara/lanastara_foss/-/raw/v0.3.0/schema.json?ref_type=tags"
8
-
module_separator = " "
9
-
timeout = 1000
10
-
[bookmarks]
11
-
search_depth = 100
12
-
exclude = []
13
-
14
-
[[module]]
15
-
type = "Commit"
16
-
empty_text = ""
17
-
[module.change]
18
-
fg = "magenta"
19
-
20
-
[[module]]
21
-
type = "Bookmarks"
22
-
separator = " "
23
-
color = "Magenta"
24
-
behind_symbol = "⇡"
25
-
26
-
[[module]]
27
-
type = "State"
28
-
separator = " "
29
-
30
-
[module.conflict]
31
-
disabled = true
32
-
text = "(CONFLICT)"
33
-
color = "Red"
34
-
35
-
[module.divergent]
36
-
disabled = true
37
-
text = "(DIVERGENT)"
38
-
color = "Cyan"
39
-
40
-
[module.empty]
41
-
disabled = false
42
-
text = "(EMPTY)"
43
-
color = "Yellow"
44
-
45
-
[module.immutable]
46
-
disabled = false
47
-
text = "(IMMUTABLE)"
48
-
color = "Yellow"
49
-
50
-
[module.hidden]
51
-
disabled = false
52
-
text = "(HIDDEN)"
53
-
color = "Yellow"
54
-
55
-
[[module]]
56
-
type = "Metrics"
57
-
template = "[{changed} {added}{removed}]"
58
-
color = "Magenta"
59
-
60
-
[module.changed_files]
61
-
prefix = ""
62
-
suffix = ""
63
-
color = "Cyan"
64
-
65
-
[module.added_lines]
66
-
prefix = "+"
67
-
suffix = ""
68
-
color = "Green"
69
-
70
-
[module.removed_lines]
71
-
prefix = "-"
72
-
suffix = ""
73
-
color = "Red"
74
-
'';
75
-
programs.starship = {
76
-
enable = true;
77
-
settings = {
78
-
format = lib.concatMapStrings (s: s) [
79
-
"$directory"
80
-
"$nix_shell"
81
-
"$custom"
82
-
"$cmd_duration"
83
-
"$line_break"
84
-
"$character"
85
-
];
86
-
nix_shell = {
87
-
format = "[$symbol]($style)";
88
-
};
89
-
custom = {
90
-
jj = {
91
-
command = ''${lib.getExe' inputs'.starship-jj.packages.default "starship-jj"} --ignore-working-copy starship prompt'';
92
-
format = "[$symbol](blue bold) $output";
93
-
symbol = "";
94
-
when = "jj root --ignore-working-copy";
95
-
};
96
-
git_branch = {
97
-
when = true;
98
-
command = "jj root >/dev/null 2>&1 || starship module git_branch";
99
-
description = "Only show git_branch if we're not in a jj repo";
100
-
};
101
-
};
102
-
};
103
-
};
104
-
}
-21
modules/home/dev/utils.nix
-21
modules/home/dev/utils.nix
···
1
-
{pkgs, ...}: {
2
-
home.packages = [
3
-
pkgs.sd
4
-
pkgs.fd
5
-
pkgs.uutils-coreutils-noprefix
6
-
];
7
-
programs = {
8
-
zoxide.enable = true;
9
-
carapace.enable = true;
10
-
11
-
ripgrep.enable = true;
12
-
bat.enable = true;
13
-
less = {
14
-
enable = true;
15
-
config = ''
16
-
#env
17
-
LESS = -S -R -i
18
-
'';
19
-
};
20
-
};
21
-
}
+9
-3
modules/home/dev/zellij.nix
modules/dev/shell/zellij.nix
+9
-3
modules/home/dev/zellij.nix
modules/dev/shell/zellij.nix
···
1
-
{inputs', ...}: {
1
+
{
2
+
inputs',
3
+
lib,
4
+
config,
5
+
...
6
+
}:
7
+
lib.mkIf config.dev.shell.enable {
2
8
programs.zellij = {
3
9
enable = true;
4
10
settings = {
···
13
19
shared._children = [
14
20
{
15
21
bind = {
16
-
_args = ["Alt f"];
17
-
ToggleFloatingPanes = {};
22
+
_args = [ "Alt f" ];
23
+
ToggleFloatingPanes = { };
18
24
};
19
25
}
20
26
];
+24
modules/locale.nix
+24
modules/locale.nix
···
1
+
{ pkgs, ... }:
2
+
{
3
+
time.timeZone = "Europe/Paris";
4
+
5
+
console = {
6
+
keyMap = "us-acentos";
7
+
packages = [ pkgs.kbd ];
8
+
};
9
+
10
+
i18n = {
11
+
defaultLocale = "en_US.UTF-8";
12
+
extraLocaleSettings = {
13
+
LC_ADDRESS = "fr_FR.UTF-8";
14
+
LC_IDENTIFICATION = "fr_FR.UTF-8";
15
+
LC_MEASUREMENT = "fr_FR.UTF-8";
16
+
LC_MONETARY = "fr_FR.UTF-8";
17
+
LC_NAME = "fr_FR.UTF-8";
18
+
LC_NUMERIC = "fr_FR.UTF-8";
19
+
LC_PAPER = "fr_FR.UTF-8";
20
+
LC_TELEPHONE = "fr_FR.UTF-8";
21
+
LC_TIME = "fr_FR.UTF-8";
22
+
};
23
+
};
24
+
}
+4
-3
modules/nixos/cachix.nix
+4
-3
modules/nixos/cachix.nix
···
3
3
lib,
4
4
config,
5
5
...
6
-
}: {
6
+
}:
7
+
{
7
8
config = lib.mkIf (!config.server) {
8
9
nix.settings = {
9
-
substituters = lib.mkAfter ["https://karitham.cachix.org"];
10
+
substituters = lib.mkAfter [ "https://karitham.cachix.org" ];
10
11
trusted-public-keys = lib.mkAfter [
11
12
"karitham.cachix.org-1:Q0wdHZsCssuepIrtx83gHibE0LTDYLVNnvaV3Nms9U0="
12
13
];
13
14
};
14
15
15
-
environment.systemPackages = [pkgs.cachix];
16
+
environment.systemPackages = [ pkgs.cachix ];
16
17
};
17
18
}
+2
-8
modules/nixos/default.nix
+2
-8
modules/nixos/default.nix
+22
modules/nixos/desktop-common.nix
+22
modules/nixos/desktop-common.nix
···
1
+
_: {
2
+
imports = [ ../../modules/home ];
3
+
4
+
networking.networkmanager.enable = true;
5
+
6
+
services = {
7
+
tailscale = {
8
+
enable = true;
9
+
useRoutingFeatures = "client";
10
+
};
11
+
touchegg.enable = true;
12
+
blueman.enable = true;
13
+
auto-cpufreq.enable = true;
14
+
};
15
+
16
+
security = {
17
+
sudo.wheelNeedsPassword = false;
18
+
rtkit.enable = true;
19
+
};
20
+
21
+
virtualisation.docker.enable = true;
22
+
}
+5
-20
modules/nixos/desktop.nix
modules/desktop/desktop.nix
+5
-20
modules/nixos/desktop.nix
modules/desktop/desktop.nix
···
4
4
pkgs,
5
5
inputs,
6
6
...
7
-
}: let
7
+
}:
8
+
let
8
9
cfg = config.desktop;
9
-
in {
10
-
options.desktop = {
11
-
enable = lib.mkEnableOption "desktop usage";
12
-
wallpaper = lib.mkOption {
13
-
default = pkgs.fetchurl {
14
-
url = "https://raw.githubusercontent.com/HoulFloof/wallpapers/f23c1010b93cb97baa7ad7c94fd552f7601496d2/misc/waves_right_colored.png";
15
-
hash = "sha256-NqqE+pGnCIWAitH86sxu1EudVEEaSO82y3NqbhtDh9k=";
16
-
};
17
-
type = lib.types.path;
18
-
description = "the wallpaper to use";
19
-
};
20
-
};
21
-
22
-
imports = [inputs.niri.nixosModules.niri];
23
-
10
+
in
11
+
{
12
+
imports = [ inputs.niri.nixosModules.niri ];
24
13
config = lib.mkIf cfg.enable {
25
-
hardware = {
26
-
bluetooth.enable = true;
27
-
};
28
-
29
14
environment = {
30
15
systemPackages = with pkgs; [
31
16
wl-clipboard
+3
-2
modules/nixos/fonts.nix
modules/desktop/fonts.nix
+3
-2
modules/nixos/fonts.nix
modules/desktop/fonts.nix
-32
modules/nixos/ipcam.nix
-32
modules/nixos/ipcam.nix
···
1
-
{
2
-
config,
3
-
lib,
4
-
pkgs,
5
-
...
6
-
}: {
7
-
options.ipcam.enable = lib.mkEnableOption "enable ipcam module";
8
-
9
-
config = lib.mkIf (config.desktop.enable && config.ipcam.enable) {
10
-
boot = {
11
-
extraModulePackages = with config.boot.kernelPackages; [v4l2loopback];
12
-
kernelModules = ["v4l2loopback"];
13
-
extraModprobeConfig = ''
14
-
options v4l2loopback video_nr=9 card_label=IP-Webcam exclusive_caps=1
15
-
'';
16
-
};
17
-
18
-
environment.systemPackages = let
19
-
port = 9696;
20
-
ipcam = pkgs.writeShellScriptBin "ipcam" ''
21
-
${lib.getExe' pkgs.android-tools "adb"} wait-for-usb-device
22
-
${lib.getExe' pkgs.android-tools "adb"} forward tcp:${toString port} tcp:8080
23
-
${lib.getExe pkgs.ffmpeg} -i http://localhost:${toString port}/video -vf format=yuv420p -f v4l2 /dev/video9
24
-
${lib.getExe' pkgs.android-tools "adb"} forward --remove tcp:${toString port}
25
-
'';
26
-
in [
27
-
pkgs.ffmpeg
28
-
pkgs.android-tools
29
-
ipcam
30
-
];
31
-
};
32
-
}
+6
-3
modules/nixos/locale.nix
modules/desktop/locale.nix
+6
-3
modules/nixos/locale.nix
modules/desktop/locale.nix
···
3
3
lib,
4
4
pkgs,
5
5
...
6
-
}: {
7
-
config = lib.mkIf (!config.server) {
6
+
}:
7
+
{
8
+
config = lib.mkIf config.desktop.locale.enable {
9
+
time.timeZone = "Europe/Paris";
10
+
8
11
console = {
9
12
keyMap = "us-acentos";
10
-
packages = [pkgs.kbd];
13
+
packages = [ pkgs.kbd ];
11
14
};
12
15
13
16
i18n = {
+6
-3
modules/nixos/nix.nix
+6
-3
modules/nixos/nix.nix
···
4
4
config,
5
5
pkgs,
6
6
...
7
-
}: {
7
+
}:
8
+
{
8
9
config = lib.mkIf (!config.server) {
9
10
nix = {
10
11
package = pkgs.lix;
···
16
17
settings = {
17
18
auto-optimise-store = true;
18
19
builders-use-substitutes = true;
19
-
allowed-users = ["@wheel"];
20
-
trusted-users = ["@wheel"];
20
+
allowed-users = [ "@wheel" ];
21
+
trusted-users = [ "@wheel" ];
21
22
commit-lockfile-summary = "chore: Update flake.lock";
22
23
accept-flake-config = true;
23
24
keep-derivations = true;
···
45
46
overlays = [
46
47
inputs.self.overlays.default
47
48
inputs.niri.overlays.niri
49
+
inputs.ghostty.overlays.default
50
+
inputs.knixpkgs.overlays.default
48
51
];
49
52
};
50
53
+9
modules/nixos/server-common.nix
+9
modules/nixos/server-common.nix
+2
-1
modules/nixos/server.nix
+2
-1
modules/nixos/server.nix
+93
modules/nixos/services/acme-nginx.nix
+93
modules/nixos/services/acme-nginx.nix
···
1
+
{ config, lib, ... }:
2
+
let
3
+
cfg = config.services.acme-nginx;
4
+
hostType = lib.types.submodule {
5
+
options = {
6
+
domain = lib.mkOption {
7
+
type = lib.types.str;
8
+
description = "The main domain for this host.";
9
+
};
10
+
extraDomainNames = lib.mkOption {
11
+
type = lib.types.listOf lib.types.str;
12
+
default = [ ];
13
+
description = "Extra domain names for this host.";
14
+
};
15
+
proxyPort = lib.mkOption {
16
+
type = lib.types.int;
17
+
description = "The port to proxy to locally for this host.";
18
+
};
19
+
};
20
+
};
21
+
in
22
+
{
23
+
options.services.acme-nginx = {
24
+
enable = lib.mkEnableOption "ACME and Nginx reverse proxy";
25
+
26
+
email = lib.mkOption {
27
+
type = lib.types.str;
28
+
description = "Email for ACME.";
29
+
};
30
+
31
+
credentialsFile = lib.mkOption {
32
+
type = lib.types.path;
33
+
description = "Path to the credentials file for DNS provider.";
34
+
};
35
+
36
+
hosts = lib.mkOption {
37
+
type = lib.types.listOf hostType;
38
+
default = [ ];
39
+
description = "List of hosts to configure.";
40
+
example = [
41
+
{
42
+
domain = "example.com";
43
+
extraDomainNames = [ "*.example.com" ];
44
+
proxyPort = 3000;
45
+
}
46
+
];
47
+
};
48
+
};
49
+
50
+
config = lib.mkIf cfg.enable {
51
+
networking.firewall.allowedTCPPorts = [
52
+
80
53
+
443
54
+
];
55
+
56
+
security.acme = {
57
+
defaults.email = cfg.email;
58
+
acceptTerms = true;
59
+
certs = lib.listToAttrs (
60
+
map (host: {
61
+
name = host.domain;
62
+
value = {
63
+
dnsProvider = "cloudflare";
64
+
inherit (cfg) credentialsFile;
65
+
inherit (config.services.nginx) group;
66
+
inherit (host) domain;
67
+
extraDomainNames = host.extraDomainNames or [ ];
68
+
reloadServices = [ "nginx" ];
69
+
};
70
+
}) cfg.hosts
71
+
);
72
+
};
73
+
74
+
services.nginx = {
75
+
enable = true;
76
+
recommendedProxySettings = true;
77
+
recommendedTlsSettings = true;
78
+
virtualHosts = lib.listToAttrs (
79
+
map (host: {
80
+
name = "~(.*)\\.${lib.escapeRegex host.domain}$";
81
+
value = {
82
+
useACMEHost = host.domain;
83
+
forceSSL = true;
84
+
locations."/" = {
85
+
proxyPass = "http://127.0.0.1:${toString host.proxyPort}";
86
+
proxyWebsockets = true;
87
+
};
88
+
};
89
+
}) cfg.hosts
90
+
);
91
+
};
92
+
};
93
+
}
-33
modules/nixos/shell.nix
-33
modules/nixos/shell.nix
···
1
-
{
2
-
config,
3
-
lib,
4
-
pkgs,
5
-
...
6
-
}: {
7
-
config = lib.mkIf (!config.server) {
8
-
users.defaultUserShell = pkgs.nushell;
9
-
environment.shells = [pkgs.nushell];
10
-
11
-
environment.sessionVariables.EDITOR =
12
-
lib.attrByPath [
13
-
"home-manager"
14
-
"users"
15
-
config.my.username
16
-
"home"
17
-
"sessionVariables"
18
-
"EDITOR"
19
-
] "nano"
20
-
config;
21
-
programs.nano.enable =
22
-
!(lib.attrByPath [
23
-
"home-manager"
24
-
"users"
25
-
config.my.username
26
-
"programs"
27
-
"helix"
28
-
"enable"
29
-
]
30
-
false
31
-
config);
32
-
};
33
-
}
+1
-4
modules/nixos/sound.nix
modules/desktop/sound.nix
+1
-4
modules/nixos/sound.nix
modules/desktop/sound.nix
+5
-6
modules/nixos/yubikey.nix
modules/desktop/yubikey.nix
+5
-6
modules/nixos/yubikey.nix
modules/desktop/yubikey.nix
···
3
3
lib,
4
4
pkgs,
5
5
...
6
-
}: {
7
-
options.yubikey.enable = lib.mkEnableOption "enable yubikey";
8
-
9
-
config = lib.mkIf (config.desktop.enable && config.yubikey.enable) {
10
-
services.udev.packages = [pkgs.yubikey-personalization];
6
+
}:
7
+
{
8
+
config = lib.mkIf (config.desktop.enable && config.desktop.yubikey.enable) {
9
+
services.udev.packages = [ pkgs.yubikey-personalization ];
11
10
12
11
programs.gnupg.agent = {
13
12
enable = true;
···
21
20
security.pam.yubico = {
22
21
enable = true;
23
22
mode = "challenge-response";
24
-
id = ["32235281"];
23
+
id = [ "32235281" ];
25
24
};
26
25
27
26
services.udev.extraRules = ''
+1
modules/server/default.nix
+1
modules/server/default.nix
···
1
+
{ imports = [ ../nixos/server-common.nix ]; }
+18
modules/wsl/default.nix
+18
modules/wsl/default.nix
···
1
+
{
2
+
inputs,
3
+
self,
4
+
config,
5
+
...
6
+
}:
7
+
{
8
+
imports = [
9
+
self.nixosModules.dev
10
+
inputs.nixos-wsl.nixosModules.default
11
+
../locale.nix
12
+
../home
13
+
];
14
+
15
+
dev.enable = true;
16
+
17
+
home-manager.users.${config.my.username}.imports = [ self.homeModules.dev ];
18
+
}
+1
-1
overlays/default.nix
+1
-1
overlays/default.nix
···
1
1
_: prev: {
2
-
pokego = prev.callPackage ../pkgs/pokego.nix {};
2
+
pokego = prev.callPackage ../pkgs/pokego.nix { };
3
3
golangci-lint-langserver = prev.golangci-lint-langserver.overrideAttrs (_: {
4
4
patches = prev.fetchurl {
5
5
url = "https://github.com/karitham/golangci-lint-langserver/commit/31e6806187d431a8865261b5441ef5a65b589ae5.patch";
+1
-3
pkgs/http-nu.nix
+1
-3
pkgs/http-nu.nix
+3
-3
pkgs/pokego.nix
+3
-3
pkgs/pokego.nix
···
1
-
{pkgs, ...}:
1
+
{ pkgs, ... }:
2
2
pkgs.buildGoModule {
3
3
pname = "pokego";
4
4
version = "devel";
···
11
11
12
12
vendorHash = "sha256-Eykg/qGqWA+qxeFPAhd0BERHtLj5X7kMQo/IPp1yRU4=";
13
13
env.CGO_ENABLED = 0;
14
-
flags = ["-trimpath"];
14
+
flags = [ "-trimpath" ];
15
15
ldflags = [
16
16
"-s"
17
17
"-w"
···
23
23
homepage = "https://github.com/karitham/pokego";
24
24
mainProgram = "pokego";
25
25
license = licenses.gpl3;
26
-
maintainers = with maintainers; [karitham];
26
+
maintainers = with maintainers; [ karitham ];
27
27
};
28
28
}
+4
-3
pkgs/topiary-nu.nix
+4
-3
pkgs/topiary-nu.nix
···
8
8
nodejs,
9
9
tree-sitter-nu,
10
10
topiary-nushell,
11
-
}: let
11
+
}:
12
+
let
12
13
treeSitterNu = stdenv.mkDerivation {
13
14
name = "tree-sitter-nu";
14
15
src = tree-sitter-nu;
···
49
50
'';
50
51
};
51
52
in
52
-
runCommand "topiary-nu"
53
+
runCommand "topiary-nu"
53
54
{
54
-
buildInputs = [makeWrapper];
55
+
buildInputs = [ makeWrapper ];
55
56
meta = {
56
57
mainProgram = "topiary-nu";
57
58
};
+50
systems/default.nix
+50
systems/default.nix
···
1
+
{ self, inputs, ... }:
2
+
{
3
+
imports = [ inputs.easy-hosts.flakeModule ];
4
+
5
+
config.easy-hosts = {
6
+
shared = {
7
+
modules = [
8
+
../modules/core.nix
9
+
../modules/nixos
10
+
];
11
+
12
+
specialArgs = { inherit inputs self; };
13
+
};
14
+
15
+
additionalClasses = {
16
+
desktop = "nixos";
17
+
server = "nixos";
18
+
wsl = "nixos";
19
+
};
20
+
21
+
perClass = class: { modules = [ ../modules/${class}/default.nix ]; };
22
+
23
+
perTag = tag: { modules = [ ../modules/tags/${tag}.nix ]; };
24
+
25
+
hosts = {
26
+
kiwi = {
27
+
class = "desktop";
28
+
tags = [ "work" ];
29
+
};
30
+
31
+
ozen = {
32
+
class = "wsl";
33
+
};
34
+
35
+
reg = {
36
+
class = "server";
37
+
};
38
+
39
+
belaf = {
40
+
class = "desktop";
41
+
tags = [ "secureboot" ];
42
+
};
43
+
44
+
wakuna = {
45
+
arch = "aarch64";
46
+
class = "server";
47
+
};
48
+
};
49
+
};
50
+
}