diff --git a/.sops.yaml b/.sops.yaml
new file mode 100644
index 0000000..4880a05
--- /dev/null
+++ b/.sops.yaml
@@ -0,0 +1,13 @@
+keys:
+ - &london_system age1rr2u4kk5jc0zk5mmgcfzlddzz82u9ldqwnd2mkcspnps7pzegsms7fys7u
+ - &london_dala age19m7s6rl4l88nv0f7el70k9u9mv6fd0nq5nw5a3f6p3ffzch274lsksu3y7
+
+creation_rules:
+ - path_regex: configurations/london/secrets/secrets.yaml$
+ key_groups:
+ - age:
+ - *london_system
+ - path_regex: configurations/london/secrets/users/dala.yaml$
+ key_groups:
+ - age:
+ - *london_dala
diff --git a/configurations/london/default.nix b/configurations/london/default.nix
new file mode 100644
index 0000000..d44330a
--- /dev/null
+++ b/configurations/london/default.nix
@@ -0,0 +1,128 @@
+{ pkgs, config, lib, extraInfo, ... }:
+{
+ boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" ];
+ boot.initrd.kernelModules = [ "dm-snapshot" ];
+ boot.kernelModules = [ "kvm-amd" ];
+ boot.extraModulePackages = [ ];
+
+ hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+
+ /* Meta */
+ isProfessional = false;
+
+ /* Volumes */
+ luksDevices = [
+ {
+ name = "crypted-nixos";
+ deviceUUID = "5a1ac4ae-d74f-4599-bc5a-fc0a3501a196";
+ isPreLVM = true;
+ }
+ ];
+
+ filesystems = [
+ {
+ mountpoint = "/";
+ deviceUUID = "8dd700f8-7bf7-426c-8869-d31687e343df";
+ fsType = "ext4";
+ }
+
+ {
+ mountpoint = "/boot";
+ deviceUUID = "F2B6-C8CA";
+ fsType = "vfat";
+ }
+
+ {
+ mountpoint = "/nix";
+ deviceUUID = "b7a643f6-a78e-4e32-a1a3-22b321465bf6";
+ fsType = "ext4";
+ }
+
+ {
+ mountpoint = "/home";
+ deviceUUID = "e26f6727-3712-4830-b8e8-fdbce5e3584b";
+ fsType = "ext4";
+ }
+ ];
+
+ swapDeviceUUID = "5fe5e76b-df3d-43ce-abf9-d2b63078df09";
+
+
+ /* Linux kernel */
+ useLatestKernel = true;
+
+
+ /* Nix */
+ allowUnfreePackages = true;
+
+ /* Hardware acceleration */
+ hwAccelerationGPU = "nvidia";
+
+ /* System secrets */
+ sops = {
+ gnupg.sshKeyPaths = [ ];
+ age = {
+ sshKeyPaths = [ ];
+ keyFile = "/var/lib/sops-nix/key.txt";
+ };
+ defaultSopsFile = ./secrets/secrets.yaml;
+ secrets.wg0_private = { };
+ };
+
+ /* Wireguard */
+ networking.wg-quick.interfaces.wg0 = {
+ address = [ "10.100.0.4/24" ];
+ dns = [ "10.100.0.1" ];
+
+ listenPort = 51820;
+ privateKeyFile = config.sops.secrets.wg0_private.path;
+
+ peers = [
+ {
+ # Rock Pro 64
+ publicKey = "XVmG3/rNsCqc8KCmOx3+UUn9DJOnJ40Uxid5JGdChR4=";
+ endpoint = "${extraInfo.wireguard.rockProEndpoint}:51820";
+ allowedIPs = [ "10.100.0.1" ];
+ persistentKeepalive = 25;
+ }
+
+ {
+ # VPS
+ publicKey = "x45YsLDpMJw1pwKOvkyzdesen3lFcKpxCXACGz+xtDs=";
+ endpoint = "${extraInfo.wireguard.VPSEndpoint}:51820";
+ allowedIPs = [ "10.100.0.2" ];
+ persistentKeepalive = 25;
+ }
+ ];
+ };
+
+ /* User config */
+ machineUsers = {
+ dala = {
+ description = "Dala";
+ groups = [ "wheel" "video" "audio" "seat" "keys" "lp" "dialout" "network" ];
+ uid = 1000;
+ shell = pkgs.fish;
+ enableHomeManagerProfile = true;
+ homeManagerConfig = {
+ desktop.monitors = [
+ {
+ name = "Iiyama North America PL2470H 0x0000047B";
+ resolution = "1920x1080@165.003Hz";
+ position = "1920 0";
+ defaultWorkspace = 1;
+ }
+ {
+ name = "Iiyama North America PL2530H 1154392601941";
+ resolution = "1920x1080@74.973Hz";
+ position = "0 0";
+ defaultWorkspace = 2;
+ }
+ ];
+
+ nixpkgs.config.allowUnfree = true;
+ development.embedded.enableTools = true;
+ };
+ };
+ };
+}
diff --git a/configurations/london/secrets/secrets.yaml b/configurations/london/secrets/secrets.yaml
new file mode 100644
index 0000000..ddb2ba8
--- /dev/null
+++ b/configurations/london/secrets/secrets.yaml
@@ -0,0 +1,21 @@
+wg0_private: ENC[AES256_GCM,data:z5G2EFh1vZk1yEwj0pFIU49u84bOjBZRzvKgqluWoQ6vqm+cMQt/dyGqXg4=,iv:XOiExUWxJczO+aJ+BogtlibqVshEkc6r8xeTPmdru4Y=,tag:+v/3JE1rqTm2x2MJUNltqw==,type:str]
+sops:
+ kms: []
+ gcp_kms: []
+ azure_kv: []
+ hc_vault: []
+ age:
+ - recipient: age1rr2u4kk5jc0zk5mmgcfzlddzz82u9ldqwnd2mkcspnps7pzegsms7fys7u
+ enc: |
+ -----BEGIN AGE ENCRYPTED FILE-----
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNOVhvOFRQQ1ppenZQdEN6
+ S3FPYkNTTnZWUnBFUXMxNEFWcUQ4WVhzK1g4CitLWktOamUyU2dPOHBUaG40WWxN
+ Nkw5M2pCWFBtTWtQMjQ0azN3Rjh3ZDAKLS0tIFNyNGxiNE41RUdDVkZmNUxyVVR5
+ dXhiMUhVc1ZBb0F0bFArZU5OU1ZRK0EKdjtUBIRrw1AhNPczQJiDw6GywJL/jm2r
+ 4o3XkFqMkP93YAoprHw7egH6t/6QVCFQTZPU4cAwJ0y1bLx9ju44uQ==
+ -----END AGE ENCRYPTED FILE-----
+ lastmodified: "2023-11-01T17:15:27Z"
+ mac: ENC[AES256_GCM,data:zL3UgmKuyzZzBTlBAyP7+nN1If7AMjq1qGkbbXKW2rlzl41x6orMdZQfOWG06eBdd7CGBoNgBNV7A9SE11RhXUvr1gdQGILie0ER2/UCEkEgXIV3tpto1C/tsEYDL7z8LSlcuPt3GJkca1Ym6yhIoe576ho7du3HclUCFBPIBQY=,iv:O3/aYlFPiueoByTyvefahrmFwGq5DAEdUaYvJXB1TFI=,tag:1Al7Lw18AZZ8spnITBuGMw==,type:str]
+ pgp: []
+ unencrypted_suffix: _unencrypted
+ version: 3.7.3
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..6841ecb
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,137 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1694529238,
+ "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "home-manager": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs-unstable"
+ ]
+ },
+ "locked": {
+ "lastModified": 1699368917,
+ "narHash": "sha256-nUtGIWf86BOkUbtksWtfglvCZ/otP0FTZlQH8Rzc7PA=",
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "rev": "6a8444467c83c961e2f5ff64fb4f422e303c98d3",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "type": "github"
+ }
+ },
+ "nixpkgs-stable": {
+ "locked": {
+ "lastModified": 1699291058,
+ "narHash": "sha256-5ggduoaAMPHUy4riL+OrlAZE14Kh7JWX4oLEs22ZqfU=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "41de143fda10e33be0f47eab2bfe08a50f234267",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-23.05",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs-stable_2": {
+ "locked": {
+ "lastModified": 1699110214,
+ "narHash": "sha256-L2TU4RgtiqF69W8Gacg2jEkEYJrW+Kp0Mp4plwQh5b8=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "78f3a4ae19f0e99d5323dd2e3853916b8ee4afee",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "release-23.05",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs-unstable": {
+ "locked": {
+ "lastModified": 1699099776,
+ "narHash": "sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "85f1ba3e51676fa8cc604a3d863d729026a6b8eb",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "home-manager": "home-manager",
+ "nixpkgs-stable": "nixpkgs-stable",
+ "nixpkgs-unstable": "nixpkgs-unstable",
+ "sops-nix": "sops-nix"
+ }
+ },
+ "sops-nix": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs-unstable"
+ ],
+ "nixpkgs-stable": "nixpkgs-stable_2"
+ },
+ "locked": {
+ "lastModified": 1699311858,
+ "narHash": "sha256-W/sQrghPAn5J9d+9kMnHqi4NPVWVpy0V/qzQeZfS/dM=",
+ "owner": "Mic92",
+ "repo": "sops-nix",
+ "rev": "664187539871f63857bda2d498f452792457b998",
+ "type": "github"
+ },
+ "original": {
+ "owner": "Mic92",
+ "repo": "sops-nix",
+ "type": "github"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..c26685e
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,72 @@
+{
+ description = "Dala's unified NixOS configuration";
+ inputs = {
+ # As we have machine using the unstable channel, and other machines using the stable one,
+ # we import both, and we will select for each machine which one to use.
+ nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
+ nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-23.05";
+ flake-utils.url = "github:numtide/flake-utils";
+
+ # Home-manager isn't used for anything except my workstations, which all use the unstable channel.
+ home-manager = {
+ url = "github:nix-community/home-manager";
+ inputs.nixpkgs.follows = "nixpkgs-unstable";
+ };
+
+ # For sops-nix, we keep the unstable nixpkgs, as it shouldn't break anything.
+ # This input is made to manage secrets on this repository.
+ sops-nix = {
+ url = "github:Mic92/sops-nix";
+ inputs.nixpkgs.follows = "nixpkgs-unstable";
+ };
+ };
+
+ outputs = { self, nixpkgs-unstable, nixpkgs-stable, home-manager, sops-nix, flake-utils }:
+ let
+ machines = import ./machines.nix;
+ in
+ {
+ nixosConfigurations = builtins.mapAttrs
+ (name: value:
+ let
+ nixpkgs =
+ if value.nixpkgsUnstable
+ then nixpkgs-unstable
+ else nixpkgs-stable;
+ in
+ nixpkgs.lib.nixosSystem {
+ system = value.system;
+
+ specialArgs = {
+ machineInfos = {
+ hostname = name;
+ } // value;
+
+ sopsHmModule = sops-nix.homeManagerModules.sops;
+ };
+
+ modules = [
+ ./configurations/${name}
+ ./modules/common
+ (if (value.machineType == "workstation")
+ then ./modules/workstation
+ else ./modules/server)
+ (if (value.machineType == "workstation" && value.enableHomeManager)
+ then home-manager.nixosModules.home-manager
+ else { })
+ sops-nix.nixosModules.sops
+ ];
+ }
+ )
+ machines;
+
+ formatter = builtins.listToAttrs (map
+ (system:
+ {
+ name = system;
+ value = nixpkgs-unstable.legacyPackages.${system}.nixpkgs-fmt;
+ }
+ )
+ flake-utils.lib.defaultSystems);
+ };
+}
diff --git a/machines.nix b/machines.nix
new file mode 100644
index 0000000..f63e013
--- /dev/null
+++ b/machines.nix
@@ -0,0 +1,9 @@
+{
+ london = {
+ machineType = "workstation";
+ nixpkgsUnstable = true;
+ system = "x86_64-linux";
+ enableHomeManager = true;
+ stateVersion = "23.11";
+ };
+}
diff --git a/modules/common/boot.nix b/modules/common/boot.nix
new file mode 100644
index 0000000..9ffc50b
--- /dev/null
+++ b/modules/common/boot.nix
@@ -0,0 +1,62 @@
+{ lib, config, ... }:
+with lib;
+let
+ luksDevicesModule = types.submodule {
+ options.name = mkOption {
+ type = types.str;
+ description = ''
+ The partition name.
+ '';
+ };
+
+ options.deviceUUID = mkOption {
+ type = types.str;
+ description = ''
+ The partition device UUID.
+ '';
+ };
+
+ options.isPreLVM = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Whether the decrypted partition will be a LVM device.
+ '';
+ };
+ };
+in
+{
+ options.enableDefaultSystemdBoot = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Whether or not enable the default SystemD boot system.
+ Can be useful for devices using u-boot.
+ '';
+ };
+
+ options.luksDevices = mkOption {
+ type = types.listOf luksDevicesModule;
+ default = [ ];
+ description = ''
+ List of LUKS devices.
+ '';
+ };
+
+ config = {
+ boot.initrd.luks.devices = builtins.listToAttrs (map
+ (fs: {
+ name = fs.name;
+ value = {
+ device = "/dev/disk/by-uuid/${fs.deviceUUID}";
+ preLVM = fs.isPreLVM;
+ };
+ })
+ config.luksDevices);
+
+ boot.loader.systemd-boot.enable = config.enableDefaultSystemdBoot;
+ boot.loader.efi.canTouchEfiVariables = true;
+ };
+}
diff --git a/modules/common/default.nix b/modules/common/default.nix
new file mode 100644
index 0000000..650c07a
--- /dev/null
+++ b/modules/common/default.nix
@@ -0,0 +1,62 @@
+{ lib, config, pkgs, machineInfos, modulesPath, ... }:
+with lib;
+{
+ imports = [
+ ./filesystem.nix
+ ./boot.nix
+ ./linux.nix
+ ./nix.nix
+ ./network.nix
+ ./hardware.nix
+ ./users.nix
+ (modulesPath + "/installer/scan/not-detected.nix")
+ ];
+
+ options.machineType = mkOption {
+ type = types.enum [ "workstation" "server" ];
+ default = "workstation";
+ example = "server";
+ description = ''
+ What is the type of this machine.
+ '';
+ };
+
+ options.isProfessional = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Whether or not this machine is used for professionnal purposes.
+ '';
+ };
+
+ options.enableDocker = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Whether or not to enable the docker stack.
+ '';
+ };
+
+ config = {
+ machineType = machineInfos.machineType;
+ system.stateVersion = machineInfos.stateVersion;
+ networking.hostName = machineInfos.hostname;
+ virtualisation.docker.enable = config.enableDocker;
+
+ # Only enable fish shell if there is at least one user using it.
+ programs.fish.enable = builtins.any (user: user.shell == pkgs.fish) (builtins.attrValues config.machineUsers);
+
+ # We always want to disable the X server as only workstation use windows manager
+ # and they always use wayland.
+ services.xserver.enable = false;
+
+ assertions = [
+ {
+ assertion = !(config.machineType == "server" && config.isProfessional);
+ message = "Only workstations can be professionnal hardware";
+ }
+ ];
+ };
+}
diff --git a/modules/common/filesystem.nix b/modules/common/filesystem.nix
new file mode 100644
index 0000000..263530c
--- /dev/null
+++ b/modules/common/filesystem.nix
@@ -0,0 +1,67 @@
+{ lib, config, ... }:
+with lib;
+let
+ fsModule = types.submodule {
+ options = {
+
+ mountpoint = mkOption {
+ type = types.str;
+ description = ''
+ The filesystem mountpoint.
+ '';
+ };
+
+ deviceUUID = mkOption {
+ type = types.str;
+ description = ''
+ The volume UUID.
+ '';
+ };
+
+ fsType = mkOption {
+ type = types.str;
+ description = ''
+ The volume filesystem.
+ '';
+ };
+
+ };
+ };
+in
+{
+ options.filesystems = mkOption {
+ type = types.listOf fsModule;
+ default = [ ];
+ example = [
+ {
+ mountpoint = "/";
+ deviceUUID = "XXXXX-YYYYYY-AJDKKSKSJ";
+ fsType = "ext4";
+ }
+ ];
+ description = ''
+ The machine filesystem tree description.
+ '';
+ };
+
+ options.swapDeviceUUID = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ };
+
+ config = {
+ fileSystems = builtins.listToAttrs (map
+ (fs: {
+ name = fs.mountpoint;
+ value = {
+ device = "/dev/disk/by-uuid/${fs.deviceUUID}";
+ fsType = fs.fsType;
+ };
+ })
+ config.filesystems);
+
+ swapDevices = mkIf (config.swapDeviceUUID != null) [
+ { device = "/dev/disk/by-uuid/${config.swapDeviceUUID}"; }
+ ];
+ };
+}
diff --git a/modules/common/hardware.nix b/modules/common/hardware.nix
new file mode 100644
index 0000000..9e6758c
--- /dev/null
+++ b/modules/common/hardware.nix
@@ -0,0 +1,26 @@
+{ lib, config, pkgs, ... }:
+with lib;
+{
+ options.hwAccelerationGPU = mkOption {
+ type = types.nullOr (types.enum [ "nvidia" "intel" ]);
+ default = null;
+ example = "nvidia";
+ description = ''
+ The GPU type.
+ '';
+ };
+
+ config = {
+ hardware.opengl = {
+ enable = config.hwAccelerationGPU != null;
+ extraPackages = with pkgs; [
+ libvdpau-va-gl
+ vaapiVdpau
+ ];
+ };
+
+ services.xserver.videoDrivers = [
+ (mkIf (config.hwAccelerationGPU == "nvidia") "nouveau")
+ ];
+ };
+}
diff --git a/modules/common/linux.nix b/modules/common/linux.nix
new file mode 100644
index 0000000..130cd6f
--- /dev/null
+++ b/modules/common/linux.nix
@@ -0,0 +1,53 @@
+{ lib, config, pkgs, ... }:
+with lib;
+{
+ options.useLatestKernel = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Whether or not to use the latest Linux kernel version.
+ '';
+ };
+
+ options.consoleFont = mkOption {
+ type = types.str;
+ default = "Lat2-Terminus16";
+ description = ''
+ The font to use in the Linux console.
+ '';
+ };
+
+ options.timeZone = mkOption {
+ type = types.str;
+ default = "Europe/Paris";
+ description = ''
+ The system time zone.
+ '';
+ };
+
+ options.locale = mkOption {
+ type = types.str;
+ default = "en_US.utf8";
+ description = ''
+ The system locale.
+ '';
+ };
+
+ options.keymap = mkOption {
+ type = types.str;
+ default = "fr";
+ example = "fr";
+ description = ''
+ The keyboard map used.
+ '';
+ };
+
+ config = {
+ boot.kernelPackages = mkIf config.useLatestKernel pkgs.linuxPackages_latest;
+ time.timeZone = config.timeZone;
+ console.font = config.consoleFont;
+ console.keyMap = config.keymap;
+ i18n.defaultLocale = config.locale;
+ };
+}
diff --git a/modules/common/network.nix b/modules/common/network.nix
new file mode 100644
index 0000000..093a339
--- /dev/null
+++ b/modules/common/network.nix
@@ -0,0 +1,38 @@
+{ lib, config, ... }:
+with lib;
+{
+ options.enableFirewall = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Whether or not to enable firewall.
+ '';
+ };
+
+ options.extraAllowedTCPPorts = mkOption {
+ type = types.listOf types.port;
+ default = [ ];
+ example = [ 53 ];
+ description = ''
+ List of custom TCP ports to open in the firewall.
+ '';
+ };
+
+ options.extraAllowedUDPPorts = mkOption {
+ type = types.listOf types.port;
+ default = [ ];
+ example = [ 53 ];
+ description = ''
+ List of custom UDP ports to open in the firewall.
+ '';
+ };
+
+ config = {
+ networking.networkmanager.enable = true;
+ networking.useDHCP = mkDefault true;
+ networking.firewall.enable = true;
+ networking.firewall.allowedTCPPorts = config.extraAllowedTCPPorts;
+ networking.firewall.allowedUDPPorts = config.extraAllowedUDPPorts;
+ };
+}
diff --git a/modules/common/nix.nix b/modules/common/nix.nix
new file mode 100644
index 0000000..b856f69
--- /dev/null
+++ b/modules/common/nix.nix
@@ -0,0 +1,26 @@
+{ pkgs, lib, config, ... }:
+with lib;
+{
+ options.allowUnfreePackages = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Whether the system can use unfree derivations.
+ '';
+ };
+
+ config = {
+ nix = {
+ settings.sandbox = true;
+
+ package = pkgs.nixVersions.stable;
+
+ extraOptions = ''
+ experimental-features = nix-command flakes
+ '';
+ };
+
+ nixpkgs.config.allowUnfree = config.allowUnfreePackages;
+ };
+}
diff --git a/modules/common/users.nix b/modules/common/users.nix
new file mode 100644
index 0000000..62afaa4
--- /dev/null
+++ b/modules/common/users.nix
@@ -0,0 +1,50 @@
+{ lib, config, ... }:
+with lib;
+let
+ userModule = types.submodule {
+ options = {
+ description = mkOption {
+ type = types.str;
+ };
+
+ groups = mkOption {
+ type = types.listOf types.str;
+ };
+
+ uid = mkOption {
+ type = types.nullOr types.int;
+ };
+
+ shell = mkOption {
+ type = types.package;
+ };
+
+ enableHomeManagerProfile = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ homeManagerConfig = mkOption {
+ default = { };
+ };
+ };
+ };
+in
+{
+ options.machineUsers = mkOption {
+ type = types.attrsOf userModule;
+ };
+
+ config = {
+ users.users = builtins.mapAttrs
+ (name: value: {
+ isNormalUser = true;
+ home = "/home/${name}";
+ description = value.description;
+ extraGroups = value.groups;
+ shell = value.shell;
+ uid = mkIf (value.uid != null) value.uid;
+ })
+ config.machineUsers;
+ };
+}
diff --git a/modules/server/default.nix b/modules/server/default.nix
new file mode 100644
index 0000000..f1a624c
--- /dev/null
+++ b/modules/server/default.nix
@@ -0,0 +1,3 @@
+{ lib, config, ... }:
+with lib;
+{ }
diff --git a/modules/workstation/bluetooth.nix b/modules/workstation/bluetooth.nix
new file mode 100644
index 0000000..6dd6f04
--- /dev/null
+++ b/modules/workstation/bluetooth.nix
@@ -0,0 +1,19 @@
+{ lib, config, ... }:
+with lib;
+{
+ options.enableBluetooth = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Enable the bluetooth stack
+ '';
+ };
+
+ config = mkIf config.enableBluetooth {
+ hardware.bluetooth = {
+ enable = true;
+ };
+ services.blueman.enable = true;
+ };
+}
diff --git a/modules/workstation/default.nix b/modules/workstation/default.nix
new file mode 100644
index 0000000..256f062
--- /dev/null
+++ b/modules/workstation/default.nix
@@ -0,0 +1,50 @@
+{ lib, config, pkgs, machineInfos, sopsHmModule, ... }:
+with lib;
+{
+
+ imports = [
+ ./sound.nix
+ ./desktop.nix
+ ./bluetooth.nix
+ ];
+
+ options.enableHomeManager = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Whether to install and use home-manager on this machine.
+ '';
+ };
+
+ config = {
+ enableHomeManager = machineInfos.enableHomeManager;
+
+ home-manager.useGlobalPkgs = mkIf config.enableHomeManager true;
+ home-manager.useUserPackages = mkIf config.enableHomeManager true;
+ home-manager.sharedModules = mkIf config.enableHomeManager [
+ ./home-manager
+ sopsHmModule
+ ];
+ home-manager.users = builtins.mapAttrs
+ (name: value:
+ mkIf value.enableHomeManagerProfile ({
+ home.username = name;
+ home.homeDirectory = "/home/${name}";
+ home.stateVersion = machineInfos.stateVersion;
+ programs.home-manager.enable = true;
+ enableFishShell = value.shell == pkgs.fish;
+ isProfessional = config.isProfessional;
+ } // value.homeManagerConfig)
+ )
+ config.machineUsers;
+
+ programs.dconf.enable = true;
+ security.polkit.enable = true;
+ services.dbus.enable = true;
+
+ fonts.fontconfig.enable = true;
+
+ services.gnome.gnome-keyring.enable = true;
+ };
+}
diff --git a/modules/workstation/desktop.nix b/modules/workstation/desktop.nix
new file mode 100644
index 0000000..388d411
--- /dev/null
+++ b/modules/workstation/desktop.nix
@@ -0,0 +1,17 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ usersHasSway = builtins.any
+ (user:
+ config.home-manager.users.${user}.desktop.enableSwayStack
+ )
+ (builtins.attrNames config.machineUsers);
+in
+{
+ programs.sway.enable = usersHasSway;
+ xdg.portal = mkIf usersHasSway {
+ enable = true;
+ wlr.enable = true;
+ extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
+ };
+}
diff --git a/modules/workstation/home-manager/communication.nix b/modules/workstation/home-manager/communication.nix
new file mode 100644
index 0000000..cda44e3
--- /dev/null
+++ b/modules/workstation/home-manager/communication.nix
@@ -0,0 +1,38 @@
+{ lib, pkgs, config, ... }:
+with lib;
+{
+ options = {
+ communication.discord.enable = mkOption {
+ type = types.bool;
+ default = !config.isProfessional;
+ example = true;
+ };
+
+ communication.slack.enable = mkOption {
+ type = types.bool;
+ default = config.isProfessional;
+ example = true;
+ };
+
+ communication.weechat.enable = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ };
+
+ communication.matrix.enable = mkOption {
+ type = types.bool;
+ default = !config.isProfessional;
+ example = false;
+ };
+ };
+
+ config.home.packages = with pkgs; [
+ (mkIf config.communication.discord.enable (discord.override {
+ nss = nss_latest;
+ }))
+ (mkIf config.communication.slack.enable slack)
+ (mkIf config.communication.weechat.enable weechat)
+ (mkIf config.communication.matrix.enable element)
+ ];
+}
diff --git a/modules/workstation/home-manager/default.nix b/modules/workstation/home-manager/default.nix
new file mode 100644
index 0000000..732e540
--- /dev/null
+++ b/modules/workstation/home-manager/default.nix
@@ -0,0 +1,73 @@
+{ pkgs, lib, ... }:
+with lib;
+let
+ multimediaPackages = with pkgs; [
+ qpwgraph
+ feh
+ gimp
+ vlc
+ ];
+
+ soundPackages = with pkgs; [
+ pulseaudio
+ pavucontrol
+ pamixer
+ ];
+
+ yubikeyTools = with pkgs; [
+ yubikey-personalization
+ yubico-pam
+ yubikey-manager
+ ];
+
+in
+{
+ imports = [
+ ./desktop
+ ./development
+ ./neovim
+ ./fish.nix
+ ./termux.nix
+ ./gpg.nix
+ ./communication.nix
+ ./mail.nix
+ ];
+
+ options.isProfessional = mkOption {
+ type = types.bool;
+ };
+
+ config = {
+
+ fonts.fontconfig.enable = true;
+
+ home.packages = with pkgs; [
+ htop
+ firefox
+ autojump
+ nextcloud-client
+ keepassxc
+ ranger
+ libreoffice
+ tldr
+ zathura
+ lazygit
+ ] ++ multimediaPackages
+ ++ soundPackages
+ ++ yubikeyTools;
+
+ # XDG-Mime configuration
+ xdg.mime.enable = true;
+ xdg.mimeApps.enable = true;
+ xdg.mimeApps.associations.added = {
+ "x-scheme-handler/https" = "firefox.desktop";
+ "x-scheme-handler/http" = "firefox.desktop";
+ };
+ xdg.mimeApps.defaultApplications = {
+ "x-scheme-handler/https" = "firefox.desktop";
+ "x-scheme-handler/http" = "firefox.desktop";
+ "text/html" = "firefox.desktop";
+ };
+ };
+
+}
diff --git a/modules/workstation/home-manager/desktop/alacritty.nix b/modules/workstation/home-manager/desktop/alacritty.nix
new file mode 100644
index 0000000..8a76c64
--- /dev/null
+++ b/modules/workstation/home-manager/desktop/alacritty.nix
@@ -0,0 +1,88 @@
+{ config, lib, ... }:
+with lib;
+let
+ tmuxFix = {
+ env = {
+ TERM = "xterm-256color";
+ };
+ };
+in
+{
+ programs.alacritty = mkIf config.desktop.enableSwayStack {
+ enable = true;
+ settings = {
+ font = {
+ normal = {
+ family = "JetBrainsMono Nerd Font Mono";
+ style = "Regular";
+ };
+ size = 10.0;
+ };
+
+ colors = {
+ primary = {
+ background = "#2e3440";
+ foreground = "#d8dee9";
+ dim_foreground = "#a5abb6";
+ };
+ cursor = {
+ text = "#2e3440";
+ cursor = "#d8dee9";
+ };
+ vi_mode_cursor = {
+ text = "#2e3440";
+ cursor = "#d8dee9";
+ };
+ selection = {
+ text = "CellForeground";
+ background = "#4c566a";
+ };
+ search = {
+ matches = {
+ foreground = "CellBackground";
+ background = "#88c0d0";
+ };
+ };
+
+ footer_bar = {
+ background = "#434c5e";
+ foreground = "#d8dee9";
+ };
+ normal = {
+ black = "#3b4252";
+ red = "#bf616a";
+ green = "#a3be8c";
+ yellow = "#ebcb8b";
+ blue = "#81a1c1";
+ magenta = "#b48ead";
+ cyan = "#88c0d0";
+ white = "#e5e9f0";
+ };
+ bright = {
+ black = "#4c566a";
+ red = "#bf616a";
+ green = "#a3be8c";
+ yellow = "#ebcb8b";
+ blue = "#81a1c1";
+ magenta = "#b48ead";
+ cyan = "#8fbcbb";
+ white = "#eceff4";
+ };
+ dim = {
+ black = "#373e4d";
+ red = "#94545d";
+ green = "#809575";
+ yellow = "#b29e75";
+ blue = "#68809a";
+ magenta = "#8c738c";
+ cyan = "#6d96a5";
+ white = "#aeb3bb";
+ };
+ };
+
+ window = {
+ opacity = 1;
+ };
+ } // tmuxFix;
+ };
+}
diff --git a/modules/workstation/home-manager/desktop/default.nix b/modules/workstation/home-manager/desktop/default.nix
new file mode 100644
index 0000000..d0f2cd5
--- /dev/null
+++ b/modules/workstation/home-manager/desktop/default.nix
@@ -0,0 +1,52 @@
+{ lib, config, pkgs, ... }:
+with lib;
+let
+ desktopPackages = with pkgs; [
+ xwayland
+ grim
+ slurp
+ wl-clipboard
+ clipman
+ wf-recorder
+ (nerdfonts.override { fonts = [ "JetBrainsMono" ]; })
+ qt5ct
+ libsForQt5.qtstyleplugin-kvantum
+ font-awesome
+ nordzy-cursor-theme
+ jetbrains-mono
+ xdg-utils
+ libnotify
+ ];
+in
+{
+ imports = [
+ ./sway.nix
+ ./alacritty.nix
+ ./swaylock.nix
+ ./waybar.nix
+ ./wofi.nix
+ ./mako.nix
+ ];
+
+ options.desktop.enableSwayStack = mkOption {
+ type = types.bool;
+ default = true;
+ };
+
+ config = mkIf config.desktop.enableSwayStack {
+ home.packages = desktopPackages;
+
+ # Theming GTK
+ gtk = {
+ enable = true;
+ theme = {
+ name = "Nordic-darker";
+ package = pkgs.nordic;
+ };
+ cursorTheme = {
+ name = "Nordzy-cursors";
+ package = pkgs.nordzy-cursor-theme;
+ };
+ };
+ };
+}
diff --git a/modules/workstation/home-manager/desktop/mako.nix b/modules/workstation/home-manager/desktop/mako.nix
new file mode 100644
index 0000000..07b57c1
--- /dev/null
+++ b/modules/workstation/home-manager/desktop/mako.nix
@@ -0,0 +1,29 @@
+{ lib, config, ... }:
+with lib;
+{
+ services.mako = mkIf config.desktop.enableSwayStack {
+ enable = true;
+
+ layer = "overlay";
+ anchor = "top-right";
+ font = "JetBrainsMono Nerd Font 10";
+ backgroundColor = "#3b4252";
+ textColor = "#d8dee9";
+ width = 330;
+ height = 100;
+ borderRadius = 2;
+ defaultTimeout = 15000;
+
+ extraConfig = ''
+ [urgency=low]
+ border-color=#434c5e
+
+ [urgency=normal]
+ border-color=#4c566a
+
+ [urgency=high]
+ default-timeout=0
+ border-color=#bf616a
+ '';
+ };
+}
diff --git a/modules/workstation/home-manager/desktop/sway.nix b/modules/workstation/home-manager/desktop/sway.nix
new file mode 100644
index 0000000..8a144f1
--- /dev/null
+++ b/modules/workstation/home-manager/desktop/sway.nix
@@ -0,0 +1,245 @@
+{ config, pkgs, lib, ... }:
+with lib;
+let
+ gnomeSchema = "org.gnome.desktop.interface";
+ monitorModule = types.submodule {
+ options = {
+ name = mkOption {
+ type = types.str;
+ };
+ resolution = mkOption {
+ type = types.str;
+ };
+ position = mkOption {
+ type = types.str;
+ };
+ defaultWorkspace = mkOption {
+ type = types.int;
+ };
+ };
+ };
+in
+{
+ options = {
+ desktop.monitors = mkOption {
+ type = types.listOf monitorModule;
+ };
+ };
+
+ config.wayland.windowManager.sway = mkIf config.desktop.enableSwayStack {
+ enable = true;
+ #systemd.enable = false;
+
+ config = rec {
+ modifier = "Mod4";
+
+ left = "left";
+ right = "right";
+ up = "up";
+ down = "down";
+
+ terminal = "${pkgs.alacritty}/bin/alacritty";
+ menu = "${pkgs.wofi}/bin/wofi --show drun,run";
+
+ fonts = {
+ names = [ "pango:JetBrainsMono Nerd Font Mono" ];
+ size = 11.0;
+ };
+
+ input = {
+ "*" = {
+ xkb_layout = "fr";
+ # xkb_options = "compose:ralt";
+ };
+ };
+
+ seat = {
+ "seat0" = {
+ "xcursor_theme" = "Nordzy-cursors";
+ };
+ };
+ output = builtins.listToAttrs
+ (builtins.map
+ (monitor: {
+ name = monitor.name;
+ value = {
+ resolution = monitor.resolution;
+ position = monitor.position;
+ };
+ })
+ config.desktop.monitors) // {
+ "*".bg = "/home/dala/Perso/wallpapers/tanuki.jpg fill";
+ };
+ workspaceOutputAssign = map
+ (monitor: {
+ output = monitor.name;
+ workspace = builtins.toString monitor.defaultWorkspace;
+ })
+ config.desktop.monitors;
+ startup = [
+ {
+ command = ''
+ ${pkgs.swayidle}/bin/swayidle -w \
+ timeout 1200 '${pkgs.swaylock}/bin/swaylock -f' \
+ timeout 1800 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \
+ before-sleep '${pkgs.swaylock}/bin/swaylock -f'
+ '';
+ }
+ { command = "${pkgs.nextcloud-client}/bin/nextcloud --background"; }
+ { command = "${pkgs.keepassxc}/bin/keepassxc"; }
+ {
+ command = ''
+ ${pkgs.wl-clipboard}/bin/wl-paste -t text --watch ${pkgs.clipman}/bin/clipman store --no-persist
+ '';
+ }
+ {
+ command = "${pkgs.glib}/bin/gsettings set ${gnomeSchema} gtk-theme 'Nordic'";
+ always = true;
+ }
+ {
+ command = "${pkgs.glib}/bin/gsettings set ${gnomeSchema} cursor-theme 'Nordzy-cursors'";
+ always = true;
+ }
+ {
+ command = "${pkgs.glib}/bin/gsettings set ${gnomeSchema} font-name 'JetBrainsMono Nerd Font Mono'";
+ always = true;
+ }
+ ];
+
+ modes = {
+ resize = {
+ "Left" = "resize shrink width 10px";
+ "Down" = "resize grow height 10px";
+ "Up" = "resize shrink height 10px";
+ "Right" = "resize grow width 10px";
+
+ "Return" = "mode default";
+ "Escape" = "mode default";
+ };
+ };
+
+ gaps = {
+ inner = 5;
+ smartGaps = true;
+ };
+
+ floating = {
+ modifier = "${modifier} normal";
+ };
+
+ bars = [{
+ command = "${pkgs.waybar}/bin/waybar";
+ }];
+
+ keybindings = {
+ "${modifier}+Return" = "exec ${terminal}";
+ "${modifier}+Shift+q" = "kill";
+ "${modifier}+d" = "exec ${menu}";
+ "${modifier}+Shift+r" = "reload";
+ "${modifier}+Shift+e" = "exec swaymsg exit";
+ "${modifier}+Shift+l" = "exec swaylock -f";
+
+ "${modifier}+Left" = "focus left";
+ "${modifier}+Down" = "focus down";
+ "${modifier}+Up" = "focus up";
+ "${modifier}+Right" = "focus right";
+
+ "${modifier}+Shift+Left" = "move left";
+ "${modifier}+Shift+Down" = "move down";
+ "${modifier}+Shift+Up" = "move up";
+ "${modifier}+Shift+Right" = "move right";
+
+ "${modifier}+1" = "workspace 1";
+ "${modifier}+2" = "workspace 2";
+ "${modifier}+3" = "workspace 3";
+ "${modifier}+4" = "workspace 4";
+ "${modifier}+5" = "workspace 5";
+ "${modifier}+6" = "workspace 6";
+ "${modifier}+7" = "workspace 7";
+ "${modifier}+8" = "workspace 8";
+ "${modifier}+9" = "workspace 9";
+ "${modifier}+0" = "workspace 10";
+
+ "${modifier}+ampersand" = "workspace 1";
+ "${modifier}+eacute" = "workspace 2";
+ "${modifier}+quotedbl" = "workspace 3";
+ "${modifier}+apostrophe" = "workspace 4";
+ "${modifier}+parenleft" = "workspace 5";
+ "${modifier}+minus" = "workspace 6";
+ "${modifier}+egrave" = "workspace 7";
+ "${modifier}+underscore" = "workspace 8";
+ "${modifier}+ccedilla" = "workspace 9";
+ "${modifier}+agrave" = "workspace 10";
+
+ "${modifier}+Shift+1" = "move container to workspace 1";
+ "${modifier}+Shift+2" = "move container to workspace 2";
+ "${modifier}+Shift+3" = "move container to workspace 3";
+ "${modifier}+Shift+4" = "move container to workspace 4";
+ "${modifier}+Shift+5" = "move container to workspace 5";
+ "${modifier}+Shift+6" = "move container to workspace 6";
+ "${modifier}+Shift+7" = "move container to workspace 7";
+ "${modifier}+Shift+8" = "move container to workspace 8";
+ "${modifier}+Shift+9" = "move container to workspace 9";
+ "${modifier}+Shift+0" = "move container to workspace 10";
+
+ "${modifier}+Shift+ampersand" = "move container to workspace 1";
+ "${modifier}+Shift+eacute" = "move container to workspace 2";
+ "${modifier}+Shift+quotedbl" = "move container to workspace 3";
+ "${modifier}+Shift+apostrophe" = "move container to workspace 4";
+ "${modifier}+Shift+parenleft" = "move container to workspace 5";
+ "${modifier}+Shift+minus" = "move container to workspace 6";
+ "${modifier}+Shift+egrave" = "move container to workspace 7";
+ "${modifier}+Shift+underscore" = "move container to workspace 8";
+ "${modifier}+Shift+ccedilla" = "move container to workspace 9";
+ "${modifier}+Shift+agrave" = "move container to workspace 10";
+
+ "${modifier}+h" = "splith";
+ "${modifier}+v" = "splitv";
+
+ "${modifier}+s" = "layout stacking";
+ "${modifier}+w" = "layout tabbed";
+ "${modifier}+e" = "layout toggle split";
+
+ "${modifier}+f" = "fullscreen";
+ "${modifier}+Shift+space" = "floating toggle";
+ "${modifier}+space" = "focus mode_toggle";
+ "${modifier}+a" = "focus parent";
+
+ "${modifier}+Shift+parenright" = "move scratchpad";
+
+ "${modifier}+parenright" = "scratchpad show";
+
+ "${modifier}+r" = "mode resize";
+
+ "XF86AudioRaiseVolume" = "exec --no-startup-id pactl set-sink-volume 0 +5%"; #increase sound volume
+ "XF86AudioLowerVolume" = "exec --no-startup-id pactl set-sink-volume 0 -5%"; #decrease sound volume
+ "XF86AudioMute" = "exec --no-startup-id pactl set-sink-mute 0 toggle"; # mute sound
+
+ "XF86MonBrightnessUp" = "exec --no-startup-id light -A 10";
+ "XF86MonBrightnessDown" = "exec --no-startup-id light -U 10";
+
+ "Control+XF86AudioMute" = "exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle";
+
+ "Print" = "exec grim -g \"$(${pkgs.slurp}/bin/slurp)\" -t png - | wl-copy --type image/png";
+ };
+ };
+
+ extraConfig = ''
+ default_border pixel
+ for_window [class=".*"] inhibit_idle fullscreen
+ for_window [app_id=".*"] inhibit_idle fullscreen
+ '';
+
+ extraSessionCommands = ''
+ export WLR_NO_HARDWARE_CURSORS=1
+ export XDG_CURRENT_DESKTOP=sway
+ export _JAVA_AWT_WM_NONREPARENTING=1
+ export NIXOS_OZONE_WL=1
+ export QT_QPA_PLATFORM=wayland
+ export QT_QPA_PLATFORMTHEME=qt5ct
+ export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
+ export MOZ_ENABLE_WAYLAND=1
+ export SDL_VIDEODRIVER=wayland
+ '';
+ };
+}
diff --git a/modules/workstation/home-manager/desktop/swaylock.nix b/modules/workstation/home-manager/desktop/swaylock.nix
new file mode 100644
index 0000000..c94cc75
--- /dev/null
+++ b/modules/workstation/home-manager/desktop/swaylock.nix
@@ -0,0 +1,52 @@
+{ lib, config, ... }:
+with lib;
+{
+ programs.swaylock = mkIf config.desktop.enableSwayStack {
+ enable = true;
+
+ settings = {
+ scaling = "fill";
+ font = "JetBrainsMono";
+ font-size = 20;
+ show-keyboard-layout = true;
+ disable-caps-lock-text = true;
+ indicator-caps-lock = true;
+ ignore-empty-password = true;
+ show-failed-attempts = true;
+ line-uses-inside = true;
+
+ indicator-radius = 70;
+ indicator-thickness = 15;
+
+ color = "#00000000";
+ inside-color = "#2e3440a0";
+ inside-ver-color = "#4c566aa0";
+ inside-wrong-color = "#bf616aa0";
+ inside-clear-color = "#434c5ea0";
+ inside-caps-lock-color = "#d08770a0";
+
+ text-color = "#d8dee9d0";
+ text-clear-color = "#d8dee9d0";
+ text-ver-color = "#d8dee9d0";
+ text-wrong-color = "#d8dee9d0";
+ layout-bg-color = "#00000000";
+ layout-text-color = "#d8dee9d0";
+
+ line-color = "#2e3440e0";
+ line-clear-color = "#2e3440e0";
+ line-caps-lock-color = "#2e3440e0";
+ line-ver-color = "#2e3440e0";
+ line-wrong-color = "#2e3440e0";
+ separator-color = "#2e3440e0";
+
+ ring-color = "#5e81acf0";
+ ring-clear-color = "#5e81aca0";
+ ring-caps-lock-color = "#bf616af0";
+ ring-ver-color = "#81a1c1f0";
+ ring-wrong-color = "#d08770f0";
+
+ bs-hl-color = "#d08770a0";
+ key-hl-color = "#81a1c1a0";
+ };
+ };
+}
diff --git a/modules/workstation/home-manager/desktop/waybar.nix b/modules/workstation/home-manager/desktop/waybar.nix
new file mode 100644
index 0000000..e725ba7
--- /dev/null
+++ b/modules/workstation/home-manager/desktop/waybar.nix
@@ -0,0 +1,275 @@
+{ config, lib, ... }:
+with lib;
+{
+ programs.waybar = mkIf config.desktop.enableSwayStack {
+ enable = true;
+ #systemd.enable = false;
+
+ settings = [{
+ layer = "top";
+ position = "top";
+ height = 30;
+
+ modules-left = [
+ "sway/workspaces"
+ "sway/mode"
+ ];
+
+ modules-center = [
+ "sway/window"
+ ];
+
+ modules-right = [
+ "memory"
+ "cpu"
+ "pulseaudio"
+ "network"
+ "battery"
+ "tray"
+ "sway/language"
+ "clock"
+ ];
+
+ "sway/workspaces" = {
+ "disable-scroll" = true;
+ "all-outputs" = false;
+ "format" = "{icon}";
+ "format-icons" = {
+ "1:term" = "";
+ "2:web" = "";
+ "3:email" = "";
+ "4:im" = "";
+ "5:dev" = "";
+ "6:music" = "";
+ "7:graph" = "";
+ "8:any" = "";
+ "9:any" = "";
+ "10:aux" = "";
+ };
+ };
+
+ "tray" = {
+ "icon-size" = 18;
+ "spacing" = 12;
+ };
+
+ "memory" = {
+ "format" = "{percentage:3}% ";
+ "states" = {
+ "warning" = 70;
+ "critical" = 90;
+ };
+ };
+
+ "cpu" = {
+ "format" = "{usage:3}% ";
+ "states" = {
+ "warning" = 70;
+ "critical" = 90;
+ };
+ };
+
+ "pulseaudio" = {
+ "format" = "{volume:3}% {icon}";
+ "format-bluetooth" = "{icon}";
+ "format-muted" = "<\big>";
+ "format-icons" = {
+ "headphone" = "";
+ "hands-free" = "";
+ "headset" = "";
+ "phone" = "";
+ "portable" = "";
+ "car" = "";
+ "default" = [ "" ];
+ };
+
+ "on-click" = "pavucontrol";
+ "on-scroll-up" = "pamixer -ui 2 && pamixer --get-volume > $SWAYSOCK.wob";
+ "on-scroll-down" = "pamixer -ud 2 && pamixer --get-volume > $SWAYSOCK.wob";
+ };
+
+ "network" = {
+ "format-wifi" = "{essid} ";
+ "format-ethernet" = "";
+ "format-disconnected" = "";
+ "format-linked" = "ﯳ";
+ "format-alt" = "{ifname}: {ipaddr}/{cidr}";
+ "tooltip-format-ethernet" = " {bandwidthDownBits} {bandwidthUpBits}";
+ "tooltip-format-wifi" = "{bandwidthDownBits} {bandwidthUpBits}";
+ };
+
+ "battery" = {
+ "states" = {
+ "5pct" = 5;
+ "10pct" = 10;
+ "20pct" = 20;
+ "30pct" = 30;
+ "40pct" = 40;
+ "50pct" = 50;
+ "60pct" = 60;
+ "70pct" = 70;
+ "80pct" = 80;
+ "90pct" = 90;
+ "full" = 100;
+ };
+
+ "format" = "{capacity:3}% {icon}";
+ "format-icons" = {
+ "5pct" = "";
+ "10pct" = "";
+ "20pct" = "";
+ "30pct" = "";
+ "40pct" = "";
+ "50pct" = "";
+ "60pct" = "";
+ "70pct" = "";
+ "80pct" = "";
+ "90pct" = "";
+ "full" = "";
+ };
+ "on-click" = "notify-send -u low -t 3000 'Battery Status' \"$(acpi)\"";
+ };
+
+ "clock" = {
+ "format-alt" = "{:%A, %B %d}";
+ "tooltip-format" = "{:%Y %B}\n{calendar}";
+ };
+ }];
+
+ style = ''
+ @keyframes blink-warning {
+ to {
+ background-color: #bf616a;
+ }
+ }
+
+ @keyframes blink-critical {
+ to {
+ color: #2e3440;
+ background-color: #bf616a;
+ }
+ }
+
+ * {
+ border: none;
+ border-radius: 0;
+ font-family: JetBrainsMono, JetBrainsMono Nerd Font Mono, monospace;
+ font-size: 14px;
+ min-height: 0;
+ box-shadow: none;
+ text-shadow: none;
+ }
+
+ window#waybar {
+ background-color: #3b4252;
+ color: #e5e9f0;
+ opacity: 0.9;
+ }
+
+ #window {
+ font-family: JetBrainsMono, JetBrainsMono Nerd Font Mono, sans-serif;
+ }
+
+ #workspaces {
+ background-color: #4c566a;
+ }
+
+ #workspaces button {
+ padding: 3px 9px 0px 9px;
+ background: transparent;
+ color: #e5e9f0;
+ border-bottom: 3px solid transparent;
+ font-weight: 900;
+ }
+
+ #workspaces button.focused {
+ background-color: #434c5e;
+ color: #eceff4;
+ border-bottom: 3px solid #ebcb8b;
+ }
+
+ #workspaces button:hover {
+ background-color: #5e81ac;
+ }
+
+ #mode {
+ padding: 0px 9px;
+ background-color: #a3be8c;
+ color: #3b4252;
+ font-family: JetBrains Mono, sans-serif;
+ font-size: 14px;
+ font-weight: bold;
+ }
+
+ #clock, #language, #pulseaudio, #tray, #memory, #cpu, #battery, #network {
+ padding: 0px 8px;
+ color: #d8dee9;
+ font-size: 14px;
+ }
+
+ #clock {
+ background-color: #4c566a;
+ font-weight: bold;
+ }
+
+ #language {
+ color: #d8dee9;
+ font-weight: bold;
+ }
+
+ #pulseaudio {
+ }
+
+ #pulseaudio.muted {
+ color: #d08770;
+ }
+
+ #tray {
+ margin-left: 10px;
+ }
+
+ #cpu {
+ padding-left: 0px;
+ font-size: 14px;
+ }
+
+ #cpu.warning {
+ color: #ebcb8b;
+ }
+
+ #cpu.critical {
+ color: #d08770;
+ }
+
+ #memory {
+ padding-left: 0px;
+ font-size: 14px;
+ }
+
+ #memory.warning {
+ color: #ebcb8b;
+ }
+
+ #memory.critical {
+ color: #d08770;
+ }
+
+ #battery {
+ font-size: 14px;
+ animation-timing-function: ease-in-out;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+ }
+
+ #battery.20pct.discharging {
+ animation-name: blink-warning;
+ animation-duration: 3s;
+ }
+
+ #battery.10pct.discharging {
+ animation-name: blink-critical;
+ animation-duration: 2s;
+ }
+ '';
+ };
+}
diff --git a/modules/workstation/home-manager/desktop/wofi.nix b/modules/workstation/home-manager/desktop/wofi.nix
new file mode 100644
index 0000000..8574ecc
--- /dev/null
+++ b/modules/workstation/home-manager/desktop/wofi.nix
@@ -0,0 +1,74 @@
+{ pkgs, config, lib, ... }:
+with lib;
+{
+ programs.wofi = mkIf config.desktop.enableSwayStack {
+ enable = true;
+
+ settings = {
+ allow_images = true;
+ allow_markup = true;
+ insensitive = true;
+ hide_scroll = true;
+ no_actions = false;
+ term = "${pkgs.alacritty}/bin/alacritty";
+ width = "35%";
+ lines = 8;
+ always_parse_args = true;
+ };
+
+ style = ''
+ #window {
+ background-color: transparent;
+ border-radius: 15px;
+ font-family: sans-serif;
+ animation: fadeIn;
+ animation-duration: 0.2s;
+ }
+
+ @keyframes fadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+ }
+
+ #outer-box {
+ margin: 15px;
+ border-radius: 15px;
+ background-color: #3b4252;
+ box-shadow: 0px 0px 5px 0 #0F0F0F;
+ }
+
+ #inner-box {
+ color: #d8dee9;
+ padding: 10px;
+ padding-top: 5px;
+ }
+
+ #input {
+ color: #e5e9f0;
+ border: 2px solid #5e81ac;
+ background-color: #4c566a;
+ padding: 6px;
+ margin: 15px;
+ margin-bottom: 0px;
+ font-size: 16px;
+ border-radius: 5px;
+ }
+
+ #entry {
+ border-radius: 5px;
+ padding: 7px;
+ margin: 0px 5px 0px 5px;
+ }
+
+ #text {
+ font-size: 16px;
+ padding: 7px;
+ color: #d8dee9;
+ }
+
+ #img {
+ padding: 4px;
+ }
+ '';
+ };
+}
diff --git a/modules/workstation/home-manager/development/default.nix b/modules/workstation/home-manager/development/default.nix
new file mode 100644
index 0000000..d9a9903
--- /dev/null
+++ b/modules/workstation/home-manager/development/default.nix
@@ -0,0 +1,35 @@
+{ config, lib, pkgs, ... }:
+with lib;
+{
+ imports = [
+ ./embedded.nix
+ ];
+
+ options.development.enableGit = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Enable git and its configuration.
+ '';
+ };
+
+ config.programs.git = mkIf config.development.enableGit {
+ enable = true;
+ package = pkgs.gitAndTools.gitFull;
+ userName = "Victor Mignot";
+ userEmail = "dala@dalaran.fr";
+ signing = mkIf config.enableGPGKeyring {
+ key = "BEAFED3D";
+ signByDefault = true;
+ };
+ extraConfig = {
+ init = {
+ defaultBranch = "main";
+ };
+ core = {
+ editor = "${pkgs.neovim}/bin/nvim";
+ };
+ };
+ };
+}
diff --git a/modules/workstation/home-manager/development/embedded.nix b/modules/workstation/home-manager/development/embedded.nix
new file mode 100644
index 0000000..569b657
--- /dev/null
+++ b/modules/workstation/home-manager/development/embedded.nix
@@ -0,0 +1,22 @@
+{ lib, config, pkgs, ... }:
+with lib;
+{
+ options.development.embedded.enableTools = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Enable embedded tools.
+ '';
+ };
+
+ options.development.embedded.toolsList = mkOption {
+ type = types.listOf types.package;
+ default = with pkgs; [
+ qemu
+ minicom
+ ];
+ };
+
+ config.home.packages = lib.mkIf config.development.embedded.enableTools config.development.embedded.toolsList;
+}
diff --git a/modules/workstation/home-manager/fish.nix b/modules/workstation/home-manager/fish.nix
new file mode 100644
index 0000000..85e0952
--- /dev/null
+++ b/modules/workstation/home-manager/fish.nix
@@ -0,0 +1,31 @@
+{ lib, pkgs, config, ... }:
+with lib;
+{
+ options.enableFishShell = mkOption {
+ type = types.bool;
+ };
+
+ config.programs.fish = mkIf config.enableFishShell {
+ enable = true;
+
+ plugins = [
+ {
+ name = "bobthefish";
+ src = pkgs.fetchFromGitHub {
+ owner = "oh-my-fish";
+ repo = "theme-bobthefish";
+ rev = "c2c47dc964a257131b3df2a127c2631b4760f3ec";
+ sha256 = "sha256-LB4g+EA3C7OxTuHfcxfgl8IVBe5NufFc+5z9VcS0Bt0=";
+ fetchSubmodules = true;
+ };
+ }
+ ];
+
+ shellInit = ''
+ set -g theme_color_scheme nord
+ if [ -z $DISPLAY ] && [ "$(tty)" = /dev/tty1 ]
+ exec ${pkgs.sway}/bin/sway
+ end
+ '';
+ };
+}
diff --git a/modules/workstation/home-manager/gpg.nix b/modules/workstation/home-manager/gpg.nix
new file mode 100644
index 0000000..b1d0926
--- /dev/null
+++ b/modules/workstation/home-manager/gpg.nix
@@ -0,0 +1,24 @@
+{ config, lib, ... }:
+with lib;
+{
+ options.enableGPGKeyring = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Add GPG keyring and GPG Agent configuration.
+ '';
+ };
+
+ config = mkIf config.enableGPGKeyring {
+ programs.gpg.enable = true;
+
+ services.gpg-agent = {
+ enable = true;
+ enableScDaemon = true;
+ enableSshSupport = true;
+ sshKeys = [ "40DE2FEE4D3C5E2C" ];
+ pinentryFlavor = "curses";
+ };
+ };
+}
diff --git a/modules/workstation/home-manager/mail.nix b/modules/workstation/home-manager/mail.nix
new file mode 100644
index 0000000..415aeb2
--- /dev/null
+++ b/modules/workstation/home-manager/mail.nix
@@ -0,0 +1,125 @@
+{ lib, pkgs, config, ... }:
+with lib;
+let
+ mailAccountModule = types.submodule {
+ isPrimary = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ mailAddress = mkOption {
+ type = types.str;
+ };
+
+ mailPasswdEval = mkOption {
+ type = types.str;
+ };
+
+ imapHost = mkOption {
+ type = types.str;
+ };
+
+ smtpHost = mkOption {
+ type = types.str;
+ };
+ };
+
+ defaultExtraMailboxes = [
+ "Archive"
+ "Receipts"
+ "Junk"
+ "Drafts"
+ "Sent"
+ "Trash"
+ ];
+
+ signature = {
+ text = ''
+ Victor Mignot
+ '';
+ showSignature = "append";
+ };
+
+ hasNoAddress = config.communication.mailAccounts == null;
+in
+{
+ options.communication.mailAccounts = mkOption {
+ type = types.nullOr (types.attrsOf mailAccountModule);
+ default = null;
+ };
+
+ config = mkIf (!hasNoAddress) {
+
+ accounts.email.accounts = builtins.mapAttrs
+ (name: value: {
+ primary = value.isPrimary;
+ address = value.mailAddress;
+ userName = value.mailAddress;
+ realName = "Victor Mignot";
+ imap.host = value.imapHost;
+ smtpHost = value.smtpHost;
+ passwordCommand = value.mailPasswdEval;
+ inherit signature;
+
+ mbsync = {
+ enable = true;
+ create = "both";
+ expunge = "both";
+ patterns = [ "*" ];
+ subFolders = "Verbatim";
+ };
+
+ msmtp.enable = true;
+
+ neomutt = {
+ enable = true;
+ mailboxName = "${name}/Inbox";
+ extraMailboxes = map
+ (mb: {
+ mailbox = mb;
+ name = "${name}/${mb}";
+ })
+ defaultExtraMailboxes;
+ };
+ })
+ config.communication.mailAccounts;
+
+ services.mbsync.enable = true;
+ programs.mbsync.enable = true;
+
+ accounts.email.maildirBasePath = "Mail";
+ programs.neomutt = {
+ enable = true;
+ sidebar.enable = true;
+ checkStatsInterval = 30;
+ sort = "reverse-date";
+ extraConfig = ''
+ set edit_headers = yes
+ set use_from = yes
+ set send_charset = "utf-8"
+
+ color body brightwhite default ^[[:space:]].*
+ color body yellow default ^(diff).*
+ color body brightwhite default ^(\s).*
+ color body cyan default ^(Signed-off-by).*
+ color body cyan default ^(Docker-DCO-1.1-Signed-off-by).*
+ color body brightwhite default ^(Cc)
+ color body yellow default "^diff \-.*"
+ color body brightwhite default "^index [a-f0-9].*"
+ color body brightblue default "^---$"
+ color body white default "^\-\-\- .*"
+ color body white default "^[\+]{3} .*"
+ color body green default "^[\+][^\+]+.*"
+ color body red default "^\-[^\-]+.*"
+ color body brightblue default "^@@ .*"
+ color body green default "LGTM"
+ color body brightmagenta default "-- Commit Summary --"
+ color body brightmagenta default "-- File Changes --"
+ color body brightmagenta default "-- Patch Links --"
+ color body green default "^Merged #.*"
+ color body red default "^Closed #.*"
+ color body brightblue default "^Reply to this email.*"
+ '';
+ };
+ };
+}
diff --git a/modules/workstation/home-manager/neovim/default.nix b/modules/workstation/home-manager/neovim/default.nix
new file mode 100644
index 0000000..18a1448
--- /dev/null
+++ b/modules/workstation/home-manager/neovim/default.nix
@@ -0,0 +1,165 @@
+{ lib, config, pkgs, ... }:
+with lib;
+{
+ options.desktop.enableNeovim = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Whether to use Neovim and its config.
+ '';
+ };
+
+ config.home.sessionVariables."EDITOR" = mkIf config.desktop.enableNeovim "${pkgs.neovim}/bin/nvim";
+
+ config.programs.neovim = mkIf config.desktop.enableNeovim {
+ enable = true;
+
+ viAlias = true;
+ vimAlias = true;
+ vimdiffAlias = true;
+
+ extraConfig = ''
+ luafile ${./luaconfig/settings.lua}
+ luafile ${./luaconfig/keybindings.lua}
+ luafile ${./luaconfig/lspconfig.lua}
+ '';
+
+ extraPackages = with pkgs; [
+ nixfmt
+ rnix-lsp
+ nil
+ ripgrep
+ entr
+ ];
+
+ plugins = with pkgs.vimPlugins; [
+
+ # Theming
+ {
+ plugin = onenord-nvim;
+ type = "lua";
+ config = ''
+ require('onenord').setup()
+ '';
+ }
+ {
+ plugin = lualine-nvim;
+ type = "lua";
+ config = ''
+ require('lualine').setup()
+ '';
+ }
+ vim-devicons
+
+ # Utility plugins
+ {
+ plugin = nerdtree;
+ type = "lua";
+ config = ''
+ vim.g.NERDTreeShowHidden = 1
+
+ vim.keymap.set('n', '', ':NERDTreeToggle', { desc = 'Toogle NERDTree pane' })
+ vim.keymap.set('n', '', ':NERDTreeFind', { desc = 'Search file in NERDTree' })
+ vim.keymap.set('n', '', ':NERDTreeFocus', { desc = 'Focus on the NERDTreePane' })
+
+ -- Keep the same NERDTree pane on each window
+ vim.api.nvim_create_autocmd("BufWinEnter", { pattern = "*", command = "if getcmdwintype() == \'\' | silent NERDTreeMirror | endif" })
+ '';
+ }
+ nerdtree-git-plugin
+ {
+ plugin = toggleterm-nvim;
+ type = "lua";
+ config = ''
+ require("toggleterm").setup{}
+
+ vim.keymap.set('n', 'tf', ':ToggleTerm direction=float', { desc = 'Open a new terminal in float buffer' })
+ vim.keymap.set('n', 'tt', ':ToggleTerm direction=tab', { desc = 'Open a new terminal in a new tab' })
+ vim.keymap.set('n', 'tv', ':ToggleTerm direction=vertical', { desc = 'Open in a vertical splitted buffer' })
+ vim.keymap.set('n', 'th', ':ToggleTerm', { desc = 'Open in a horizontal splitted buffer' })
+ '';
+ }
+ {
+ plugin = neogit;
+ type = "lua";
+ config = ''
+ require('neogit').setup {}
+ '';
+ }
+ {
+ plugin = gitsigns-nvim;
+ type = "lua";
+ config = ''
+ require('gitsigns').setup()
+ '';
+ }
+ vim-multiple-cursors
+ vim-sleuth
+ vim-commentary
+ {
+ plugin = telescope-nvim;
+ type = "lua";
+ config = ''
+ local telescope = require('telescope.builtin')
+
+ vim.keymap.set('n', 'ff', telescope.find_files, { desc = 'Search file with Telescope' })
+ vim.keymap.set('n', 'fg', telescope.live_grep, { desc = 'Live grep with Telescope'})
+ vim.keymap.set('n', 'fb', telescope.buffers, { desc = 'Search amongst current buffers (opened files)'})
+ vim.keymap.set('n', 'fh', telescope.help_tags, { desc = 'Search within nvim manual'})
+ vim.keymap.set('n', 'fs', telescope.lsp_workspace_symbols, { desc = 'Search symbol' })
+ '';
+ }
+ plenary-nvim
+ telescope-fzy-native-nvim
+
+ # Language support plugins
+ vim-nix
+ vim-nixhash
+ {
+ plugin = rust-vim;
+ type = "lua";
+ config = ''
+ vim.g.rustfmt_autosave = 1
+ '';
+ }
+ vim-markdown
+ markdown-preview-nvim
+
+ {
+ plugin = vimtex;
+ type = "viml";
+ config = ''
+ let g:vimtex_view_method = 'zathura'
+ let g:vimtex_compiler_method = 'tectonic'
+
+ let g:vimtex_compiler_tectonic = {
+ \'out_dir' : ' ',
+ \'hooks' : [],
+ \'options' : [
+ \ '--keep-logs',
+ \ '--synctex',
+ \ '-Zshell-escape',
+ \ '-Zshell-escape-cwd=$PWD'
+ \],
+ \}
+
+ '';
+ }
+
+ # Autocompletion and LSP server
+ nvim-lspconfig
+ nvim-cmp
+ cmp-path
+ cmp-cmdline
+ cmp-buffer
+ cmp-nvim-lsp
+ vim-vsnip
+ ];
+ };
+
+ config.xdg.configFile.nvim = mkIf config.desktop.enableNeovim {
+ source = ./luaconfig;
+ recursive = true;
+ };
+}
diff --git a/modules/workstation/home-manager/neovim/luaconfig/keybindings.lua b/modules/workstation/home-manager/neovim/luaconfig/keybindings.lua
new file mode 100644
index 0000000..4e7a878
--- /dev/null
+++ b/modules/workstation/home-manager/neovim/luaconfig/keybindings.lua
@@ -0,0 +1,11 @@
+-- Navigate around panes
+vim.keymap.set('n', '', 'h', { desc = 'Navigate to left pane' })
+vim.keymap.set('n', '', 'l', { desc = 'Navigate to right pane' })
+vim.keymap.set('n', '', 'k', { desc = 'Navigate to upper pane' })
+vim.keymap.set('n', '', 'j', { desc = 'Toogle lower pane' })
+
+-- Move panes position
+vim.keymap.set('n', '', 'H', { desc = 'Navigate to left pane' })
+vim.keymap.set('n', '', 'L', { desc = 'Navigate to right pane' })
+vim.keymap.set('n', '', 'K', { desc = 'Navigate to upper pane' })
+vim.keymap.set('n', '', 'J', { desc = 'Toogle lower pane' })
diff --git a/modules/workstation/home-manager/neovim/luaconfig/lspconfig.lua b/modules/workstation/home-manager/neovim/luaconfig/lspconfig.lua
new file mode 100644
index 0000000..816475d
--- /dev/null
+++ b/modules/workstation/home-manager/neovim/luaconfig/lspconfig.lua
@@ -0,0 +1,94 @@
+-- Nvim LSP Config
+
+local map_opts = { noremap=true, silent=true }
+
+vim.keymap.set('n', 'e', vim.diagnostic.open_float, map_opts)
+vim.keymap.set('n', 'p', vim.diagnostic.goto_prev, map_opts)
+vim.keymap.set('n', 'n', vim.diagnostic.goto_next, map_opts)
+vim.keymap.set('n', 'l', vim.diagnostic.setloclist, map_opts)
+
+
+-- Enable keybinds on LSP server attach
+local on_attach = function(client, bufnr)
+ -- Enable completion triggered by
+ vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
+
+ -- Mappings
+ local bufopts = { noremap=true, silent=true, buffer=bufnr }
+ vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts)
+ vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts)
+ vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts)
+ vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, bufopts)
+ vim.keymap.set('n', '', vim.lsp.buf.signature_help, bufopts)
+ vim.keymap.set('n', 'wa', vim.lsp.buf.add_workspace_folder, bufopts)
+ vim.keymap.set('n', 'wr', vim.lsp.buf.remove_workspace_folder, bufopts)
+ vim.keymap.set('n', 'wl', function()
+ print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
+ end, bufopts)
+ vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, bufopts)
+ vim.keymap.set('n', 'rn', vim.lsp.buf.rename, bufopts)
+ vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, bufopts)
+ vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts)
+ vim.keymap.set('n', 'f', function() vim.lsp.buf.format { async = true } end, bufopts)
+end
+
+-- Set-up autocompletion
+
+local cmp = require('cmp')
+vim.opt.completeopt = {'menu', 'menuone', 'noselect'}
+
+cmp.setup({
+ snippet = {
+ -- Necessary snippet engine
+ expand = function (args)
+ vim.fn["vsnip#anonymous"](args.body)
+ end,
+ },
+
+ window = {
+ -- completion = cmp.config.window.bordered(),
+ -- documentation = cmp.config.window.bordered,
+ },
+
+ mapping = cmp.mapping.preset.insert({
+ [''] = cmp.mapping.scroll_docs(4),
+ [''] = cmp.mapping.scroll_docs(-4),
+ [''] = cmp.mapping.complete(),
+ [''] = cmp.mapping.abort(),
+ [''] = cmp.mapping.confirm({select = true}),
+ }),
+
+ sources = cmp.config.sources({
+ { name = 'nvim_lsp' },
+ { name = 'vsnip' },
+ }, { { name = 'buffer' } }),
+})
+
+
+-- Language servers setup
+local capabilities = require('cmp_nvim_lsp').default_capabilities()
+
+require('lspconfig')['rust_analyzer'].setup {
+ on_attach = on_attach,
+ capabilities = capabilities,
+}
+
+require('lspconfig')['rnix'].setup {
+ on_attach = on_attach,
+ capabilities = capabilities
+}
+
+require('lspconfig')["nil_ls"].setup {
+ on_attach = on_attach,
+ capabilities = capabilities
+}
+
+require('lspconfig')['ltex'].setup {
+ on_attach = on_attach,
+ capabilities = capabilities
+}
+
+require('lspconfig')['texlab'].setup {
+ on_attach = on_attach,
+ capabilities = capabilities
+}
diff --git a/modules/workstation/home-manager/neovim/luaconfig/settings.lua b/modules/workstation/home-manager/neovim/luaconfig/settings.lua
new file mode 100644
index 0000000..1b1887a
--- /dev/null
+++ b/modules/workstation/home-manager/neovim/luaconfig/settings.lua
@@ -0,0 +1,17 @@
+-- Set line numbers
+vim.opt.number = true
+
+-- Replace tab with whitespaces
+vim.opt.expandtab = true
+
+-- Set tabs as 4 whitespaces
+vim.opt.tabstop = 4
+
+-- Set indentation adaptability
+vim.opt.autoindent = true
+
+-- Set default level of identation
+vim.opt.shiftwidth = 4
+
+-- Use the system clipboard
+vim.opt.clipboard = 'unnamedplus'
diff --git a/modules/workstation/home-manager/termux.nix b/modules/workstation/home-manager/termux.nix
new file mode 100644
index 0000000..10aaf84
--- /dev/null
+++ b/modules/workstation/home-manager/termux.nix
@@ -0,0 +1,46 @@
+{ lib, config, pkgs, ... }:
+with lib;
+let
+ tmuxExtraConfig = ''
+ set -ag terminal-overrides ",xterm-256color:RGB"
+ '';
+in
+{
+ options.enableTermux = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Enable termux and the associated config.
+ '';
+ };
+
+ config.programs.tmux = mkIf config.enableTermux {
+ enable = true;
+
+ # Make windows count start to 1
+ baseIndex = 1;
+
+ # Use 24h clock
+ clock24 = true;
+
+ shell = if config.enableFishShell then "${pkgs.fish}/bin/fish" else "${pkgs.bash}/bin/bash";
+
+ keyMode = "vi";
+
+ tmuxp.enable = true;
+
+ terminal = "tmux-256color";
+
+ plugins = with pkgs.tmuxPlugins; [
+ {
+ plugin = nord;
+ extraConfig = ''
+ set -g @plugin "arcticicestudio/nord-tmux"
+ '';
+ }
+ ];
+
+ extraConfig = tmuxExtraConfig;
+ };
+}
diff --git a/modules/workstation/sound.nix b/modules/workstation/sound.nix
new file mode 100644
index 0000000..5f90ecc
--- /dev/null
+++ b/modules/workstation/sound.nix
@@ -0,0 +1,11 @@
+{ ... }:
+{
+ services.pipewire = {
+ enable = true;
+ alsa.enable = true;
+ alsa.support32Bit = true;
+ pulse.enable = true;
+ };
+
+ programs.noisetorch.enable = true;
+}