From e1a65b47a6f5ceb39b00e62d9148d236f1cfdd28 Mon Sep 17 00:00:00 2001
From: Swarsel
Date: Wed, 17 Jul 2024 04:34:14 +0200
Subject: [PATCH] chore: clean up repository
- consolidate Wiki.org and SwarselSystems.org
- remove obsoleted profiles
---
SwarselSystems.org | 9730 +++++++++--------
Wiki.org | 536 -
index.html | 11356 +++++++++++---------
profiles/onett/hardware-configuration.nix | 33 -
profiles/onett/home.nix | 132 -
profiles/onett/nixos.nix | 108 -
profiles/stand/home.nix | 94 -
profiles/stand/nixos.nix | 98 -
profiles/surface/home.nix | 177 -
profiles/twoson/home.nix | 127 -
profiles/twoson/nixos.nix | 102 -
11 files changed, 11143 insertions(+), 11350 deletions(-)
delete mode 100644 Wiki.org
delete mode 100644 profiles/onett/hardware-configuration.nix
delete mode 100644 profiles/onett/home.nix
delete mode 100644 profiles/onett/nixos.nix
delete mode 100644 profiles/stand/home.nix
delete mode 100644 profiles/stand/nixos.nix
delete mode 100644 profiles/surface/home.nix
delete mode 100644 profiles/twoson/home.nix
delete mode 100644 profiles/twoson/nixos.nix
diff --git a/SwarselSystems.org b/SwarselSystems.org
index b846434..4c9efff 100644
--- a/SwarselSystems.org
+++ b/SwarselSystems.org
@@ -974,541 +974,986 @@ No matter what you do, check the initial /etc/nixos/configuration.nix for notabl
:PROPERTIES:
:CUSTOM_ID: h:58dc6384-0d19-4f71-9043-4014bd033ba2
:END:
-**** Threed (Surface Pro 3)
+**** Sandbox (Lenovo Y510P)
:PROPERTIES:
-:CUSTOM_ID: h:7b1a8f91-ef43-433c-ba4c-c5baf50e1de4
+:CUSTOM_ID: h:60cf171f-2ec9-418f-8f67-85d159efe9d0
:END:
-New setup for the SP3, this time using NixOS - another machine will take over the HM-only config for compatibility in the future.
+My old laptop, replaced by a new one, since most basic functions have stopped to work lately. However, it is still good as a dummy server for testing things out before having them go live.
***** NixOS
:PROPERTIES:
-:CUSTOM_ID: h:980f1aca-28b3-4ed7-ae7f-6d8cdc28dea1
+:CUSTOM_ID: h:23b0f629-343c-42fa-bf9b-70bea341c0d2
:END:
-#+begin_src nix :noweb yes :tangle profiles/threed/nixos.nix
-
- { config, lib, pkgs, inputs, ... }:
+#+begin_src nix :noweb yes :tangle profiles/sandbox/nixos.nix
- {
- <>
+ { config, pkgs, modulesPath, unstable, sops, ... }: let
+ matrixDomain = "swatrix.swarsel.win";
+ in {
- services = {
- getty.autologinUser = "swarsel";
- greetd.settings.initial_session.user="swarsel";
- };
+ imports = [
+ ./hardware-configuration.nix
+ # we import here a service that is not available yet on normal nixpkgs
+ # this module is hence not in the modules list, we add it ourselves
+ (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix")
+ ];
- hardware.bluetooth.enable = true;
+ boot.loader.grub = {
+ enable = true;
+ device = "/dev/sda";
+ useOSProber = true;
+ };
- # Bootloader
- boot = {
- loader.systemd-boot.enable = lib.mkForce false;
- lanzaboote = {
- enable = true;
- pkiBundle = "/etc/secureboot";
- };
- loader.efi.canTouchEfiVariables = true;
- # use bootspec instead of lzbt for secure boot. This is not a generally needed setting
- bootspec.enable = true;
- # kernelPackages = pkgs.linuxPackages_latest;
- };
+ users.users.swarsel = {
+ isNormalUser = true;
+ description = "Leon S";
+ extraGroups = [ "networkmanager" "wheel" "lp"];
+ packages = with pkgs; [];
+ };
- networking = {
- hostName = "threed";
- enableIPv6 = false;
- firewall.enable = false;
- };
+ # actual config starts here
- stylix.image = ../../wallpaper/surfacewp.png;
- <>
+ fileSystems."/mnt/Eternor" = {
+ device = "//192.168.1.3/Eternor";
+ fsType = "cifs";
+ options = let
+ # this line prevents hanging on network split
+ automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s";
+ in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=1000,gid=100"];
+ };
- users.users.swarsel = {
- isNormalUser = true;
- description = "Leon S";
- extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" ];
- packages = with pkgs; [];
- };
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ lego
+ nginx
+ calibre
+ openvpn
+ jq
+ iptables
+ busybox
+ wireguard-tools
+ matrix-synapse
+ lottieconverter
+ ffmpeg
+ pciutils
+ alsa-utils
+ mpv
+ zfs
+ ];
- environment.systemPackages = with pkgs; [
- ];
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
- system.stateVersion = "23.05";
+ nix.settings.experimental-features = ["nix-command" "flakes"];
- }
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ listenAddresses = [{
+ port = 22;
+ addr = "0.0.0.0";
+ }];
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../secrets/keys/authorized_keys
+ ];
-#+end_src
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
-***** Home Manager
-:PROPERTIES:
-:CUSTOM_ID: h:449c20d8-338a-483c-a6f0-9a164a6071d6
-:END:
-#+begin_src nix :noweb yes :tangle profiles/threed/home.nix
+ environment.shellAliases = {
+ nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
- { config, pkgs, lib, fetchFromGitHub, ... }:
+ boot.supportedFilesystems = [ "zfs" ];
+ boot.zfs.forceImportRoot = false;
+ networking.hostId = "8a8ad84a";
- {
+ networking.hostName = "sandbox"; # Define your hostname.
+ networking.enableIPv6 = true;
+ networking.firewall.enable = false;
- <>
+ documentation = {
+ enable = false;
+ };
- home = {
- username = "swarsel";
- homeDirectory = "/home/swarsel";
- stateVersion = "23.05"; # Please read the comment before changing.
- keyboard.layout = "us";
- packages = with pkgs; [
- ];
- };
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/root/.dotfiles/secrets/sandbox/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.dnstokenfull = {owner="acme";};
+ sops.templates."certs.secret".content = ''
+ CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
+ '';
- sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
+ security.acme = {
+ acceptTerms = true;
+ preliminarySelfsigned = false;
+ defaults.email = "mrswarsel@gmail.com";
+ defaults.dnsProvider = "cloudflare";
+ defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
+ };
- programs.waybar.settings.mainBar = {
- cpu.format = "{icon0} {icon1} {icon2} {icon3}";
- temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp3_input";
- };
- <>
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ virtualHosts = {
- wayland.windowManager.sway= {
- config = rec {
- input = {
- "*" = {
- xkb_layout = "us";
- xkb_options = "grp:win_space_toggle";
- xkb_variant = "altgr-intl";
- };
- "type:touchpad" = {
- dwt = "enabled";
- tap = "enabled";
- natural_scroll = "enabled";
- middle_emulation = "enabled";
+ "stash.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "https://192.168.1.5";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ # "/push/" = {
+ # proxyPass = "http://192.168.2.5:7867";
+ # };
+ "/.well-known/carddav" = {
+ return = "301 $scheme://$host/remote.php/dav";
+ };
+ "/.well-known/caldav" = {
+ return = "301 $scheme://$host/remote.php/dav";
+ };
+ };
};
- };
- output = {
- eDP-1 = {
- mode = "2160x1440@59.955Hz";
- scale = "1";
- bg = "~/.dotfiles/wallpaper/surfacewp.png fill";
+ "swatrix.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "~ ^(/_matrix|/_synapse/client)" = {
+ proxyPass = "http://127.0.0.1:8008";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
};
- };
- keybindings = let
- modifier = config.wayland.windowManager.sway.config.modifier;
- in {
- "${modifier}+F2" = "exec brightnessctl set +5%";
- "${modifier}+F1"= "exec brightnessctl set 5%-";
- "${modifier}+n" = "exec sway output eDP-1 transform normal, splith";
- "${modifier}+Ctrl+p" = "exec wl-mirror eDP-1";
- "${modifier}+t" = "exec sway output eDP-1 transform 90, splitv";
- "${modifier}+XF86AudioLowerVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
- "${modifier}+XF86AudioRaiseVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
- "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\"";
- };
- startup = [
- <>
- ];
+ "sound.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:4040";
+ proxyWebsockets = true;
+ extraConfig = ''
+ proxy_redirect http:// https://;
+ proxy_read_timeout 600s;
+ proxy_send_timeout 600s;
+ proxy_buffering off;
+ proxy_request_buffering off;
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- keycodebindings = {
- "124" = "exec systemctl suspend";
- };
- };
-
- extraConfig = "
- exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05 map_to_output eDP-1
- exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05_Stylus map_to_output eDP-1
- ";
- };
- }
-#+end_src
-
-**** Fourside (Lenovo Thinkpad P14s Gen2)
-:PROPERTIES:
-:CUSTOM_ID: h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9
-:END:
-
-My new main machine.
-
-***** NixOS
-:PROPERTIES:
-:CUSTOM_ID: h:ab6fefc4-aabd-456c-8a21-5fcb20c02869
-:END:
-
-Mostly just sets some opened ports for several games, enables virtualbox (which I do not want everywhere because of resource considerations) and enables thinkfan, which allows for better fan control on Lenovo Thinkpad machines.
-
-#+begin_src nix :noweb yes :tangle profiles/fourside/nixos.nix
+ "scan.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:28981";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- { config, lib, pkgs, inputs, ... }:
+ "screen.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:8096";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- {
+ "scroll.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:8080";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- # <>
- imports =
- [
- ./hardware-configuration.nix
- ];
- services = {
- getty.autologinUser = "swarsel";
- greetd.settings.initial_session.user="swarsel";
- };
+ };
+ };
- boot = {
- loader.systemd-boot.enable = true;
- loader.efi.canTouchEfiVariables = true;
- # kernelPackages = pkgs.linuxPackages_latest;
- };
- sops.age.sshKeyPaths = [ "${config.users.users.swarsel.home}/.ssh/sops" ];
+ sops.secrets.kavita = { owner = "kavita";};
- networking = {
- hostName = "fourside"; # Define your hostname.
- nftables.enable = true;
- enableIPv6 = false;
- firewall.checkReversePath = false;
- firewall = {
+ services.kavita = {
enable = true;
- allowedUDPPorts = [ 4380 27036 14242 34197 51820 ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard
- allowedTCPPorts = [ ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard
- allowedTCPPortRanges = [
- {from = 27015; to = 27030;} # barotrauma
- {from = 27036; to = 27037;} # barotrauma
- ];
- allowedUDPPortRanges = [
- {from = 27000; to = 27031;} # barotrauma
- {from = 58962; to = 58964;} # barotrauma
- ];
+ user = "kavita";
+ port = 8080;
+ tokenKeyFile = config.sops.secrets.kavita.path;
};
- };
- virtualisation.virtualbox = {
- host = {
- enable = true;
- enableExtensionPack = true;
- };
- # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch
- guest = {
- enable = false;
- };
+ users.users.jellyfin = {
+ extraGroups = [ "video" "render" ];
};
- stylix.image = ../../wallpaper/lenovowp.png;
- <>
+ # nixpkgs.config.packageOverrides = pkgs: {
+ # vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
+ # };
- hardware = {
- graphics = {
- enable = true;
- enable32Bit = true;
- extraPackages = with pkgs; [
- vulkan-loader
- vulkan-validation-layers
- vulkan-extension-layer
- ];
- };
- bluetooth.enable = true;
- trackpoint = {
- enable = true;
- device = "TPPS/2 Elan TrackPoint";
- };
- };
+ hardware.graphics = {
+ enable = true;
+ extraPackages = with pkgs; [
+ intel-media-driver # LIBVA_DRIVER_NAME=iHD
+ vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
+ vaapiVdpau
+ libvdpau-va-gl
+ ];
+ };
- programs.steam = {
- enable = true;
- extraCompatPackages = [
- pkgs.proton-ge-bin
- ];
- };
+ services.jellyfin = {
+ enable = true;
+ user = "jellyfin";
+ # openFirewall = true; # this works only for the default ports
+ };
- # Configure keymap in X11 (only used for login)
+ users.groups.vpn = {};
- services.thinkfan = {
- enable = false;
- };
- services.power-profiles-daemon.enable = true;
- services.fprintd.enable = true;
+ users.users.vpn = {
+ isNormalUser = true;
+ group = "vpn";
+ home = "/home/vpn";
+ };
- users.users.swarsel = {
- isNormalUser = true;
- description = "Leon S";
- hashedPasswordFile = config.sops.secrets.swarseluser.path;
- extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ];
- packages = with pkgs; [];
- };
+ boot.kernelModules = [ "tun" ];
- environment.systemPackages = with pkgs; [
- # gog games installing
- heroic
- # minecraft
- temurin-bin-17
- (prismlauncher.override {
- glfw = pkgs.glfw-wayland-minecraft;
- })
- ];
+ services.radarr = {
+ enable = true;
+ };
- system.stateVersion = "23.05";
+ services.readarr = {
+ enable = true;
+ };
+ services.sonarr = {
+ enable = true;
+ };
+ services.lidarr = {
+ enable = true;
+ };
+ services.prowlarr = {
+ enable = true;
+ };
+ networking.firewall.extraCommands = ''
+ sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP
+ '';
+ networking.iproute2 = {
+ enable = true;
+ rttablesExtraConfig = ''
+ 200 vpn
+ '';
+ };
+ boot.kernel.sysctl = {
+ "net.ipv4.conf.all.rp_filter" = 2;
+ "net.ipv4.conf.default.rp_filter" = 2;
+ "net.ipv4.conf.enp7s0.rp_filter" = 2;
+ };
+ environment.etc = {
+ "openvpn/iptables.sh" =
+ { source = ../../scripts/server1/iptables.sh;
+ mode = "0755";
+ };
+ "openvpn/update-resolv-conf" =
+ { source = ../../scripts/server1/update-resolv-conf;
+ mode = "0755";
+ };
+ "openvpn/routing.sh" =
+ { source = ../../scripts/server1/routing.sh;
+ mode = "0755";
+ };
+ "openvpn/ca.rsa.2048.crt" =
+ { source = ../../secrets/certs/ca.rsa.2048.crt;
+ mode = "0644";
+ };
+ "openvpn/crl.rsa.2048.pem" =
+ { source = ../../secrets/certs/crl.rsa.2048.pem;
+ mode = "0644";
+ };
+ };
- }
+ sops.secrets.vpnuser = {};
+ sops.secrets.rpcuser = {owner="vpn";};
+ sops.secrets.vpnpass = {};
+ sops.secrets.rpcpass = {owner="vpn";};
+ sops.secrets.vpnprot = {};
+ sops.secrets.vpnloc = {};
+ # sops.secrets.crlpem = {};
+ # sops.secrets.capem = {};
+ sops.templates."transmission-rpc".owner = "vpn";
+ sops.templates."transmission-rpc".content = builtins.toJSON {
+ rpc-username = config.sops.placeholder.rpcuser;
+ rpc-password = config.sops.placeholder.rpcpass;
+ };
-#+end_src
-
-***** Home Manager
-:PROPERTIES:
-:CUSTOM_ID: h:85f7110c-2f25-4506-b64a-fce29f29d0d0
-:END:
-
-This is basically just adjusted to the core count, path to the =hwmon= (this was very bothersome on this machine due to changing address), as well as making use of the top-row function keys.
-
-#+begin_src nix :noweb yes :tangle profiles/fourside/home.nix
-
- { config, pkgs, lib, fetchFromGitHub, ... }:
-
- {
-
- <>
- home = {
- username = "swarsel";
- homeDirectory = "/home/swarsel";
- stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing.
- keyboard.layout = "us"; # TEMPLATE
- packages = with pkgs; [
- ];
- };
- sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
-
- # waybar config - TEMPLATE - update for cores and temp
- programs.waybar.settings.mainBar = {
- cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
- # temperature.hwmon-path = "/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon4/temp1_input";
- temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/";
- temperature.input-filename = "temp1_input";
- };
+ sops.templates.pia.content = ''
+ ${config.sops.placeholder.vpnuser}
+ ${config.sops.placeholder.vpnpass}
+ '';
- <>
+ sops.templates.vpn.content = ''
+ client
+ dev tun
+ proto ${config.sops.placeholder.vpnprot}
+ remote ${config.sops.placeholder.vpnloc}
+ resolv-retry infinite
+ nobind
+ persist-key
+ persist-tun
+ cipher aes-128-cbc
+ auth sha1
+ tls-client
+ remote-cert-tls server
- wayland.windowManager.sway= {
- config = rec {
- # update for actual inputs here,
- input = {
- "36125:53060:splitkb.com_Kyria_rev3" = {
- xkb_layout = "us";
- xkb_variant = "altgr-intl";
- };
- "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE
- xkb_layout = "us";
- xkb_options = "grp:win_space_toggle";
- xkb_variant = "altgr-intl";
- };
- "type:touchpad" = {
- dwt = "enabled";
- tap = "enabled";
- natural_scroll = "enabled";
- middle_emulation = "enabled";
- };
+ auth-user-pass ${config.sops.templates.pia.path}
+ compress
+ verb 1
+ reneg-sec 0
- };
+ crl-verify /etc/openvpn/crl.rsa.2048.pem
+ ca /etc/openvpn/ca.rsa.2048.crt
- output = {
- eDP-1 = {
- mode = "1920x1080"; # TEMPLATE
- scale = "1";
- position = "1920,0";
- # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- };
- HDMI-A-1 = {
- mode = "2560x1440";
- scale = "1";
- # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- position = "0,0";
- };
- };
+ disable-occ
+ '';
- workspaceOutputAssign = [
- { output = "eDP-1"; workspace = "1:一";}
- { output = "HDMI-A-1"; workspace = "2:二";}
- ];
+ services.openvpn.servers = {
+ pia = {
+ autoStart = true;
+ updateResolvConf = false;
+ config = "config ${config.sops.templates.vpn.path}";
+ };
+ };
+ services.transmission = {
+ enable = true;
+ credentialsFile = config.sops.templates."transmission-rpc".path;
+ user = "vpn";
+ settings = {
- keybindings = let
- modifier = config.wayland.windowManager.sway.config.modifier;
- in {
- "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkelement.sh\"";
- "XF86MonBrightnessUp" = "exec brightnessctl set +5%";
- "XF86MonBrightnessDown"= "exec brightnessctl set 5%-";
- "XF86Display" = "exec wl-mirror eDP-1";
- # these are left open to use
- # "XF86WLAN" = "exec wl-mirror eDP-1";
- # "XF86Messenger" = "exec wl-mirror eDP-1";
- # "XF86Go" = "exec wl-mirror eDP-1";
- # "XF86Favorites" = "exec wl-mirror eDP-1";
- # "XF86HomePage" = "exec wtype -P Escape -p Escape";
- # "XF86AudioLowerVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink -5%";
- # "XF86AudioRaiseVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink +5% ";
- "XF86AudioMute" = "pactl set-sink-mute alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink toggle";
- };
+ alt-speed-down= 8000;
+ alt-speed-enabled= false;
+ alt-speed-time-begin= 0;
+ alt-speed-time-day= 127;
+ alt-speed-time-enabled= true;
+ alt-speed-time-end= 360;
+ alt-speed-up= 2000;
+ bind-address-ipv4= "0.0.0.0";
+ bind-address-ipv6= "::";
+ blocklist-enabled= false;
+ blocklist-url= "http://www.example.com/blocklist";
+ cache-size-mb= 256;
+ dht-enabled= false;
+ download-dir= "/test";
+ download-limit= 100;
+ download-limit-enabled= 0;
+ download-queue-enabled= true;
+ download-queue-size= 5;
+ encryption= 2;
+ idle-seeding-limit= 30;
+ idle-seeding-limit-enabled= false;
+ incomplete-dir= "/var/lib/transmission-daemon/Downloads";
+ incomplete-dir-enabled= false;
+ lpd-enabled= false;
+ max-peers-global= 200;
+ message-level= 1;
+ peer-congestion-algorithm= "";
+ peer-id-ttl-hours= 6;
+ peer-limit-global= 100;
+ peer-limit-per-torrent= 40;
+ peer-port= 22371;
+ peer-port-random-high= 65535;
+ peer-port-random-low= 49152;
+ peer-port-random-on-start= false;
+ peer-socket-tos= "default";
+ pex-enabled= false;
+ port-forwarding-enabled= false;
+ preallocation= 1;
+ prefetch-enabled= true;
+ queue-stalled-enabled= true;
+ queue-stalled-minutes= 30;
+ ratio-limit= 2;
+ ratio-limit-enabled= false;
+ rename-partial-files= true;
+ rpc-authentication-required= true;
+ rpc-bind-address= "0.0.0.0";
+ rpc-enabled= true;
+ rpc-host-whitelist= "";
+ rpc-host-whitelist-enabled= true;
+ rpc-port= 9091;
+ rpc-url= "/transmission/";
+ rpc-whitelist= "127.0.0.1,192.168.3.2";
+ rpc-whitelist-enabled= true;
+ scrape-paused-torrents-enabled= true;
+ script-torrent-done-enabled= false;
+ seed-queue-enabled= false;
+ seed-queue-size= 10;
+ speed-limit-down= 6000;
+ speed-limit-down-enabled= true;
+ speed-limit-up= 500;
+ speed-limit-up-enabled= true;
+ start-added-torrents= true;
+ trash-original-torrent-files= false;
+ umask= 2;
+ upload-limit= 100;
+ upload-limit-enabled= 0;
+ upload-slots-per-torrent= 14;
+ utp-enabled= false;
+ };
+ };
- startup = [
- <>
- ];
- };
- };
- }
+ # services.nginx = {
+ # enable = true;
+ # virtualHosts = {
-#+end_src
+ # "192.168.1.192" = {
+ # locations = {
+ # "/transmission" = {
+ # proxyPass = "http://127.0.0.1:9091";
+ # extraConfig = ''
+ # proxy_set_header Host $host;
+ # proxy_set_header X-Real-IP $remote_addr;
+ # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ # '';
+ # };
+ # };
+ # };
+ # };
+ # };
-**** Winters (Framwork Laptop 16)
-:PROPERTIES:
-:CUSTOM_ID: h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9
-:END:
-My work machine.
+ # sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
+ # sops.templates."matrix_user_register.sh".content = ''
+ # register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
+ # '';
+ # sops.templates.matrixshared.owner = "matrix-synapse";
+ # sops.templates.matrixshared.content = ''
+ # registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
+ # '';
+ # sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
+ # sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
+ # sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
+ # sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
+ # sops.templates.mautrixtelegram.owner = "matrix-synapse";
+ # sops.templates.mautrixtelegram.content = ''
+ # MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
+ # MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
+ # MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
+ # MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
+ # '';
-***** NixOS
-:PROPERTIES:
-:CUSTOM_ID: h:ab6fefc4-aabd-456c-8a21-5fcb20c02869
-:END:
-Mostly just sets some opened ports for several games, enables virtualbox (which I do not want everywhere because of resource considerations) and enables thinkfan, which allows for better fan control on Lenovo Thinkpad machines.
-#+begin_src nix :noweb yes :tangle profiles/winters/nixos.nix
- { config, lib, pkgs, inputs, ... }:
+ # ----------------
+ # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
+ # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
+ # sops.templates.mautrixwhatsapp.content = ''
+ # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
+ # '';
- {
-
- # <>
- imports =
- [
- ./hardware-configuration.nix
- ];
-
- services = {
- getty.autologinUser = "swarsel";
- greetd.settings.initial_session.user="swarsel";
- };
-
- boot = {
- loader.systemd-boot.enable = true;
- loader.efi.canTouchEfiVariables = true;
- kernelPackages = pkgs.linuxPackages_latest;
- };
+ services.postgresql.enable = true;
+ services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
+ CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
+ CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
+ CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
+ CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
+ CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ '';
- networking = {
- hostName = "winters"; # Define your hostname.
- nftables.enable = true;
- enableIPv6 = true;
- firewall.checkReversePath = "strict";
- firewall = {
- enable = true;
- allowedUDPPorts = [ ];
- allowedTCPPorts = [ ];
- allowedTCPPortRanges = [
+ services.matrix-synapse = {
+ settings.app_service_config_files = [
+ "/var/lib/matrix-synapse/telegram-registration.yaml"
+ "/var/lib/matrix-synapse/whatsapp-registration.yaml"
+ "/var/lib/matrix-synapse/signal-registration.yaml"
+ "/var/lib/matrix-synapse/doublepuppet.yaml"
];
- allowedUDPPortRanges = [
+ enable = false;
+ settings.server_name = matrixDomain;
+ settings.public_baseurl = "https://${matrixDomain}";
+ extraConfigFiles = [
+ config.sops.templates.matrixshared.path
+ ];
+ settings.listeners = [
+ { port = 8008;
+ bind_addresses = [ "0.0.0.0" ];
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [
+ {
+ names = [ "client" "federation" ];
+ compress = true;
+ }
+ ];
+ }
];
};
- };
- virtualisation.virtualbox = {
- host = {
- enable = true;
- enableExtensionPack = true;
+ services.mautrix-telegram = {
+ enable = false;
+ environmentFile = config.sops.templates.mautrixtelegram.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
+ address= "http://localhost:29317";
+ hostname = "0.0.0.0";
+ port = "29317";
+ provisioning.enabled = true;
+ id = "telegram";
+ # ephemeral_events = true; # not needed due to double puppeting
+ public = {
+ enabled = false;
+ };
+ database = "postgresql:///mautrix-telegram?host=/run/postgresql";
+ };
+ bridge = {
+ # login_shared_secret_map = {
+ # matrixDomain = "as_token:doublepuppet";
+ # };
+ relaybot.authless_portals = true;
+ allow_avatar_remove = true;
+ allow_contact_info = true;
+ sync_channel_members = true;
+ startup_sync = true;
+ sync_create_limit = 0;
+ sync_direct_chats = true;
+ telegram_link_preview = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
+ # Animated stickers conversion requires additional packages in the
+ # service's path.
+ # If this isn't a fresh installation, clearing the bridge's uploaded
+ # file cache might be necessary (make a database backup first!):
+ # delete from telegram_file where \
+ # mime_type in ('application/gzip', 'application/octet-stream')
+ animated_sticker = {
+ target = "gif";
+ args = {
+ width = 256;
+ height = 256;
+ fps = 30; # only for webm
+ background = "020202"; # only for gif, transparency not supported
+ };
+ };
+ };
+ };
};
- # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch
- guest = {
+ # systemd.services.mautrix-telegram.path = with pkgs; [
+ # lottieconverter # for animated stickers conversion, unfree package
+ # ffmpeg # if converting animated stickers to webm (very slow!)
+ # ];
+
+ services.mautrix-whatsapp = {
enable = false;
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
+ address= "http://localhost:29318";
+ hostname = "0.0.0.0";
+ port = 29318;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
+ };
+ };
+ bridge = {
+ displayname_template = "{{or .FullName .PushName .JID}} (WA)";
+ history_sync = {
+ backfill = true;
+ max_initial_conversations = -1;
+ message_count = -1;
+ request_full_sync = true;
+ full_sync_config = {
+ days_limit = 900;
+ size_mb_limit = 5000;
+ storage_quota_mb = 5000;
+ };
+ };
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ sync_manual_marked_unread = true;
+ send_presence_on_typing = true;
+ parallel_member_sync = true;
+ url_previews = true;
+ caption_in_message = true;
+ extev_polls = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
+ };
};
};
- stylix.image = ../../wallpaper/lenovowp.png;
- <>
+ services.mautrix-signal = {
+ enable = false;
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
- hardware = {
- graphics = {
- enable = true;
- enable32Bit = true;
- extraPackages = with pkgs; [
- ];
+ address= "http://localhost:29328";
+ hostname = "0.0.0.0";
+ port = 29328;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-signal?host=/run/postgresql";
+ };
+ };
+ bridge = {
+ displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ caption_in_message = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
+ };
};
- bluetooth.enable = true;
};
- programs.steam = {
- enable = true;
- extraCompatPackages = [
- pkgs.proton-ge-bin
- ];
- };
+ # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
+ # messages out after a while.
- services.power-profiles-daemon.enable = true;
+ systemd.timers."restart-bridges" = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnBootSec = "1d";
+ OnUnitActiveSec = "1d";
+ Unit = "restart-bridges.service";
+ };
+ };
- users.users.swarsel = {
- isNormalUser = true;
- description = "Leon S";
- extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ];
- packages = with pkgs; [];
- };
+ systemd.services."restart-bridges" = {
+ script = ''
+ systemctl restart mautrix-whatsapp.service
+ systemctl restart mautrix-signal.service
+ systemctl restart mautrix-telegram.service
+ '';
+ serviceConfig = {
+ Type = "oneshot";
+ User = "root";
+ };
+ };
+
+
+ users.groups.navidrome = {
+ gid = 61593;
+ };
+
+ users.groups.mpd = {};
+
+ users.users.navidrome = {
+ isSystemUser = true;
+ uid = 61593;
+ group = "navidrome";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ users.users.mpd = {
+ isSystemUser = true;
+ group = "mpd";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ sound = {
+ enable = true;
+ };
+
+ hardware.enableAllFirmware = true;
+
+ sops.secrets.mpdpass = { owner = "mpd";};
+
+ services.navidrome = {
+ enable = true;
+ settings = {
+ Address = "0.0.0.0";
+ Port = 4040;
+ MusicFolder = "/mnt/";
+ EnableSharing = true;
+ EnableTranscodingConfig = true;
+ Scanner.GroupAlbumReleases = true;
+ ScanSchedule = "@every 24h";
+ # Insert these values locally as sops-nix does not work for them
+ # LastFM.ApiKey = TEMPLATE;
+ # LastFM.Secret = TEMPLATE;
+ # Spotify.ID = TEMPLATE;
+ # Spotify.Secret = TEMPLATE;
+ UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png";
+ UIWelcomeMessage = "~SwarselSound~";
+ };
+ };
+ services.mpd = {
+ enable = true;
+ musicDirectory = "/mnt/Eternor/Musik";
+ user = "mpd";
+ group = "mpd";
+ network = {
+ port = 3254;
+ listenAddress = "any";
+ };
+ credentials = [
+ {
+ passwordFile = config.sops.secrets.mpdpass.path;
+ permissions = [
+ "read"
+ "add"
+ "control"
+ "admin"
+ ];
+ }
+ ];
+ };
+
+
+ users.groups.spotifyd = {
+ gid = 65136;
+ };
+
+ users.users.spotifyd = {
+ isSystemUser = true;
+ uid = 65136;
+ group = "spotifyd";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ services.spotifyd = {
+ enable = true;
+ settings = {
+ global = {
+ dbus_type = "session";
+ use_mpris = false;
+ device = "default:CARD=PCH";
+ device_name = "SwarselSpot";
+ mixer = "alsa";
+ zeroconf_port = 1025;
+ };
+ };
+ };
+
+ # Network shares
+ # add a user with sudo smbpasswd -a
+ services.samba = {
+ package = pkgs.samba4Full;
+ extraConfig = ''
+ workgroup = WORKGROUP
+ server role = standalone server
+ dns proxy = no
+
+ pam password change = yes
+ map to guest = bad user
+ create mask = 0664
+ force create mode = 0664
+ directory mask = 0775
+ force directory mode = 0775
+ follow symlinks = yes
+ '';
+
+ # ^^ `samba4Full` is compiled with avahi, ldap, AD etc support compared to the default package, `samba`
+ # Required for samba to register mDNS records for auto discovery
+ # See https://github.com/NixOS/nixpkgs/blob/592047fc9e4f7b74a4dc85d1b9f5243dfe4899e3/pkgs/top-level/all-packages.nix#L27268
+ enable = true;
+ # openFirewall = true;
+ shares.test = {
+ browseable = "yes";
+ "read only" = "no";
+ "guest ok" = "no";
+ path = "/test2";
+ writable = "true";
+ comment = "Eternor";
+ "valid users" = "@smbtest2";
+ };
+ };
+
+
+ services.avahi = {
+ publish.enable = true;
+ publish.userServices = true;
+ # ^^ Needed to allow samba to automatically register mDNS records without the need for an `extraServiceFile`
+ nssmdns = true;
+ # ^^ Not one hundred percent sure if this is needed- if it aint broke, don't fix it
+ enable = true;
+ };
+
+ services.samba-wsdd = {
+ # This enables autodiscovery on windows since SMB1 (and thus netbios) support was discontinued
+ enable = true;
+ };
+
+
+
+
+
+
+
+
+
+
+ }
+
+#+end_src
+**** Threed (Surface Pro 3)
+:PROPERTIES:
+:CUSTOM_ID: h:7b1a8f91-ef43-433c-ba4c-c5baf50e1de4
+:END:
+
+New setup for the SP3, this time using NixOS - another machine will take over the HM-only config for compatibility in the future.
+
+***** NixOS
+:PROPERTIES:
+:CUSTOM_ID: h:980f1aca-28b3-4ed7-ae7f-6d8cdc28dea1
+:END:
+
+#+begin_src nix :noweb yes :tangle profiles/threed/nixos.nix
+
+ { config, lib, pkgs, inputs, ... }:
+
+ {
+ <>
+
+ services = {
+ getty.autologinUser = "swarsel";
+ greetd.settings.initial_session.user="swarsel";
+ };
+
+ hardware.bluetooth.enable = true;
+
+ # Bootloader
+ boot = {
+ loader.systemd-boot.enable = lib.mkForce false;
+ lanzaboote = {
+ enable = true;
+ pkiBundle = "/etc/secureboot";
+ };
+ loader.efi.canTouchEfiVariables = true;
+ # use bootspec instead of lzbt for secure boot. This is not a generally needed setting
+ bootspec.enable = true;
+ # kernelPackages = pkgs.linuxPackages_latest;
+ };
+
+ networking = {
+ hostName = "threed";
+ enableIPv6 = false;
+ firewall.enable = false;
+ };
+
+ stylix.image = ../../wallpaper/surfacewp.png;
+ <>
+
+ users.users.swarsel = {
+ isNormalUser = true;
+ description = "Leon S";
+ extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" ];
+ packages = with pkgs; [];
+ };
environment.systemPackages = with pkgs; [
- sbctl
- # gog games installing
- heroic
- # minecraft
- temurin-bin-17
- (prismlauncher.override {
- glfw = pkgs.glfw-wayland-minecraft;
- })
];
system.stateVersion = "23.05";
-
}
#+end_src
-***** TODO Home Manager
+***** Home Manager
:PROPERTIES:
-:CUSTOM_ID: h:85f7110c-2f25-4506-b64a-fce29f29d0d0
+:CUSTOM_ID: h:449c20d8-338a-483c-a6f0-9a164a6071d6
:END:
-
-TODO: Adjust =hwmon= path, I/O modules and XF86 keys once laptop arrives.
-
-#+begin_src nix :noweb yes :tangle profiles/winters/home.nix
+#+begin_src nix :noweb yes :tangle profiles/threed/home.nix
{ config, pkgs, lib, fetchFromGitHub, ... }:
{
<>
+
home = {
username = "swarsel";
homeDirectory = "/home/swarsel";
- stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing.
- keyboard.layout = "us"; # TEMPLATE
+ stateVersion = "23.05"; # Please read the comment before changing.
+ keyboard.layout = "us";
packages = with pkgs; [
];
};
+
sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
- # waybar config - TEMPLATE - update for cores and temp
programs.waybar.settings.mainBar = {
- cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
-
- temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/";
- temperature.input-filename = "temp1_input";
+ cpu.format = "{icon0} {icon1} {icon2} {icon3}";
+ temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp3_input";
};
-
<>
wayland.windowManager.sway= {
config = rec {
- # update for actual inputs here,
input = {
- "36125:53060:splitkb.com_Kyria_rev3" = {
- xkb_layout = "us";
- xkb_variant = "altgr-intl";
- };
- "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE
+ "*" = {
xkb_layout = "us";
xkb_options = "grp:win_space_toggle";
xkb_variant = "altgr-intl";
@@ -1519,471 +1964,509 @@ TODO: Adjust =hwmon= path, I/O modules and XF86 keys once laptop arrives.
natural_scroll = "enabled";
middle_emulation = "enabled";
};
-
};
output = {
eDP-1 = {
- mode = "1920x1080"; # TEMPLATE
+ mode = "2160x1440@59.955Hz";
scale = "1";
- position = "1920,0";
- # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- };
- # external monitor
- HDMI-A-1 = {
- mode = "2560x1440";
- scale = "1";
- # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- position = "0,0";
+ bg = "~/.dotfiles/wallpaper/surfacewp.png fill";
};
};
- workspaceOutputAssign = [
- { output = "eDP-1"; workspace = "1:一";}
- { output = "HDMI-A-1"; workspace = "2:二";}
- ];
-
-
keybindings = let
modifier = config.wayland.windowManager.sway.config.modifier;
in {
-
+ "${modifier}+F2" = "exec brightnessctl set +5%";
+ "${modifier}+F1"= "exec brightnessctl set 5%-";
+ "${modifier}+n" = "exec sway output eDP-1 transform normal, splith";
+ "${modifier}+Ctrl+p" = "exec wl-mirror eDP-1";
+ "${modifier}+t" = "exec sway output eDP-1 transform 90, splitv";
+ "${modifier}+XF86AudioLowerVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
+ "${modifier}+XF86AudioRaiseVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
+ "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\"";
};
startup = [
<>
];
+
+ keycodebindings = {
+ "124" = "exec systemctl suspend";
+ };
};
+
+ extraConfig = "
+ exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05 map_to_output eDP-1
+ exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05_Stylus map_to_output eDP-1
+ ";
};
}
-
#+end_src
-*** Virtual hosts
+**** Fourside (Lenovo Thinkpad P14s Gen2)
:PROPERTIES:
-:CUSTOM_ID: h:4dc59747-9598-4029-aa7d-92bf186d6c06
+:CUSTOM_ID: h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9
:END:
-My server setup is built on Proxmox VE; back when I started, I created all kinds of wild Debian/Ubuntu/etc. KVMs and LXCs on there. However, the root disk has suffered a weird failure where it has become unable to be cloned, but it is still functional for now. I am currently rewriting all machines on there to use NixOS instead; this is a ongoing process.
-
-In the long run, I am thinking about a transition to kubernetes or using just a server running NixOS and using the built-in container functionality. For now however, I like the network management provided by Proxmox, as I am a bit intimidated by doing that from scratch.
+My new main machine.
-**** TEMPLATE
-:PROPERTIES:
-:CUSTOM_ID: h:292c583e-0b67-4456-bdba-a72d4e53ce66
-:END:
***** NixOS
:PROPERTIES:
-:CUSTOM_ID: h:598a2a4c-4d99-46d6-9d4a-dd9e73704f09
+:CUSTOM_ID: h:ab6fefc4-aabd-456c-8a21-5fcb20c02869
:END:
-#+begin_src nix :tangle profiles/server1/TEMPLATE/nixos.nix
+Mostly just sets some opened ports for several games, enables virtualbox (which I do not want everywhere because of resource considerations) and enables thinkfan, which allows for better fan control on Lenovo Thinkpad machines.
- { pkgs, modulesPath, ... }:
+#+begin_src nix :noweb yes :tangle profiles/fourside/nixos.nix
+
+ { config, lib, pkgs, inputs, ... }:
{
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ];
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- ];
+ # <>
+ imports =
+ [
+ ./hardware-configuration.nix
+ ];
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
+ services = {
+ getty.autologinUser = "swarsel";
+ greetd.settings.initial_session.user="swarsel";
};
- nix.settings.experimental-features = ["nix-command" "flakes"];
+ boot = {
+ loader.systemd-boot.enable = true;
+ loader.efi.canTouchEfiVariables = true;
+ # kernelPackages = pkgs.linuxPackages_latest;
+ };
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "TEMPLATE"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
- services.openssh = {
+ sops.age.sshKeyPaths = [ "${config.users.users.swarsel.home}/.ssh/sops" ];
+
+ networking = {
+ hostName = "fourside"; # Define your hostname.
+ nftables.enable = true;
+ enableIPv6 = false;
+ firewall.checkReversePath = false;
+ firewall = {
+ enable = true;
+ allowedUDPPorts = [ 4380 27036 14242 34197 51820 ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard
+ allowedTCPPorts = [ ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard
+ allowedTCPPortRanges = [
+ {from = 27015; to = 27030;} # barotrauma
+ {from = 27036; to = 27037;} # barotrauma
+ ];
+ allowedUDPPortRanges = [
+ {from = 27000; to = 27031;} # barotrauma
+ {from = 58962; to = 58964;} # barotrauma
+ ];
+ };
+ };
+
+ virtualisation.virtualbox = {
+ host = {
enable = true;
- settings.PermitRootLogin = "yes";
+ enableExtensionPack = true;
+ };
+ # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch
+ guest = {
+ enable = false;
+ };
+ };
+
+ stylix.image = ../../wallpaper/lenovowp.png;
+ <>
+
+ hardware = {
+ graphics = {
+ enable = true;
+ enable32Bit = true;
+ extraPackages = with pkgs; [
+ vulkan-loader
+ vulkan-validation-layers
+ vulkan-extension-layer
+ ];
+ };
+ bluetooth.enable = true;
+ trackpoint = {
+ enable = true;
+ device = "TPPS/2 Elan TrackPoint";
+ };
+ };
+
+ programs.steam = {
+ enable = true;
+ extraCompatPackages = [
+ pkgs.proton-ge-bin
+ ];
};
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
+
+ # Configure keymap in X11 (only used for login)
+
+ services.thinkfan = {
+ enable = false;
+ };
+ services.power-profiles-daemon.enable = true;
+ services.fprintd.enable = true;
+
+ users.users.swarsel = {
+ isNormalUser = true;
+ description = "Leon S";
+ hashedPasswordFile = config.sops.secrets.swarseluser.path;
+ extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ];
+ packages = with pkgs; [];
+ };
+
+ environment.systemPackages = with pkgs; [
+ # gog games installing
+ heroic
+ # minecraft
+ temurin-bin-17
+ (prismlauncher.override {
+ glfw = pkgs.glfw-wayland-minecraft;
+ })
];
- # users.users.root.password = "TEMPLATE";
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ system.stateVersion = "23.05";
+
+
}
#+end_src
-**** NGINX
-:PROPERTIES:
-:CUSTOM_ID: h:90340ea4-5ef0-4466-92cf-12d8ece805ba
-:END:
-***** NixOS
+***** Home Manager
:PROPERTIES:
-:CUSTOM_ID: h:519899ad-adcd-435b-8857-71635afbc756
+:CUSTOM_ID: h:85f7110c-2f25-4506-b64a-fce29f29d0d0
:END:
-#+begin_src nix :tangle profiles/server1/nginx/nixos.nix
-
- { config, pkgs, modulesPath, ... }:
- {
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- ];
+This is basically just adjusted to the core count, path to the =hwmon= (this was very bothersome on this machine due to changing address), as well as making use of the top-row function keys.
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- lego
- nginx
- ];
+#+begin_src nix :noweb yes :tangle profiles/fourside/home.nix
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
+ { config, pkgs, lib, fetchFromGitHub, ... }:
- nix.settings.experimental-features = ["nix-command" "flakes"];
+ {
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/nginx/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.dnstokenfull = {owner="acme";};
- sops.templates."certs.secret".content = ''
- CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
- '';
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "nginx"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
+ <>
+ home = {
+ username = "swarsel";
+ homeDirectory = "/home/swarsel";
+ stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing.
+ keyboard.layout = "us"; # TEMPLATE
+ packages = with pkgs; [
+ ];
};
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
- # users.users.root.password = "TEMPLATE";
-
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
- security.acme = {
- acceptTerms = true;
- preliminarySelfsigned = false;
- defaults.email = "mrswarsel@gmail.com";
- defaults.dnsProvider = "cloudflare";
- defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
+ # waybar config - TEMPLATE - update for cores and temp
+ programs.waybar.settings.mainBar = {
+ cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
+ # temperature.hwmon-path = "/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon4/temp1_input";
+ temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/";
+ temperature.input-filename = "temp1_input";
};
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
+ <>
- services.nginx = {
- enable = true;
- recommendedProxySettings = true;
- recommendedTlsSettings = true;
- recommendedOptimisation = true;
- recommendedGzipSettings = true;
- virtualHosts = {
-
- "stash.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "https://192.168.1.5";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- # "/push/" = {
- # proxyPass = "http://192.168.2.5:7867";
- # };
- "/.well-known/carddav" = {
- return = "301 $scheme://$host/remote.php/dav";
- };
- "/.well-known/caldav" = {
- return = "301 $scheme://$host/remote.php/dav";
- };
- };
- };
-
- "matrix2.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "~ ^(/_matrix|/_synapse/client)" = {
- proxyPass = "http://192.168.1.23:8008";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
-
-
- "sound.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://192.168.1.13:4040";
- proxyWebsockets = true;
- extraConfig = ''
- proxy_redirect http:// https://;
- proxy_read_timeout 600s;
- proxy_send_timeout 600s;
- proxy_buffering off;
- proxy_request_buffering off;
- client_max_body_size 0;
- '';
- };
- };
+ wayland.windowManager.sway= {
+ config = rec {
+ # update for actual inputs here,
+ input = {
+ "36125:53060:splitkb.com_Kyria_rev3" = {
+ xkb_layout = "us";
+ xkb_variant = "altgr-intl";
};
-
- "scan.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://192.168.1.24:28981";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
+ "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE
+ xkb_layout = "us";
+ xkb_options = "grp:win_space_toggle";
+ xkb_variant = "altgr-intl";
};
-
- "screen.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://192.168.1.16:8096";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
+ "type:touchpad" = {
+ dwt = "enabled";
+ tap = "enabled";
+ natural_scroll = "enabled";
+ middle_emulation = "enabled";
};
- "matrix.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "~ ^(/_matrix|/_synapse/client)" = {
- proxyPass = "http://192.168.1.20:8008";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ };
- "scroll.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://192.168.1.22:8080";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
+ output = {
+ eDP-1 = {
+ mode = "1920x1080"; # TEMPLATE
+ scale = "1";
+ position = "1920,0";
+ # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
};
-
- "blog.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "https://192.168.1.7";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
+ HDMI-A-1 = {
+ mode = "2560x1440";
+ scale = "1";
+ # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ position = "0,0";
};
-
};
- };
-
+ workspaceOutputAssign = [
+ { output = "eDP-1"; workspace = "1:一";}
+ { output = "HDMI-A-1"; workspace = "2:二";}
+ ];
+ keybindings = let
+ modifier = config.wayland.windowManager.sway.config.modifier;
+ in {
+ "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkelement.sh\"";
+ "XF86MonBrightnessUp" = "exec brightnessctl set +5%";
+ "XF86MonBrightnessDown"= "exec brightnessctl set 5%-";
+ "XF86Display" = "exec wl-mirror eDP-1";
+ # these are left open to use
+ # "XF86WLAN" = "exec wl-mirror eDP-1";
+ # "XF86Messenger" = "exec wl-mirror eDP-1";
+ # "XF86Go" = "exec wl-mirror eDP-1";
+ # "XF86Favorites" = "exec wl-mirror eDP-1";
+ # "XF86HomePage" = "exec wtype -P Escape -p Escape";
+ # "XF86AudioLowerVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink -5%";
+ # "XF86AudioRaiseVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink +5% ";
+ "XF86AudioMute" = "pactl set-sink-mute alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink toggle";
+ };
+ startup = [
+ <>
+ ];
+ };
+ };
}
#+end_src
-**** [Manual steps required] Calibre
+**** Winters (Framwork Laptop 16)
:PROPERTIES:
-:CUSTOM_ID: h:12152533-a000-4e7e-8038-43f8e501cedd
+:CUSTOM_ID: h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9
:END:
-This machine requires manual setup:
-1) (obsolete for now) Set up calibre-web:
- - Create metadata.db with 664 permissions, make sure parent directory is writeable
- - Login @ books.swarsel.win using initial creds:
- - user: admin
- - pw: admin123
- - point to metadata.db file, make sure you can upload
- - Change pw, create normal user
-2) Setup kavita:
- - Login @ scrolls.swarsel.win
- - Create admin user
- - Import Libraries
- - Create normal user
-
-In general, I am not amazed by this setup; Kavita is the reader of choice, calibre-web mostly is there to have a convenient way to fullfill the opinionated folder structure when uploading ebooks (calibre-web does not work on its own since it forces sqlite which does not work nicely with my NFS book store). I hope that in the future Kavita will implement ebook upload, or that calibre-web will ditch the sqlite constraints.
+My work machine.
***** NixOS
:PROPERTIES:
-:CUSTOM_ID: h:0094ccd0-36e4-46cb-a422-6f1aefb786d6
+:CUSTOM_ID: h:ab6fefc4-aabd-456c-8a21-5fcb20c02869
:END:
-#+begin_src nix :tangle profiles/server1/calibre/nixos.nix
+Mostly just sets some opened ports for several games, enables virtualbox (which I do not want everywhere because of resource considerations) and enables thinkfan, which allows for better fan control on Lenovo Thinkpad machines.
- { config, pkgs, modulesPath, ... }:
+#+begin_src nix :noweb yes :tangle profiles/winters/nixos.nix
+
+ { config, lib, pkgs, inputs, ... }:
{
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- ];
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- calibre
- ];
+ # <>
+ imports =
+ [
+ ./hardware-configuration.nix
+ ];
- users.groups.lxc_shares = {
- gid = 10000;
- members = [
- "kavita"
- "calibre-web"
- "root"
- ];
+ services = {
+ getty.autologinUser = "swarsel";
+ greetd.settings.initial_session.user="swarsel";
};
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
+ boot = {
+ loader.systemd-boot.enable = true;
+ loader.efi.canTouchEfiVariables = true;
+ kernelPackages = pkgs.linuxPackages_latest;
};
- nix.settings.experimental-features = ["nix-command" "flakes"];
-
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/calibre/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.kavita = { owner = "kavita";};
- # sops.secrets.smbuser = { };
- # sops.secrets.smbpassword = { };
- # sops.secrets.smbdomain = { };
- # sops.templates."smb.cred".content = ''
- # user=${config.sops.placeholder.smbuser}
- # password=${config.sops.placeholder.smbpassword}
- # domain=${config.sops.placeholder.smbdomain}
- # '';
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "calibre"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
- services.openssh = {
+ networking = {
+ hostName = "winters"; # Define your hostname.
+ nftables.enable = true;
+ enableIPv6 = true;
+ firewall.checkReversePath = "strict";
+ firewall = {
+ enable = true;
+ allowedUDPPorts = [ ];
+ allowedTCPPorts = [ ];
+ allowedTCPPortRanges = [
+ ];
+ allowedUDPPortRanges = [
+ ];
+ };
+ };
+
+ virtualisation.virtualbox = {
+ host = {
enable = true;
- settings.PermitRootLogin = "yes";
+ enableExtensionPack = true;
+ };
+ # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch
+ guest = {
+ enable = false;
+ };
+ };
+
+ stylix.image = ../../wallpaper/lenovowp.png;
+ <>
+
+ hardware = {
+ graphics = {
+ enable = true;
+ enable32Bit = true;
+ extraPackages = with pkgs; [
+ ];
+ };
+ bluetooth.enable = true;
+ };
+
+ programs.steam = {
+ enable = true;
+ extraCompatPackages = [
+ pkgs.proton-ge-bin
+ ];
};
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ services.power-profiles-daemon.enable = true;
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ users.users.swarsel = {
+ isNormalUser = true;
+ description = "Leon S";
+ extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ];
+ packages = with pkgs; [];
};
+ environment.systemPackages = with pkgs; [
+ sbctl
+ # gog games installing
+ heroic
+ # minecraft
+ temurin-bin-17
+ (prismlauncher.override {
+ glfw = pkgs.glfw-wayland-minecraft;
+ })
+ ];
- # services.calibre-server = {
- # enable = true;
- # user = "calibre-server";
- # auth.enable = true;
- # auth.userDb = "/srv/calibre/users.sqlite";
- # libraries = [
- # /media/Books/main
- # /media/Books/diverse
- # /media/Books/language
- # /media/Books/science
- # /media/Books/sport
- # /media/Books/novels
- # ];
- # };
+ system.stateVersion = "23.05";
- # services.calibre-web = {
- # enable = true;
- # user = "calibre-web";
- # group = "calibre-web";
- # listen.port = 8083;
- # listen.ip = "0.0.0.0";
- # options = {
- # enableBookUploading = true;
- # enableKepubify = true;
- # enableBookConversion = true;
- # };
- # };
- services.kavita = {
- enable = true;
- user = "kavita";
- port = 8080;
- tokenKeyFile = config.sops.secrets.kavita.path;
+ }
+
+#+end_src
+
+***** TODO Home Manager
+:PROPERTIES:
+:CUSTOM_ID: h:85f7110c-2f25-4506-b64a-fce29f29d0d0
+:END:
+
+TODO: Adjust =hwmon= path, I/O modules and XF86 keys once laptop arrives.
+
+#+begin_src nix :noweb yes :tangle profiles/winters/home.nix
+
+ { config, pkgs, lib, fetchFromGitHub, ... }:
+
+ {
+
+ <>
+ home = {
+ username = "swarsel";
+ homeDirectory = "/home/swarsel";
+ stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing.
+ keyboard.layout = "us"; # TEMPLATE
+ packages = with pkgs; [
+ ];
+ };
+ sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
+
+ # waybar config - TEMPLATE - update for cores and temp
+ programs.waybar.settings.mainBar = {
+ cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
+
+ temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/";
+ temperature.input-filename = "temp1_input";
};
+ <>
+
+ wayland.windowManager.sway= {
+ config = rec {
+ # update for actual inputs here,
+ input = {
+ "36125:53060:splitkb.com_Kyria_rev3" = {
+ xkb_layout = "us";
+ xkb_variant = "altgr-intl";
+ };
+ "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE
+ xkb_layout = "us";
+ xkb_options = "grp:win_space_toggle";
+ xkb_variant = "altgr-intl";
+ };
+ "type:touchpad" = {
+ dwt = "enabled";
+ tap = "enabled";
+ natural_scroll = "enabled";
+ middle_emulation = "enabled";
+ };
+
+ };
+
+ output = {
+ eDP-1 = {
+ mode = "1920x1080"; # TEMPLATE
+ scale = "1";
+ position = "1920,0";
+ # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ };
+ # external monitor
+ HDMI-A-1 = {
+ mode = "2560x1440";
+ scale = "1";
+ # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ position = "0,0";
+ };
+ };
+
+ workspaceOutputAssign = [
+ { output = "eDP-1"; workspace = "1:一";}
+ { output = "HDMI-A-1"; workspace = "2:二";}
+ ];
+
+
+ keybindings = let
+ modifier = config.wayland.windowManager.sway.config.modifier;
+ in {
+
+ };
+ startup = [
+ <>
+ ];
+ };
+ };
}
#+end_src
-**** Jellyfin
+*** Virtual hosts
:PROPERTIES:
-:CUSTOM_ID: h:4a194546-9a9e-47c4-8d03-8d2428d45d30
+:CUSTOM_ID: h:4dc59747-9598-4029-aa7d-92bf186d6c06
+:END:
+
+My server setup is built on Proxmox VE; back when I started, I created all kinds of wild Debian/Ubuntu/etc. KVMs and LXCs on there. However, the root disk has suffered a weird failure where it has become unable to be cloned, but it is still functional for now. I am currently rewriting all machines on there to use NixOS instead; this is a ongoing process.
+
+In the long run, I am thinking about a transition to kubernetes or using just a server running NixOS and using the built-in container functionality. For now however, I like the network management provided by Proxmox, as I am a bit intimidated by doing that from scratch.
+
+**** TEMPLATE
+:PROPERTIES:
+:CUSTOM_ID: h:292c583e-0b67-4456-bdba-a72d4e53ce66
:END:
***** NixOS
:PROPERTIES:
-:CUSTOM_ID: h:9e94efd9-f63b-46ce-b34c-ec3128de5ed9
+:CUSTOM_ID: h:598a2a4c-4d99-46d6-9d4a-dd9e73704f09
:END:
-#+begin_src nix :tangle profiles/server1/jellyfin/nixos.nix
+#+begin_src nix :tangle profiles/server1/TEMPLATE/nixos.nix
- { config, pkgs, modulesPath, ... }:
+ { pkgs, modulesPath, ... }:
{
imports = [
(modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
];
environment.systemPackages = with pkgs; [
@@ -1992,18 +2475,6 @@ In general, I am not amazed by this setup; Kavita is the reader of choice, calib
ssh-to-age
];
- users.groups.lxc_shares = {
- gid = 10000;
- members = [
- "jellyfin"
- "root"
- ];
- };
-
- users.users.jellyfin = {
- extraGroups = [ "video" "render" ];
- };
-
services.xserver = {
layout = "us";
xkbVariant = "altgr-intl";
@@ -2011,13 +2482,9 @@ In general, I am not amazed by this setup; Kavita is the reader of choice, calib
nix.settings.experimental-features = ["nix-command" "flakes"];
- # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- # sops.defaultSopsFile = "/.dotfiles/secrets/jellyfin/secrets.yaml";
- # sops.validateSopsFiles = false;
-
proxmoxLXC.manageNetwork = true; # manage network myself
proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "jellyfin"; # Define your hostname.
+ networking.hostName = "TEMPLATE"; # Define your hostname.
networking.useDHCP = true;
networking.enableIPv6 = false;
networking.firewall.enable = false;
@@ -2028,1471 +2495,1309 @@ In general, I am not amazed by this setup; Kavita is the reader of choice, calib
users.users.root.openssh.authorizedKeys.keyFiles = [
../../../secrets/keys/authorized_keys
];
+ # users.users.root.password = "TEMPLATE";
system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ }
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
-
- nixpkgs.config.packageOverrides = pkgs: {
- vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
- };
- hardware.graphics = {
- enable = true;
- extraPackages = with pkgs; [
- intel-media-driver # LIBVA_DRIVER_NAME=iHD
- vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
- vaapiVdpau
- libvdpau-va-gl
- ];
- };
+#+end_src
- services.jellyfin = {
- enable = true;
- user = "jellyfin";
- # openFirewall = true; # this works only for the default ports
- };
-
- }
-
-#+end_src
-
-**** [WIP/Incomplete/Untested] Transmission
+**** NGINX
:PROPERTIES:
-:CUSTOM_ID: h:dffc1243-8d6a-4cac-8a5d-3a27d4546235
+:CUSTOM_ID: h:90340ea4-5ef0-4466-92cf-12d8ece805ba
:END:
-
-This stuff just does not work, I seem to be unable to create a working VPN Split Tunneling on NixOS. Maybe this is introduced by the wonky Proxmox-NixOS container interaction, I am not sure. For now, this machine does not work at all and I am stuck with my Debian Container that does this for me ...
-
***** NixOS
:PROPERTIES:
-:CUSTOM_ID: h:2a2ebf94-b262-4e83-ab86-d8b1ebec492d
+:CUSTOM_ID: h:519899ad-adcd-435b-8857-71635afbc756
:END:
-#+begin_src nix :tangle profiles/server1/transmission/nixos.nix
-
- { config, pkgs, modulesPath, ... }:
+#+begin_src nix :tangle profiles/server1/nginx/nixos.nix
- {
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- # ./openvpn.nix #this file holds the vpn login data
- ];
+ { config, pkgs, modulesPath, ... }:
+ {
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
+ ];
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- openvpn
- jq
- iptables
- busybox
- wireguard-tools
- ];
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ lego
+ nginx
+ ];
- users.groups.lxc_shares = {
- gid = 10000;
- members = [
- "vpn"
- "radarr"
- "sonarr"
- "lidarr"
- "readarr"
- "root"
- ];
- };
- users.groups.vpn = {};
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
- users.users.vpn = {
- isNormalUser = true;
- group = "vpn";
- home = "/home/vpn";
- };
+ nix.settings.experimental-features = ["nix-command" "flakes"];
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/.dotfiles/secrets/nginx/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.dnstokenfull = {owner="acme";};
+ sops.templates."certs.secret".content = ''
+ CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
+ '';
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "nginx"; # Define your hostname.
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ networking.firewall.enable = false;
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
+ # users.users.root.password = "TEMPLATE";
- nix.settings.experimental-features = ["nix-command" "flakes"];
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/transmission/secrets.yaml";
- sops.validateSopsFiles = false;
+ security.acme = {
+ acceptTerms = true;
+ preliminarySelfsigned = false;
+ defaults.email = "mrswarsel@gmail.com";
+ defaults.dnsProvider = "cloudflare";
+ defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
+ };
- boot.kernelModules = [ "tun" ];
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "transmission"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
+ environment.shellAliases = {
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
- services.radarr = {
- enable = true;
- };
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ virtualHosts = {
- services.readarr = {
- enable = true;
- };
- services.sonarr = {
- enable = true;
- };
- services.lidarr = {
- enable = true;
- };
- services.prowlarr = {
- enable = true;
- };
+ "stash.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "https://192.168.1.5";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ # "/push/" = {
+ # proxyPass = "http://192.168.2.5:7867";
+ # };
+ "/.well-known/carddav" = {
+ return = "301 $scheme://$host/remote.php/dav";
+ };
+ "/.well-known/caldav" = {
+ return = "301 $scheme://$host/remote.php/dav";
+ };
+ };
+ };
- # networking.interfaces = {
- # lo = {
- # useDHCP = false;
- # ipv4.addresses = [
- # { address = "127.0.0.1"; prefixLength = 8; }
- # ];
- # };
- #
- # eth0 = {
- # useDHCP = true;
- # };
- # };
+ "matrix2.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "~ ^(/_matrix|/_synapse/client)" = {
+ proxyPass = "http://192.168.1.23:8008";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- # networking.firewall.extraCommands = ''
- # sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP
- # '';
- networking.iproute2 = {
- enable = true;
- rttablesExtraConfig = ''
- 200 vpn
- '';
- };
- # boot.kernel.sysctl = {
- # "net.ipv4.conf.all.rp_filter" = 2;
- # "net.ipv4.conf.default.rp_filter" = 2;
- # "net.ipv4.conf.eth0.rp_filter" = 2;
- # };
- environment.etc = {
- "openvpn/iptables.sh" =
- { source = ../../../scripts/server1/iptables.sh;
- mode = "0755";
- };
- "openvpn/update-resolv-conf" =
- { source = ../../../scripts/server1/update-resolv-conf;
- mode = "0755";
- };
- "openvpn/routing.sh" =
- { source = ../../../scripts/server1/routing.sh;
- mode = "0755";
- };
- "openvpn/ca.rsa.2048.crt" =
- { source = ../../../secrets/certs/ca.rsa.2048.crt;
- mode = "0644";
- };
- "openvpn/crl.rsa.2048.pem" =
- { source = ../../../secrets/certs/crl.rsa.2048.pem;
- mode = "0644";
- };
- };
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
- listenAddresses = [{
- port = 22;
- addr = "0.0.0.0";
- }];
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
- # users.users.root.password = "TEMPLATE";
+ "sound.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.13:4040";
+ proxyWebsockets = true;
+ extraConfig = ''
+ proxy_redirect http:// https://;
+ proxy_read_timeout 600s;
+ proxy_send_timeout 600s;
+ proxy_buffering off;
+ proxy_request_buffering off;
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
-
- sops.secrets.vpnuser = {};
- sops.secrets.rpcuser = {owner="vpn";};
- sops.secrets.vpnpass = {};
- sops.secrets.rpcpass = {owner="vpn";};
- sops.secrets.vpnprot = {};
- sops.secrets.vpnloc = {};
- # sops.secrets.crlpem = {};
- # sops.secrets.capem = {};
- sops.templates."transmission-rpc".owner = "vpn";
- sops.templates."transmission-rpc".content = builtins.toJSON {
- rpc-username = config.sops.placeholder.rpcuser;
- rpc-password = config.sops.placeholder.rpcpass;
- };
-
- sops.templates.pia.content = ''
- ${config.sops.placeholder.vpnuser}
- ${config.sops.placeholder.vpnpass}
+ "scan.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.24:28981";
+ extraConfig = ''
+ client_max_body_size 0;
'';
+ };
+ };
+ };
- sops.templates.vpn.content = ''
- client
- dev tun
- proto ${config.sops.placeholder.vpnprot}
- remote ${config.sops.placeholder.vpnloc}
- resolv-retry infinite
- nobind
- persist-key
- persist-tun
- cipher aes-128-cbc
- auth sha1
- tls-client
- remote-cert-tls server
+ "screen.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.16:8096";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- auth-user-pass ${config.sops.templates.pia.path}
- compress
- verb 1
- reneg-sec 0
+ "matrix.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "~ ^(/_matrix|/_synapse/client)" = {
+ proxyPass = "http://192.168.1.20:8008";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- crl-verify /etc/openvpn/crl.rsa.2048.pem
- ca /etc/openvpn/ca.rsa.2048.crt
+ "scroll.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.22:8080";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- disable-occ
- dhcp-option DNS 209.222.18.222
- dhcp-option DNS 209.222.18.218
- dhcp-option DNS 8.8.8.8
- route-noexec
+ "blog.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "https://192.168.1.7";
+ extraConfig = ''
+ client_max_body_size 0;
'';
+ };
+ };
+ };
- # services.pia.enable = true;
- # services.pia.authUserPass.username = "na";
- # services.pia.authUserPass.password = "na";
+ };
+ };
- # systemd.services.openvpn-vpn = {
- # wantedBy = [ "multi-user.target" ];
- # after = [ "network.target" ];
- # description = "OpenVPN connection to pia";
- # serviceConfig = {
- # Type = "forking";
- # RuntimeDirectory="openvpn";
- # PrivateTmp=true;
- # KillMode="mixed";
- # ExecStart = ''@${pkgs.openvpn}/sbin/openvpn openvpn --daemon ovpn-pia --status /run/openvpn/pia.status 10 --cd /etc/openvpn --script-security 2 --config ${config.sops.templates.vpn.path} --writepid /run/openvpn/pia.pid'';
- # PIDFile=''/run/openvpn/pia.pid'';
- # ExecReload=''/run/current-system/sw/bin/kill -HUP $MAINPID'';
- # WorkingDirectory="/etc/openvpn";
- # Restart="on-failure";
- # RestartSec=30;
- # ProtectSystem="yes";
- # DeviceAllow=["/dev/null rw" "/dev/net/tun rw"];
- # };
- # };
- services.openvpn.servers = {
- pia = {
- autoStart = false;
- updateResolvConf = true;
- # up = ''
- # export INTERFACE="tun0"
- # export VPNUSER="vpn"
- # export LOCALIP="192.168.1.191"
- # export NETIF="eth0"
- # export VPNIF="tun0"
- # export GATEWAYIP=$(ifconfig $VPNIF | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}' | egrep -v '255|(127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})' | tail -n1)
- # iptables -F -t nat
- # iptables -F -t mangle
- # iptables -F -t filter
- # iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
- # iptables -t mangle -A OUTPUT ! --dest $LOCALIP -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
- # iptables -t mangle -A OUTPUT --dest $LOCALIP -p udp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
- # iptables -t mangle -A OUTPUT --dest $LOCALIP -p tcp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
- # iptables -t mangle -A OUTPUT ! --src $LOCALIP -j MARK --set-mark 0x1
- # iptables -t mangle -A OUTPUT -j CONNMARK --save-mark
- # iptables -A INPUT -i $INTERFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
- # iptables -A INPUT -i $INTERFACE -j REJECT
- # iptables -A OUTPUT -o lo -m owner --uid-owner $VPNUSER -j ACCEPT
- # iptables -A OUTPUT -o $INTERFACE -m owner --uid-owner $VPNUSER -j ACCEPT
- # iptables -t nat -A POSTROUTING -o $INTERFACE -j MASQUERADE
- # iptables -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
- # iptables -A OUTPUT ! --src $LOCALIP -o $NETIF -j REJECT
- # if [[ `ip rule list | grep -c 0x1` == 0 ]]; then
- # ip rule add from all fwmark 0x1 lookup $VPNUSER
- # fi
- # ip route replace default via $GATEWAYIP table $VPNUSER
- # ip route append default via 127.0.0.1 dev lo table $VPNUSER
- # ip route flush cache
- # '';
- # down = "bash /etc/openvpn/update-resolv-conf";
- # these are outsourced to a local file, I am not sure if it can be done with sops-nix
- # authUserPass = {
- # username = "TODO:secrets";
- # password = "TODO:secrets";
- # };
- config = "config ${config.sops.templates.vpn.path}";
- };
- };
- services.transmission = {
- enable = true;
- credentialsFile = config.sops.templates."transmission-rpc".path;
- user = "vpn";
- group = "lxc_shares";
- settings = {
- alt-speed-down= 8000;
- alt-speed-enabled= false;
- alt-speed-time-begin= 0;
- alt-speed-time-day= 127;
- alt-speed-time-enabled= true;
- alt-speed-time-end= 360;
- alt-speed-up= 2000;
- bind-address-ipv4= "0.0.0.0";
- bind-address-ipv6= "::";
- blocklist-enabled= false;
- blocklist-url= "http://www.example.com/blocklist";
- cache-size-mb= 4;
- dht-enabled= false;
- download-dir= "/media/Eternor/New";
- download-limit= 100;
- download-limit-enabled= 0;
- download-queue-enabled= true;
- download-queue-size= 5;
- encryption= 2;
- idle-seeding-limit= 30;
- idle-seeding-limit-enabled= false;
- incomplete-dir= "/var/lib/transmission-daemon/Downloads";
- incomplete-dir-enabled= false;
- lpd-enabled= false;
- max-peers-global= 200;
- message-level= 1;
- peer-congestion-algorithm= "";
- peer-id-ttl-hours= 6;
- peer-limit-global= 100;
- peer-limit-per-torrent= 40;
- peer-port= 22371;
- peer-port-random-high= 65535;
- peer-port-random-low= 49152;
- peer-port-random-on-start= false;
- peer-socket-tos= "default";
- pex-enabled= false;
- port-forwarding-enabled= false;
- preallocation= 1;
- prefetch-enabled= true;
- queue-stalled-enabled= true;
- queue-stalled-minutes= 30;
- ratio-limit= 2;
- ratio-limit-enabled= false;
- rename-partial-files= true;
- rpc-authentication-required= true;
- rpc-bind-address= "0.0.0.0";
- rpc-enabled= true;
- rpc-host-whitelist= "";
- rpc-host-whitelist-enabled= true;
- rpc-port= 9091;
- rpc-url= "/transmission/";
- rpc-whitelist= "127.0.0.1,192.168.3.2";
- rpc-whitelist-enabled= true;
- scrape-paused-torrents-enabled= true;
- script-torrent-done-enabled= false;
- seed-queue-enabled= false;
- seed-queue-size= 10;
- speed-limit-down= 6000;
- speed-limit-down-enabled= true;
- speed-limit-up= 500;
- speed-limit-up-enabled= true;
- start-added-torrents= true;
- trash-original-torrent-files= false;
- umask= 2;
- upload-limit= 100;
- upload-limit-enabled= 0;
- upload-slots-per-torrent= 14;
- utp-enabled= false;
- };
- };
- # services.nginx = {
- # enable = true;
- # virtualHosts = {
-
- # "192.168.1.192" = {
- # locations = {
- # "/transmission" = {
- # proxyPass = "http://127.0.0.1:9091";
- # extraConfig = ''
- # proxy_set_header Host $host;
- # proxy_set_header X-Real-IP $remote_addr;
- # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- # '';
- # };
- # };
- # };
- # };
- # };
-
-
- }
+ }
#+end_src
-**** [Manual steps needed] Matrix
+**** [Manual steps required] Calibre
:PROPERTIES:
-:CUSTOM_ID: h:1d6221c4-1f48-4f83-b262-5298ed99218e
+:CUSTOM_ID: h:12152533-a000-4e7e-8038-43f8e501cedd
:END:
-1) After the initial setup, run the
- - /run/secrets-generated/matrix_user_register.sh
-command to register a new admin user.
-2) All bridges will fail on first start, copy the registration files using:
- - cp /var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse/
- - chown matrix-synapse:matrix-synapse var/lib/matrix-synapse/telegram-registration.yaml
-Make sure to also do this for doublepuppet.yaml
-3) Restart postgresql.service, matrix-synapse.service, mautrix-whatsapp.service, mautrix-telegram.service
+This machine requires manual setup:
+1) (obsolete for now) Set up calibre-web:
+ - Create metadata.db with 664 permissions, make sure parent directory is writeable
+ - Login @ books.swarsel.win using initial creds:
+ - user: admin
+ - pw: admin123
+ - point to metadata.db file, make sure you can upload
+ - Change pw, create normal user
+2) Setup kavita:
+ - Login @ scrolls.swarsel.win
+ - Create admin user
+ - Import Libraries
+ - Create normal user
+
+In general, I am not amazed by this setup; Kavita is the reader of choice, calibre-web mostly is there to have a convenient way to fullfill the opinionated folder structure when uploading ebooks (calibre-web does not work on its own since it forces sqlite which does not work nicely with my NFS book store). I hope that in the future Kavita will implement ebook upload, or that calibre-web will ditch the sqlite constraints.
***** NixOS
:PROPERTIES:
-:CUSTOM_ID: h:a0b2d610-7258-4875-adb4-9ec4afe05b02
+:CUSTOM_ID: h:0094ccd0-36e4-46cb-a422-6f1aefb786d6
:END:
-#+begin_src nix :noweb yes :tangle profiles/server1/matrix/nixos.nix
+#+begin_src nix :tangle profiles/server1/calibre/nixos.nix
- { config, pkgs, modulesPath, unstable, sops, ... }: let
- matrixDomain = "matrix2.swarsel.win";
- in {
- <>
+ { config, pkgs, modulesPath, ... }:
+ {
imports = [
(modulesPath + "/virtualisation/proxmox-lxc.nix")
./hardware-configuration.nix
- # we import here a service that is not available yet on normal nixpkgs
- # this module is hence not in the modules list, we add it ourselves
];
- networking.hostName = "matrix"; # Define your hostname.
- networking.firewall.enable = false;
environment.systemPackages = with pkgs; [
git
gnupg
ssh-to-age
- matrix-synapse
- lottieconverter
- ffmpeg
+ calibre
];
+ users.groups.lxc_shares = {
+ gid = 10000;
+ members = [
+ "kavita"
+ "calibre-web"
+ "root"
+ ];
+ };
+
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
+
+ nix.settings.experimental-features = ["nix-command" "flakes"];
+
sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/matrix/secrets.yaml";
+ sops.defaultSopsFile = "/.dotfiles/secrets/calibre/secrets.yaml";
sops.validateSopsFiles = false;
- sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
- sops.templates."matrix_user_register.sh".content = ''
- register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
- '';
- sops.templates.matrixshared.owner = "matrix-synapse";
- sops.templates.matrixshared.content = ''
- registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
- '';
- sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
- sops.templates.mautrixtelegram.owner = "matrix-synapse";
- sops.templates.mautrixtelegram.content = ''
- MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
- MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
- MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
- MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
- '';
- # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
- # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
- # sops.templates.mautrixwhatsapp.content = ''
- # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
+ sops.secrets.kavita = { owner = "kavita";};
+ # sops.secrets.smbuser = { };
+ # sops.secrets.smbpassword = { };
+ # sops.secrets.smbdomain = { };
+ # sops.templates."smb.cred".content = ''
+ # user=${config.sops.placeholder.smbuser}
+ # password=${config.sops.placeholder.smbpassword}
+ # domain=${config.sops.placeholder.smbdomain}
# '';
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "calibre"; # Define your hostname.
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ networking.firewall.enable = false;
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
- services.postgresql.enable = true;
- services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
- CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
- CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
- CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
- CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
- CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- '';
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
- services.matrix-synapse = {
- settings.app_service_config_files = [
- "/var/lib/matrix-synapse/telegram-registration.yaml"
- "/var/lib/matrix-synapse/whatsapp-registration.yaml"
- "/var/lib/matrix-synapse/signal-registration.yaml"
- "/var/lib/matrix-synapse/doublepuppet.yaml"
- ];
+ environment.shellAliases = {
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
+
+
+ # services.calibre-server = {
+ # enable = true;
+ # user = "calibre-server";
+ # auth.enable = true;
+ # auth.userDb = "/srv/calibre/users.sqlite";
+ # libraries = [
+ # /media/Books/main
+ # /media/Books/diverse
+ # /media/Books/language
+ # /media/Books/science
+ # /media/Books/sport
+ # /media/Books/novels
+ # ];
+ # };
+
+ # services.calibre-web = {
+ # enable = true;
+ # user = "calibre-web";
+ # group = "calibre-web";
+ # listen.port = 8083;
+ # listen.ip = "0.0.0.0";
+ # options = {
+ # enableBookUploading = true;
+ # enableKepubify = true;
+ # enableBookConversion = true;
+ # };
+ # };
+
+ services.kavita = {
enable = true;
- settings.server_name = matrixDomain;
- settings.public_baseurl = "https://${matrixDomain}";
- extraConfigFiles = [
- config.sops.templates.matrixshared.path
- ];
- settings.listeners = [
- { port = 8008;
- bind_addresses = [ "0.0.0.0" ];
- type = "http";
- tls = false;
- x_forwarded = true;
- resources = [
- {
- names = [ "client" "federation" ];
- compress = true;
- }
- ];
- }
+ user = "kavita";
+ port = 8080;
+ tokenKeyFile = config.sops.secrets.kavita.path;
+ };
+
+
+ }
+
+#+end_src
+
+**** Jellyfin
+:PROPERTIES:
+:CUSTOM_ID: h:4a194546-9a9e-47c4-8d03-8d2428d45d30
+:END:
+***** NixOS
+:PROPERTIES:
+:CUSTOM_ID: h:9e94efd9-f63b-46ce-b34c-ec3128de5ed9
+:END:
+
+#+begin_src nix :tangle profiles/server1/jellyfin/nixos.nix
+
+ { config, pkgs, modulesPath, ... }:
+
+ {
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
+ ];
+
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ ];
+
+ users.groups.lxc_shares = {
+ gid = 10000;
+ members = [
+ "jellyfin"
+ "root"
];
};
- services.mautrix-telegram = {
- enable = true;
- environmentFile = config.sops.templates.mautrixtelegram.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29317";
- hostname = "0.0.0.0";
- port = "29317";
- provisioning.enabled = true;
- id = "telegram";
- # ephemeral_events = true; # not needed due to double puppeting
- public = {
- enabled = false;
- };
- database = "postgresql:///mautrix-telegram?host=/run/postgresql";
- };
- bridge = {
- # login_shared_secret_map = {
- # matrixDomain = "as_token:doublepuppet";
- # };
- relaybot.authless_portals = true;
- allow_avatar_remove = true;
- allow_contact_info = true;
- sync_channel_members = true;
- startup_sync = true;
- sync_create_limit = 0;
- sync_direct_chats = true;
- telegram_link_preview = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- # Animated stickers conversion requires additional packages in the
- # service's path.
- # If this isn't a fresh installation, clearing the bridge's uploaded
- # file cache might be necessary (make a database backup first!):
- # delete from telegram_file where \
- # mime_type in ('application/gzip', 'application/octet-stream')
- animated_sticker = {
- target = "gif";
- args = {
- width = 256;
- height = 256;
- fps = 30; # only for webm
- background = "020202"; # only for gif, transparency not supported
- };
- };
- };
- };
+ users.users.jellyfin = {
+ extraGroups = [ "video" "render" ];
};
- systemd.services.mautrix-telegram.path = with pkgs; [
- lottieconverter # for animated stickers conversion, unfree package
- ffmpeg # if converting animated stickers to webm (very slow!)
- ];
- services.mautrix-whatsapp = {
- enable = true;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29318";
- hostname = "0.0.0.0";
- port = 29318;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
- };
- };
- bridge = {
- displayname_template = "{{or .FullName .PushName .JID}} (WA)";
- history_sync = {
- backfill = true;
- max_initial_conversations = -1;
- message_count = -1;
- request_full_sync = true;
- full_sync_config = {
- days_limit = 900;
- size_mb_limit = 5000;
- storage_quota_mb = 5000;
- };
- };
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- sync_manual_marked_unread = true;
- send_presence_on_typing = true;
- parallel_member_sync = true;
- url_previews = true;
- caption_in_message = true;
- extev_polls = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- };
- };
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
};
- services.mautrix-signal = {
- enable = true;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
+ nix.settings.experimental-features = ["nix-command" "flakes"];
- address= "http://localhost:29328";
- hostname = "0.0.0.0";
- port = 29328;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-signal?host=/run/postgresql";
- };
- };
- bridge = {
- displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- caption_in_message = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- };
- };
+ # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ # sops.defaultSopsFile = "/.dotfiles/secrets/jellyfin/secrets.yaml";
+ # sops.validateSopsFiles = false;
+
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "jellyfin"; # Define your hostname.
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ networking.firewall.enable = false;
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
};
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
- # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
- # messages out after a while.
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
- systemd.timers."restart-bridges" = {
- wantedBy = [ "timers.target" ];
- timerConfig = {
- OnBootSec = "1d";
- OnUnitActiveSec = "1d";
- Unit = "restart-bridges.service";
- };
+ environment.shellAliases = {
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
};
- systemd.services."restart-bridges" = {
- script = ''
- systemctl restart mautrix-whatsapp.service
- systemctl restart mautrix-signal.service
- systemctl restart mautrix-telegram.service
- '';
- serviceConfig = {
- Type = "oneshot";
- User = "root";
- };
+ nixpkgs.config.packageOverrides = pkgs: {
+ vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
+ };
+ hardware.graphics = {
+ enable = true;
+ extraPackages = with pkgs; [
+ intel-media-driver # LIBVA_DRIVER_NAME=iHD
+ vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
+ vaapiVdpau
+ libvdpau-va-gl
+ ];
+ };
+
+ services.jellyfin = {
+ enable = true;
+ user = "jellyfin";
+ # openFirewall = true; # this works only for the default ports
};
}
#+end_src
-**** Sound
+**** [WIP/Incomplete/Untested] Transmission
:PROPERTIES:
-:CUSTOM_ID: h:b36415bf-77fa-4d51-842c-8cde0e46b844
+:CUSTOM_ID: h:dffc1243-8d6a-4cac-8a5d-3a27d4546235
:END:
+
+This stuff just does not work, I seem to be unable to create a working VPN Split Tunneling on NixOS. Maybe this is introduced by the wonky Proxmox-NixOS container interaction, I am not sure. For now, this machine does not work at all and I am stuck with my Debian Container that does this for me ...
+
***** NixOS
:PROPERTIES:
-:CUSTOM_ID: h:4bb55d69-9e09-4338-9f1e-a77ce37f02ed
+:CUSTOM_ID: h:2a2ebf94-b262-4e83-ab86-d8b1ebec492d
:END:
-#+begin_src nix :noweb yes :tangle profiles/server1/sound/nixos.nix
+#+begin_src nix :tangle profiles/server1/transmission/nixos.nix
- { config, pkgs, modulesPath, ... }:
+ { config, pkgs, modulesPath, ... }:
- {
- <>
+ {
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
+ # ./openvpn.nix #this file holds the vpn login data
+ ];
- proxmoxLXC.privileged = true; # manage hostname myself
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ openvpn
+ jq
+ iptables
+ busybox
+ wireguard-tools
+ ];
- users.groups.lxc_pshares = {
- gid = 110000;
- members = [
- "navidrome"
- "mpd"
- "root"
- ];
- };
+ users.groups.lxc_shares = {
+ gid = 10000;
+ members = [
+ "vpn"
+ "radarr"
+ "sonarr"
+ "lidarr"
+ "readarr"
+ "root"
+ ];
+ };
+ users.groups.vpn = {};
- users.groups.navidrome = {
- gid = 61593;
- };
+ users.users.vpn = {
+ isNormalUser = true;
+ group = "vpn";
+ home = "/home/vpn";
+ };
- users.groups.mpd = {};
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
- users.users.navidrome = {
- isSystemUser = true;
- uid = 61593;
- group = "navidrome";
- extraGroups = [ "audio" "utmp" ];
- };
+ nix.settings.experimental-features = ["nix-command" "flakes"];
- users.users.mpd = {
- isSystemUser = true;
- group = "mpd";
- extraGroups = [ "audio" "utmp" ];
- };
-
- sound = {
- enable = true;
- };
-
- hardware.enableAllFirmware = true;
- networking.hostName = "sound"; # Define your hostname.
- networking.firewall.enable = false;
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- pciutils
- alsa-utils
- mpv
- ];
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/.dotfiles/secrets/transmission/secrets.yaml";
+ sops.validateSopsFiles = false;
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/sound/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.mpdpass = { owner = "mpd";};
+ boot.kernelModules = [ "tun" ];
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "transmission"; # Define your hostname.
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ networking.firewall.enable = false;
- services.navidrome = {
- enable = true;
- settings = {
- Address = "0.0.0.0";
- Port = 4040;
- MusicFolder = "/media";
- EnableSharing = true;
- EnableTranscodingConfig = true;
- Scanner.GroupAlbumReleases = true;
- ScanSchedule = "@every 1d";
- # Insert these values locally as sops-nix does not work for them
- LastFM.ApiKey = TEMPLATE;
- LastFM.Secret = TEMPLATE;
- Spotify.ID = TEMPLATE;
- Spotify.Secret = TEMPLATE;
- UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png";
- UIWelcomeMessage = "~SwarselSound~";
- };
- };
- services.mpd = {
- enable = true;
- musicDirectory = "/media";
- user = "mpd";
- group = "mpd";
- network = {
- port = 3254;
- listenAddress = "any";
- };
- credentials = [
- {
- passwordFile = config.sops.secrets.mpdpass.path;
- permissions = [
- "read"
- "add"
- "control"
- "admin"
- ];
- }
- ];
- };
- }
-#+end_src
+ services.radarr = {
+ enable = true;
+ };
-**** Spotifyd
-:PROPERTIES:
-:CUSTOM_ID: h:23032961-346c-4141-97b9-a4d5469dc7d8
-:END:
-***** NixOS
-:PROPERTIES:
-:CUSTOM_ID: h:857bb1f6-9aeb-4600-ac79-a85ef011c847
-:END:
+ services.readarr = {
+ enable = true;
+ };
+ services.sonarr = {
+ enable = true;
+ };
+ services.lidarr = {
+ enable = true;
+ };
+ services.prowlarr = {
+ enable = true;
+ };
-#+begin_src nix :noweb yes :tangle profiles/server1/spotifyd/nixos.nix
+ # networking.interfaces = {
+ # lo = {
+ # useDHCP = false;
+ # ipv4.addresses = [
+ # { address = "127.0.0.1"; prefixLength = 8; }
+ # ];
+ # };
+ #
+ # eth0 = {
+ # useDHCP = true;
+ # };
+ # };
- { config, pkgs, modulesPath, ... }:
+ # networking.firewall.extraCommands = ''
+ # sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP
+ # '';
+ networking.iproute2 = {
+ enable = true;
+ rttablesExtraConfig = ''
+ 200 vpn
+ '';
+ };
+ # boot.kernel.sysctl = {
+ # "net.ipv4.conf.all.rp_filter" = 2;
+ # "net.ipv4.conf.default.rp_filter" = 2;
+ # "net.ipv4.conf.eth0.rp_filter" = 2;
+ # };
+ environment.etc = {
+ "openvpn/iptables.sh" =
+ { source = ../../../scripts/server1/iptables.sh;
+ mode = "0755";
+ };
+ "openvpn/update-resolv-conf" =
+ { source = ../../../scripts/server1/update-resolv-conf;
+ mode = "0755";
+ };
+ "openvpn/routing.sh" =
+ { source = ../../../scripts/server1/routing.sh;
+ mode = "0755";
+ };
+ "openvpn/ca.rsa.2048.crt" =
+ { source = ../../../secrets/certs/ca.rsa.2048.crt;
+ mode = "0644";
+ };
+ "openvpn/crl.rsa.2048.pem" =
+ { source = ../../../secrets/certs/crl.rsa.2048.pem;
+ mode = "0644";
+ };
+ };
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ listenAddresses = [{
+ port = 22;
+ addr = "0.0.0.0";
+ }];
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
- {
- <>
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ # users.users.root.password = "TEMPLATE";
- proxmoxLXC.privileged = true; # manage hostname myself
+ environment.shellAliases = {
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
- users.groups.spotifyd = {
- gid = 65136;
- };
+ sops.secrets.vpnuser = {};
+ sops.secrets.rpcuser = {owner="vpn";};
+ sops.secrets.vpnpass = {};
+ sops.secrets.rpcpass = {owner="vpn";};
+ sops.secrets.vpnprot = {};
+ sops.secrets.vpnloc = {};
+ # sops.secrets.crlpem = {};
+ # sops.secrets.capem = {};
+ sops.templates."transmission-rpc".owner = "vpn";
+ sops.templates."transmission-rpc".content = builtins.toJSON {
+ rpc-username = config.sops.placeholder.rpcuser;
+ rpc-password = config.sops.placeholder.rpcpass;
+ };
- users.users.spotifyd = {
- isSystemUser = true;
- uid = 65136;
- group = "spotifyd";
- extraGroups = [ "audio" "utmp" ];
- };
+ sops.templates.pia.content = ''
+ ${config.sops.placeholder.vpnuser}
+ ${config.sops.placeholder.vpnpass}
+ '';
- sound = {
- enable = true;
- };
+ sops.templates.vpn.content = ''
+ client
+ dev tun
+ proto ${config.sops.placeholder.vpnprot}
+ remote ${config.sops.placeholder.vpnloc}
+ resolv-retry infinite
+ nobind
+ persist-key
+ persist-tun
+ cipher aes-128-cbc
+ auth sha1
+ tls-client
+ remote-cert-tls server
- hardware.enableAllFirmware = true;
- networking.hostName = "spotifyd"; # Define your hostname.
- networking.firewall.enable = false;
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- ];
+ auth-user-pass ${config.sops.templates.pia.path}
+ compress
+ verb 1
+ reneg-sec 0
- # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- # sops.defaultSopsFile = "/.dotfiles/secrets/spotifyd/secrets.yaml";
- # sops.validateSopsFiles = false;
+ crl-verify /etc/openvpn/crl.rsa.2048.pem
+ ca /etc/openvpn/ca.rsa.2048.crt
- services.spotifyd = {
- enable = true;
- settings = {
- global = {
- dbus_type = "session";
- use_mpris = false;
- device = "default:CARD=PCH";
- device_name = "SwarselSpot";
- mixer = "alsa";
- zeroconf_port = 1025;
- };
- };
- };
+ disable-occ
+ dhcp-option DNS 209.222.18.222
+ dhcp-option DNS 209.222.18.218
+ dhcp-option DNS 8.8.8.8
+ route-noexec
+ '';
- }
+ # services.pia.enable = true;
+ # services.pia.authUserPass.username = "na";
+ # services.pia.authUserPass.password = "na";
-#+end_src
-**** Sync
-:PROPERTIES:
-:CUSTOM_ID: h:4c5febb0-fdf6-44c5-8d51-7ea0f8930abf
-:END:
-***** NixOS
-:PROPERTIES:
-:CUSTOM_ID: h:e5fbb73a-799a-438f-a88c-fc14d110ac9c
+ # systemd.services.openvpn-vpn = {
+ # wantedBy = [ "multi-user.target" ];
+ # after = [ "network.target" ];
+ # description = "OpenVPN connection to pia";
+ # serviceConfig = {
+ # Type = "forking";
+ # RuntimeDirectory="openvpn";
+ # PrivateTmp=true;
+ # KillMode="mixed";
+ # ExecStart = ''@${pkgs.openvpn}/sbin/openvpn openvpn --daemon ovpn-pia --status /run/openvpn/pia.status 10 --cd /etc/openvpn --script-security 2 --config ${config.sops.templates.vpn.path} --writepid /run/openvpn/pia.pid'';
+ # PIDFile=''/run/openvpn/pia.pid'';
+ # ExecReload=''/run/current-system/sw/bin/kill -HUP $MAINPID'';
+ # WorkingDirectory="/etc/openvpn";
+ # Restart="on-failure";
+ # RestartSec=30;
+ # ProtectSystem="yes";
+ # DeviceAllow=["/dev/null rw" "/dev/net/tun rw"];
+ # };
+ # };
+ services.openvpn.servers = {
+ pia = {
+ autoStart = false;
+ updateResolvConf = true;
+ # up = ''
+ # export INTERFACE="tun0"
+ # export VPNUSER="vpn"
+ # export LOCALIP="192.168.1.191"
+ # export NETIF="eth0"
+ # export VPNIF="tun0"
+ # export GATEWAYIP=$(ifconfig $VPNIF | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}' | egrep -v '255|(127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})' | tail -n1)
+ # iptables -F -t nat
+ # iptables -F -t mangle
+ # iptables -F -t filter
+ # iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
+ # iptables -t mangle -A OUTPUT ! --dest $LOCALIP -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
+ # iptables -t mangle -A OUTPUT --dest $LOCALIP -p udp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
+ # iptables -t mangle -A OUTPUT --dest $LOCALIP -p tcp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
+ # iptables -t mangle -A OUTPUT ! --src $LOCALIP -j MARK --set-mark 0x1
+ # iptables -t mangle -A OUTPUT -j CONNMARK --save-mark
+ # iptables -A INPUT -i $INTERFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+ # iptables -A INPUT -i $INTERFACE -j REJECT
+ # iptables -A OUTPUT -o lo -m owner --uid-owner $VPNUSER -j ACCEPT
+ # iptables -A OUTPUT -o $INTERFACE -m owner --uid-owner $VPNUSER -j ACCEPT
+ # iptables -t nat -A POSTROUTING -o $INTERFACE -j MASQUERADE
+ # iptables -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+ # iptables -A OUTPUT ! --src $LOCALIP -o $NETIF -j REJECT
+ # if [[ `ip rule list | grep -c 0x1` == 0 ]]; then
+ # ip rule add from all fwmark 0x1 lookup $VPNUSER
+ # fi
+ # ip route replace default via $GATEWAYIP table $VPNUSER
+ # ip route append default via 127.0.0.1 dev lo table $VPNUSER
+ # ip route flush cache
+ # '';
+ # down = "bash /etc/openvpn/update-resolv-conf";
+ # these are outsourced to a local file, I am not sure if it can be done with sops-nix
+ # authUserPass = {
+ # username = "TODO:secrets";
+ # password = "TODO:secrets";
+ # };
+ config = "config ${config.sops.templates.vpn.path}";
+ };
+ };
+
+ services.transmission = {
+ enable = true;
+ credentialsFile = config.sops.templates."transmission-rpc".path;
+ user = "vpn";
+ group = "lxc_shares";
+ settings = {
+
+ alt-speed-down= 8000;
+ alt-speed-enabled= false;
+ alt-speed-time-begin= 0;
+ alt-speed-time-day= 127;
+ alt-speed-time-enabled= true;
+ alt-speed-time-end= 360;
+ alt-speed-up= 2000;
+ bind-address-ipv4= "0.0.0.0";
+ bind-address-ipv6= "::";
+ blocklist-enabled= false;
+ blocklist-url= "http://www.example.com/blocklist";
+ cache-size-mb= 4;
+ dht-enabled= false;
+ download-dir= "/media/Eternor/New";
+ download-limit= 100;
+ download-limit-enabled= 0;
+ download-queue-enabled= true;
+ download-queue-size= 5;
+ encryption= 2;
+ idle-seeding-limit= 30;
+ idle-seeding-limit-enabled= false;
+ incomplete-dir= "/var/lib/transmission-daemon/Downloads";
+ incomplete-dir-enabled= false;
+ lpd-enabled= false;
+ max-peers-global= 200;
+ message-level= 1;
+ peer-congestion-algorithm= "";
+ peer-id-ttl-hours= 6;
+ peer-limit-global= 100;
+ peer-limit-per-torrent= 40;
+ peer-port= 22371;
+ peer-port-random-high= 65535;
+ peer-port-random-low= 49152;
+ peer-port-random-on-start= false;
+ peer-socket-tos= "default";
+ pex-enabled= false;
+ port-forwarding-enabled= false;
+ preallocation= 1;
+ prefetch-enabled= true;
+ queue-stalled-enabled= true;
+ queue-stalled-minutes= 30;
+ ratio-limit= 2;
+ ratio-limit-enabled= false;
+ rename-partial-files= true;
+ rpc-authentication-required= true;
+ rpc-bind-address= "0.0.0.0";
+ rpc-enabled= true;
+ rpc-host-whitelist= "";
+ rpc-host-whitelist-enabled= true;
+ rpc-port= 9091;
+ rpc-url= "/transmission/";
+ rpc-whitelist= "127.0.0.1,192.168.3.2";
+ rpc-whitelist-enabled= true;
+ scrape-paused-torrents-enabled= true;
+ script-torrent-done-enabled= false;
+ seed-queue-enabled= false;
+ seed-queue-size= 10;
+ speed-limit-down= 6000;
+ speed-limit-down-enabled= true;
+ speed-limit-up= 500;
+ speed-limit-up-enabled= true;
+ start-added-torrents= true;
+ trash-original-torrent-files= false;
+ umask= 2;
+ upload-limit= 100;
+ upload-limit-enabled= 0;
+ upload-slots-per-torrent= 14;
+ utp-enabled= false;
+ };
+ };
+
+ # services.nginx = {
+ # enable = true;
+ # virtualHosts = {
+
+ # "192.168.1.192" = {
+ # locations = {
+ # "/transmission" = {
+ # proxyPass = "http://127.0.0.1:9091";
+ # extraConfig = ''
+ # proxy_set_header Host $host;
+ # proxy_set_header X-Real-IP $remote_addr;
+ # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ # '';
+ # };
+ # };
+ # };
+ # };
+ # };
+
+
+ }
+
+#+end_src
+
+**** [Manual steps needed] Matrix
+:PROPERTIES:
+:CUSTOM_ID: h:1d6221c4-1f48-4f83-b262-5298ed99218e
:END:
-#+begin_src nix :tangle profiles/remote/oracle/sync/nixos.nix
+1) After the initial setup, run the
+ - /run/secrets-generated/matrix_user_register.sh
+command to register a new admin user.
+2) All bridges will fail on first start, copy the registration files using:
+ - cp /var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse/
+ - chown matrix-synapse:matrix-synapse var/lib/matrix-synapse/telegram-registration.yaml
+Make sure to also do this for doublepuppet.yaml
+3) Restart postgresql.service, matrix-synapse.service, mautrix-whatsapp.service, mautrix-telegram.service
- { config, pkgs, modulesPath, ... }:
+***** NixOS
+:PROPERTIES:
+:CUSTOM_ID: h:a0b2d610-7258-4875-adb4-9ec4afe05b02
+:END:
+
+#+begin_src nix :noweb yes :tangle profiles/server1/matrix/nixos.nix
+
+ { config, pkgs, modulesPath, unstable, sops, ... }: let
+ matrixDomain = "matrix2.swarsel.win";
+ in {
+ <>
- {
imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
./hardware-configuration.nix
+ # we import here a service that is not available yet on normal nixpkgs
+ # this module is hence not in the modules list, we add it ourselves
];
+ networking.hostName = "matrix"; # Define your hostname.
+ networking.firewall.enable = false;
environment.systemPackages = with pkgs; [
git
gnupg
ssh-to-age
+ matrix-synapse
+ lottieconverter
+ ffmpeg
];
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
-
- nix.settings.experimental-features = ["nix-command" "flakes"];
-
sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/root/.dotfiles/secrets/sync/secrets.yaml";
+ sops.defaultSopsFile = "/.dotfiles/secrets/matrix/secrets.yaml";
sops.validateSopsFiles = false;
- sops.secrets.swarsel = { owner = "root";};
- sops.secrets.dnstokenfull = {owner="acme";};
- sops.templates."certs.secret".content = ''
- CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
+ sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
+ sops.templates."matrix_user_register.sh".content = ''
+ register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
'';
+ sops.templates.matrixshared.owner = "matrix-synapse";
+ sops.templates.matrixshared.content = ''
+ registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
+ '';
+ sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
+ sops.templates.mautrixtelegram.owner = "matrix-synapse";
+ sops.templates.mautrixtelegram.content = ''
+ MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
+ MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
+ MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
+ MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
+ '';
+ # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
+ # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
+ # sops.templates.mautrixwhatsapp.content = ''
+ # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
+ # '';
- security.acme = {
- acceptTerms = true;
- preliminarySelfsigned = false;
- defaults.email = "mrswarsel@gmail.com";
- defaults.dnsProvider = "cloudflare";
- defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
- };
-
- services.nginx = {
- enable = true;
- recommendedProxySettings = true;
- recommendedTlsSettings = true;
- recommendedOptimisation = true;
- recommendedGzipSettings = true;
- virtualHosts = {
-
- "synki.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://localhost:27701";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
-
- "sync.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://localhost:8384/";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
-
- "swagit.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://localhost:3000";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
- };
- };
-
- boot.tmp.cleanOnBoot = true;
- zramSwap.enable = false;
- networking.hostName = "sync";
- networking.enableIPv6 = false;
- networking.domain = "subnet03112148.vcn03112148.oraclevcn.com";
- networking.firewall.extraCommands = ''
- iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 27701 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 8384 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 3000 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 22000 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p udp --dport 22000 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p udp --dport 21027 -j ACCEPT
+ services.postgresql.enable = true;
+ services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
+ CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
+ CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
+ CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
+ CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
+ CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
'';
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../../secrets/keys/authorized_keys
- ];
-
- system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change
-
- environment.shellAliases = {
- nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
- boot.loader.grub.device = "nodev";
-
- services.anki-sync-server = {
+ services.matrix-synapse = {
+ settings.app_service_config_files = [
+ "/var/lib/matrix-synapse/telegram-registration.yaml"
+ "/var/lib/matrix-synapse/whatsapp-registration.yaml"
+ "/var/lib/matrix-synapse/signal-registration.yaml"
+ "/var/lib/matrix-synapse/doublepuppet.yaml"
+ ];
enable = true;
- port = 27701;
- address = "0.0.0.0";
- openFirewall = true;
- users = [
- {
- username = "Swarsel";
- passwordFile = config.sops.secrets.swarsel.path;
+ settings.server_name = matrixDomain;
+ settings.public_baseurl = "https://${matrixDomain}";
+ extraConfigFiles = [
+ config.sops.templates.matrixshared.path
+ ];
+ settings.listeners = [
+ { port = 8008;
+ bind_addresses = [ "0.0.0.0" ];
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [
+ {
+ names = [ "client" "federation" ];
+ compress = true;
+ }
+ ];
}
];
};
- services.syncthing = {
+ services.mautrix-telegram = {
enable = true;
- guiAddress = "0.0.0.0:8384";
- openDefaultPorts = true;
+ environmentFile = config.sops.templates.mautrixtelegram.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
+ address= "http://localhost:29317";
+ hostname = "0.0.0.0";
+ port = "29317";
+ provisioning.enabled = true;
+ id = "telegram";
+ # ephemeral_events = true; # not needed due to double puppeting
+ public = {
+ enabled = false;
+ };
+ database = "postgresql:///mautrix-telegram?host=/run/postgresql";
+ };
+ bridge = {
+ # login_shared_secret_map = {
+ # matrixDomain = "as_token:doublepuppet";
+ # };
+ relaybot.authless_portals = true;
+ allow_avatar_remove = true;
+ allow_contact_info = true;
+ sync_channel_members = true;
+ startup_sync = true;
+ sync_create_limit = 0;
+ sync_direct_chats = true;
+ telegram_link_preview = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
+ # Animated stickers conversion requires additional packages in the
+ # service's path.
+ # If this isn't a fresh installation, clearing the bridge's uploaded
+ # file cache might be necessary (make a database backup first!):
+ # delete from telegram_file where \
+ # mime_type in ('application/gzip', 'application/octet-stream')
+ animated_sticker = {
+ target = "gif";
+ args = {
+ width = 256;
+ height = 256;
+ fps = 30; # only for webm
+ background = "020202"; # only for gif, transparency not supported
+ };
+ };
+ };
+ };
};
+ systemd.services.mautrix-telegram.path = with pkgs; [
+ lottieconverter # for animated stickers conversion, unfree package
+ ffmpeg # if converting animated stickers to webm (very slow!)
+ ];
- services.forgejo = {
+ services.mautrix-whatsapp = {
enable = true;
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
settings = {
- DEFAULT = {
- APP_NAME = "~SwaGit~";
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
};
- server = {
- PROTOCOL = "http";
- HTTP_PORT = 3000;
- HTTP_ADDR = "0.0.0.0";
- DOMAIN = "swagit.swarsel.win";
- ROOT_URL = "https://swagit.swarsel.win";
+ appservice = {
+ address= "http://localhost:29318";
+ hostname = "0.0.0.0";
+ port = 29318;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
+ };
};
- service = {
- DISABLE_REGISTRATION = true;
- SHOW_REGISTRATION_BUTTON = false;
+ bridge = {
+ displayname_template = "{{or .FullName .PushName .JID}} (WA)";
+ history_sync = {
+ backfill = true;
+ max_initial_conversations = -1;
+ message_count = -1;
+ request_full_sync = true;
+ full_sync_config = {
+ days_limit = 900;
+ size_mb_limit = 5000;
+ storage_quota_mb = 5000;
+ };
+ };
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ sync_manual_marked_unread = true;
+ send_presence_on_typing = true;
+ parallel_member_sync = true;
+ url_previews = true;
+ caption_in_message = true;
+ extev_polls = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
};
};
};
- }
-
-#+end_src
-
-**** [Manual steps required] Swatrix
-:PROPERTIES:
-:CUSTOM_ID: h:39553a9c-7095-4db8-b0df-bf47d91cb937
-:END:
-***** NixOS
-:PROPERTIES:
-:CUSTOM_ID: h:441d367d-cddd-40d7-9db7-d170e61e1c52
-:END:
-
-The files mentioned by
+ services.mautrix-signal = {
+ enable = true;
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
-#+begin_src nix :tangle no
+ address= "http://localhost:29328";
+ hostname = "0.0.0.0";
+ port = 29328;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-signal?host=/run/postgresql";
+ };
+ };
+ bridge = {
+ displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ caption_in_message = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
+ };
+ };
+ };
- settings.app_service_config_files = [
- "/var/lib/matrix-synapse/telegram-registration.yaml"
- "/var/lib/matrix-synapse/whatsapp-registration.yaml"
- "/var/lib/matrix-synapse/signal-registration.yaml"
- "/var/lib/matrix-synapse/doublepuppet.yaml"
- ]
+ # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
+ # messages out after a while.
+
+ systemd.timers."restart-bridges" = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnBootSec = "1d";
+ OnUnitActiveSec = "1d";
+ Unit = "restart-bridges.service";
+ };
+ };
+
+ systemd.services."restart-bridges" = {
+ script = ''
+ systemctl restart mautrix-whatsapp.service
+ systemctl restart mautrix-signal.service
+ systemctl restart mautrix-telegram.service
+ '';
+ serviceConfig = {
+ Type = "oneshot";
+ User = "root";
+ };
+ };
+
+ }
#+end_src
-need to be moved to the corresponding location. The below files are created as soon as the appservice is run once. This means that matrix will crash on the first startup; afterwards run these commands and restart the service.
+**** Sound
+:PROPERTIES:
+:CUSTOM_ID: h:b36415bf-77fa-4d51-842c-8cde0e46b844
+:END:
+***** NixOS
+:PROPERTIES:
+:CUSTOM_ID: h:4bb55d69-9e09-4338-9f1e-a77ce37f02ed
+:END:
-#+begin_src shell :tangle no
+#+begin_src nix :noweb yes :tangle profiles/server1/sound/nixos.nix
- cp /var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse/
- chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/telegram-registration.yaml
- cp /var/lib/mautrix-signal/signal-registration.yaml /var/lib/matrix-synapse/
- chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/signal-registration.yaml
- cp /var/lib/mautrix-whatsapp/whatsapp-registration.yaml /var/lib/matrix-synapse/
- chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/whatsapp-registration.yaml
+ { config, pkgs, modulesPath, ... }:
-#+end_src
+ {
+ <>
-as for the contents of doublepuppet.yaml:
+ proxmoxLXC.privileged = true; # manage hostname myself
-#+begin_src yaml :tangle no
-id: doublepuppet
-url:
-as_token: doublepuppet
-hs_token: notused
-sender_localpart: notused
-rate_limited: false
-namespaces:
- users:
- - regex: '@.*:matrix2\.swarsel\.win'
- exclusive: false
-#+end_src
+ users.groups.lxc_pshares = {
+ gid = 110000;
+ members = [
+ "navidrome"
+ "mpd"
+ "root"
+ ];
+ };
-Lastly, the machine that runs matrix needs to regularly update, as otherwise you will lose connectivity to the bridges.
+ users.groups.navidrome = {
+ gid = 61593;
+ };
-#+begin_src nix :tangle profiles/remote/oracle/matrix/nixos.nix
+ users.groups.mpd = {};
- { config, pkgs, modulesPath, unstable, sops, ... }: let
- matrixDomain = "swatrix.swarsel.win";
- in {
+ users.users.navidrome = {
+ isSystemUser = true;
+ uid = 61593;
+ group = "navidrome";
+ extraGroups = [ "audio" "utmp" ];
+ };
- imports = [
- ./hardware-configuration.nix
- # (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix") # no longer needed; mautrix-signal was added to nixpkgs
- ];
+ users.users.mpd = {
+ isSystemUser = true;
+ group = "mpd";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ sound = {
+ enable = true;
+ };
+ hardware.enableAllFirmware = true;
+ networking.hostName = "sound"; # Define your hostname.
+ networking.firewall.enable = false;
environment.systemPackages = with pkgs; [
git
gnupg
ssh-to-age
- matrix-synapse
- lottieconverter
- ffmpeg
+ pciutils
+ alsa-utils
+ mpv
];
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
-
- nix.settings.experimental-features = ["nix-command" "flakes"];
-
sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/root/.dotfiles/secrets/omatrix/secrets.yaml";
+ sops.defaultSopsFile = "/.dotfiles/secrets/sound/secrets.yaml";
sops.validateSopsFiles = false;
- sops.secrets.dnstokenfull = {owner="acme";};
- sops.templates."certs.secret".content = ''
- CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
- '';
-
- documentation = {
- enable = false;
- };
-
- security.acme = {
- acceptTerms = true;
- preliminarySelfsigned = false;
- defaults.email = "mrswarsel@gmail.com";
- defaults.dnsProvider = "cloudflare";
- defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
- };
+ sops.secrets.mpdpass = { owner = "mpd";};
- services.nginx = {
+ services.navidrome = {
enable = true;
- recommendedProxySettings = true;
- recommendedTlsSettings = true;
- recommendedOptimisation = true;
- recommendedGzipSettings = true;
- virtualHosts = {
-
- "swatrix.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "~ ^(/_matrix|/_synapse/client)" = {
- proxyPass = "http://localhost:8008";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ settings = {
+ Address = "0.0.0.0";
+ Port = 4040;
+ MusicFolder = "/media";
+ EnableSharing = true;
+ EnableTranscodingConfig = true;
+ Scanner.GroupAlbumReleases = true;
+ ScanSchedule = "@every 1d";
+ # Insert these values locally as sops-nix does not work for them
+ LastFM.ApiKey = TEMPLATE;
+ LastFM.Secret = TEMPLATE;
+ Spotify.ID = TEMPLATE;
+ Spotify.Secret = TEMPLATE;
+ UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png";
+ UIWelcomeMessage = "~SwarselSound~";
};
};
-
- boot.tmp.cleanOnBoot = true;
- zramSwap.enable = false;
- networking.hostName = "swatrix";
- networking.enableIPv6 = false;
- # networking.domain = "subnet03112148.vcn03112148.oraclevcn.com";
- networking.domain = "swarsel.win";
- networking.firewall.extraCommands = ''
- iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 8008 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 29317 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 29318 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 29328 -j ACCEPT
- '';
- services.openssh = {
+ services.mpd = {
enable = true;
- settings.PermitRootLogin = "yes";
+ musicDirectory = "/media";
+ user = "mpd";
+ group = "mpd";
+ network = {
+ port = 3254;
+ listenAddress = "any";
+ };
+ credentials = [
+ {
+ passwordFile = config.sops.secrets.mpdpass.path;
+ permissions = [
+ "read"
+ "add"
+ "control"
+ "admin"
+ ];
+ }
+ ];
};
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../../secrets/keys/authorized_keys
- ];
+ }
+#+end_src
- system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change
+**** Spotifyd
+:PROPERTIES:
+:CUSTOM_ID: h:23032961-346c-4141-97b9-a4d5469dc7d8
+:END:
+***** NixOS
+:PROPERTIES:
+:CUSTOM_ID: h:857bb1f6-9aeb-4600-ac79-a85ef011c847
+:END:
- environment.shellAliases = {
- nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
+#+begin_src nix :noweb yes :tangle profiles/server1/spotifyd/nixos.nix
- boot.loader.grub.device = "nodev";
+ { config, pkgs, modulesPath, ... }:
- sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
- sops.templates."matrix_user_register.sh".content = ''
- register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
- '';
- sops.templates.matrixshared.owner = "matrix-synapse";
- sops.templates.matrixshared.content = ''
- registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
- '';
- sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
- sops.templates.mautrixtelegram.owner = "matrix-synapse";
- sops.templates.mautrixtelegram.content = ''
- MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
- MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
- MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
- MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
- '';
- # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
- # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
- # sops.templates.mautrixwhatsapp.content = ''
- # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
- # '';
+ {
+ <>
- services.postgresql.enable = true;
- services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
- CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
- CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
- CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
- CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
- CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- '';
+ proxmoxLXC.privileged = true; # manage hostname myself
- services.matrix-synapse = {
- settings.app_service_config_files = [
- "/var/lib/matrix-synapse/telegram-registration.yaml"
- "/var/lib/matrix-synapse/whatsapp-registration.yaml"
- "/var/lib/matrix-synapse/signal-registration.yaml"
- "/var/lib/matrix-synapse/doublepuppet.yaml"
- ];
- enable = true;
- settings.server_name = matrixDomain;
- settings.public_baseurl = "https://${matrixDomain}";
- extraConfigFiles = [
- config.sops.templates.matrixshared.path
- ];
- settings.listeners = [
- { port = 8008;
- bind_addresses = [ "0.0.0.0" ];
- type = "http";
- tls = false;
- x_forwarded = true;
- resources = [
- {
- names = [ "client" "federation" ];
- compress = true;
- }
- ];
- }
- ];
+ users.groups.spotifyd = {
+ gid = 65136;
};
- services.mautrix-telegram = {
- enable = true;
- environmentFile = config.sops.templates.mautrixtelegram.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29317";
- hostname = "0.0.0.0";
- port = "29317";
- provisioning.enabled = true;
- id = "telegram";
- # ephemeral_events = true; # not needed due to double puppeting
- public = {
- enabled = false;
- };
- database = "postgresql:///mautrix-telegram?host=/run/postgresql";
- };
- bridge = {
- # login_shared_secret_map = {
- # matrixDomain = "as_token:doublepuppet";
- # };
- relaybot.authless_portals = true;
- allow_avatar_remove = true;
- allow_contact_info = true;
- sync_channel_members = true;
- startup_sync = true;
- sync_create_limit = 0;
- sync_direct_chats = true;
- telegram_link_preview = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- # Animated stickers conversion requires additional packages in the
- # service's path.
- # If this isn't a fresh installation, clearing the bridge's uploaded
- # file cache might be necessary (make a database backup first!):
- # delete from telegram_file where \
- # mime_type in ('application/gzip', 'application/octet-stream')
- animated_sticker = {
- target = "gif";
- args = {
- width = 256;
- height = 256;
- fps = 30; # only for webm
- background = "020202"; # only for gif, transparency not supported
- };
- };
- };
- };
+ users.users.spotifyd = {
+ isSystemUser = true;
+ uid = 65136;
+ group = "spotifyd";
+ extraGroups = [ "audio" "utmp" ];
};
- systemd.services.mautrix-telegram.path = with pkgs; [
- lottieconverter # for animated stickers conversion, unfree package
- ffmpeg # if converting animated stickers to webm (very slow!)
- ];
- services.mautrix-whatsapp = {
+ sound = {
enable = true;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29318";
- hostname = "0.0.0.0";
- port = 29318;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
- };
- };
- bridge = {
- displayname_template = "{{or .FullName .PushName .JID}} (WA)";
- history_sync = {
- backfill = true;
- max_initial_conversations = -1;
- message_count = -1;
- request_full_sync = true;
- full_sync_config = {
- days_limit = 900;
- size_mb_limit = 5000;
- storage_quota_mb = 5000;
- };
- };
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- sync_manual_marked_unread = true;
- send_presence_on_typing = true;
- parallel_member_sync = true;
- url_previews = true;
- caption_in_message = true;
- extev_polls = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- };
- };
};
- services.mautrix-signal = {
+ hardware.enableAllFirmware = true;
+ networking.hostName = "spotifyd"; # Define your hostname.
+ networking.firewall.enable = false;
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ ];
+
+ # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ # sops.defaultSopsFile = "/.dotfiles/secrets/spotifyd/secrets.yaml";
+ # sops.validateSopsFiles = false;
+
+ services.spotifyd = {
enable = true;
- registerToSynapse = false; # this has the same effect as registering to app_service_config_file above
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
-
- address= "http://localhost:29328";
- hostname = "0.0.0.0";
- port = 29328;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-signal?host=/run/postgresql";
- };
- };
- bridge = {
- displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- caption_in_message = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
+ global = {
+ dbus_type = "session";
+ use_mpris = false;
+ device = "default:CARD=PCH";
+ device_name = "SwarselSpot";
+ mixer = "alsa";
+ zeroconf_port = 1025;
};
};
};
- # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
- # messages out after a while.
-
- systemd.timers."restart-bridges" = {
- wantedBy = [ "timers.target" ];
- timerConfig = {
- OnBootSec = "1d";
- OnUnitActiveSec = "1d";
- Unit = "restart-bridges.service";
- };
- };
-
- systemd.services."restart-bridges" = {
- script = ''
- systemctl restart mautrix-whatsapp.service
- systemctl restart mautrix-signal.service
- systemctl restart mautrix-telegram.service
- '';
- serviceConfig = {
- Type = "oneshot";
- User = "root";
- };
- };
-
}
#+end_src
-**** Paperless
+**** Sync
:PROPERTIES:
-:CUSTOM_ID: h:17b9ba9d-94c9-44d5-99dd-776174d4bcc9
+:CUSTOM_ID: h:4c5febb0-fdf6-44c5-8d51-7ea0f8930abf
:END:
***** NixOS
:PROPERTIES:
-:CUSTOM_ID: h:1fc355ca-ca8c-4b02-ab3f-5656f2992112
+:CUSTOM_ID: h:e5fbb73a-799a-438f-a88c-fc14d110ac9c
:END:
-#+begin_src nix :noweb yes :tangle profiles/server1/paperless/nixos.nix
+#+begin_src nix :tangle profiles/remote/oracle/sync/nixos.nix
{ config, pkgs, modulesPath, ... }:
{
- <>
-
- users.groups.lxc_shares = {
- gid = 10000;
- members = [
- "paperless"
- "root"
- ];
- };
+ imports = [
+ ./hardware-configuration.nix
+ ];
environment.systemPackages = with pkgs; [
git
@@ -3500,918 +3805,613 @@ Lastly, the machine that runs matrix needs to regularly update, as otherwise you
ssh-to-age
];
- networking.hostName = "paperless"; # Define your hostname.
- networking.firewall.enable = false;
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
+
+ nix.settings.experimental-features = ["nix-command" "flakes"];
sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/root/.dotfiles/secrets/paperless/secrets.yaml";
+ sops.defaultSopsFile = "/root/.dotfiles/secrets/sync/secrets.yaml";
sops.validateSopsFiles = false;
- sops.secrets.admin = { owner = "paperless";};
+ sops.secrets.swarsel = { owner = "root";};
+ sops.secrets.dnstokenfull = {owner="acme";};
+ sops.templates."certs.secret".content = ''
+ CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
+ '';
- services.paperless = {
- enable = true;
- mediaDir = "/media";
- user = "paperless";
- port = 28981;
- passwordFile = config.sops.secrets.admin.path;
- address = "0.0.0.0";
- extraConfig = {
- PAPERLESS_OCR_LANGUAGE = "deu+eng";
- PAPERLESS_URL = "scan.swarsel.win";
- PAPERLESS_OCR_USER_ARGS = builtins.toJSON {
- optimize = 1;
- pdfa_image_compression = "lossless";
- };
- };
+ security.acme = {
+ acceptTerms = true;
+ preliminarySelfsigned = false;
+ defaults.email = "mrswarsel@gmail.com";
+ defaults.dnsProvider = "cloudflare";
+ defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
};
- }
-
-#+end_src
-
-**** Sandbox (Lenovo Y510P)
-:PROPERTIES:
-:CUSTOM_ID: h:60cf171f-2ec9-418f-8f67-85d159efe9d0
-:END:
-
-My laptop, sadly soon to be replaced by a new one, since most basic functions are stopping to work lately.
-
-***** NixOS
-:PROPERTIES:
-:CUSTOM_ID: h:23b0f629-343c-42fa-bf9b-70bea341c0d2
-:END:
-
-#+begin_src nix :noweb yes :tangle profiles/sandbox/nixos.nix
-
- { config, pkgs, modulesPath, unstable, sops, ... }: let
- matrixDomain = "swatrix.swarsel.win";
- in {
-
- imports = [
- ./hardware-configuration.nix
- # we import here a service that is not available yet on normal nixpkgs
- # this module is hence not in the modules list, we add it ourselves
- (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix")
- ];
-
- boot.loader.grub = {
- enable = true;
- device = "/dev/sda";
- useOSProber = true;
- };
-
- users.users.swarsel = {
- isNormalUser = true;
- description = "Leon S";
- extraGroups = [ "networkmanager" "wheel" "lp"];
- packages = with pkgs; [];
- };
-
- # actual config starts here
-
- fileSystems."/mnt/Eternor" = {
- device = "//192.168.1.3/Eternor";
- fsType = "cifs";
- options = let
- # this line prevents hanging on network split
- automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s";
- in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=1000,gid=100"];
- };
-
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- lego
- nginx
- calibre
- openvpn
- jq
- iptables
- busybox
- wireguard-tools
- matrix-synapse
- lottieconverter
- ffmpeg
- pciutils
- alsa-utils
- mpv
- zfs
- ];
-
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
-
- nix.settings.experimental-features = ["nix-command" "flakes"];
-
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
- listenAddresses = [{
- port = 22;
- addr = "0.0.0.0";
- }];
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../secrets/keys/authorized_keys
- ];
-
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
-
- environment.shellAliases = {
- nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
-
- boot.supportedFilesystems = [ "zfs" ];
- boot.zfs.forceImportRoot = false;
- networking.hostId = "8a8ad84a";
-
- networking.hostName = "sandbox"; # Define your hostname.
- networking.enableIPv6 = true;
- networking.firewall.enable = false;
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ virtualHosts = {
- documentation = {
- enable = false;
+ "synki.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://localhost:27701";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
};
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/root/.dotfiles/secrets/sandbox/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.dnstokenfull = {owner="acme";};
- sops.templates."certs.secret".content = ''
- CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
- '';
-
- security.acme = {
- acceptTerms = true;
- preliminarySelfsigned = false;
- defaults.email = "mrswarsel@gmail.com";
- defaults.dnsProvider = "cloudflare";
- defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
- };
-
- services.nginx = {
- enable = true;
- recommendedProxySettings = true;
- recommendedTlsSettings = true;
- recommendedOptimisation = true;
- recommendedGzipSettings = true;
- virtualHosts = {
-
- "stash.swarsel.win" = {
+ "sync.swarsel.win" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
- proxyPass = "https://192.168.1.5";
+ proxyPass = "http://localhost:8384/";
extraConfig = ''
- client_max_body_size 0;
+ client_max_body_size 0;
'';
};
- # "/push/" = {
- # proxyPass = "http://192.168.2.5:7867";
- # };
- "/.well-known/carddav" = {
- return = "301 $scheme://$host/remote.php/dav";
- };
- "/.well-known/caldav" = {
- return = "301 $scheme://$host/remote.php/dav";
- };
};
};
- "swatrix.swarsel.win" = {
+ "swagit.swarsel.win" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
locations = {
- "~ ^(/_matrix|/_synapse/client)" = {
- proxyPass = "http://127.0.0.1:8008";
+ "/" = {
+ proxyPass = "http://localhost:3000";
extraConfig = ''
- client_max_body_size 0;
- '';
+ client_max_body_size 0;
+ '';
};
};
};
+ };
+ };
+ boot.tmp.cleanOnBoot = true;
+ zramSwap.enable = false;
+ networking.hostName = "sync";
+ networking.enableIPv6 = false;
+ networking.domain = "subnet03112148.vcn03112148.oraclevcn.com";
+ networking.firewall.extraCommands = ''
+ iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 27701 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 8384 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 3000 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 22000 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p udp --dport 22000 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p udp --dport 21027 -j ACCEPT
+ '';
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../../secrets/keys/authorized_keys
+ ];
- "sound.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://127.0.0.1:4040";
- proxyWebsockets = true;
- extraConfig = ''
- proxy_redirect http:// https://;
- proxy_read_timeout 600s;
- proxy_send_timeout 600s;
- proxy_buffering off;
- proxy_request_buffering off;
- client_max_body_size 0;
- '';
- };
- };
- };
+ system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change
- "scan.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://127.0.0.1:28981";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ environment.shellAliases = {
+ nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
- "screen.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://127.0.0.1:8096";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ boot.loader.grub.device = "nodev";
- "scroll.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://127.0.0.1:8080";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ services.anki-sync-server = {
+ enable = true;
+ port = 27701;
+ address = "0.0.0.0";
+ openFirewall = true;
+ users = [
+ {
+ username = "Swarsel";
+ passwordFile = config.sops.secrets.swarsel.path;
+ }
+ ];
+ };
+ services.syncthing = {
+ enable = true;
+ guiAddress = "0.0.0.0:8384";
+ openDefaultPorts = true;
+ };
- };
+ services.forgejo = {
+ enable = true;
+ settings = {
+ DEFAULT = {
+ APP_NAME = "~SwaGit~";
};
+ server = {
+ PROTOCOL = "http";
+ HTTP_PORT = 3000;
+ HTTP_ADDR = "0.0.0.0";
+ DOMAIN = "swagit.swarsel.win";
+ ROOT_URL = "https://swagit.swarsel.win";
+ };
+ service = {
+ DISABLE_REGISTRATION = true;
+ SHOW_REGISTRATION_BUTTON = false;
+ };
+ };
+ };
+ }
- sops.secrets.kavita = { owner = "kavita";};
-
- services.kavita = {
- enable = true;
- user = "kavita";
- port = 8080;
- tokenKeyFile = config.sops.secrets.kavita.path;
- };
+#+end_src
- users.users.jellyfin = {
- extraGroups = [ "video" "render" ];
- };
+**** [Manual steps required] Swatrix
+:PROPERTIES:
+:CUSTOM_ID: h:39553a9c-7095-4db8-b0df-bf47d91cb937
+:END:
+***** NixOS
+:PROPERTIES:
+:CUSTOM_ID: h:441d367d-cddd-40d7-9db7-d170e61e1c52
+:END:
- # nixpkgs.config.packageOverrides = pkgs: {
- # vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
- # };
+The files mentioned by
- hardware.graphics = {
- enable = true;
- extraPackages = with pkgs; [
- intel-media-driver # LIBVA_DRIVER_NAME=iHD
- vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
- vaapiVdpau
- libvdpau-va-gl
- ];
- };
+#+begin_src nix :tangle no
- services.jellyfin = {
- enable = true;
- user = "jellyfin";
- # openFirewall = true; # this works only for the default ports
- };
+ settings.app_service_config_files = [
+ "/var/lib/matrix-synapse/telegram-registration.yaml"
+ "/var/lib/matrix-synapse/whatsapp-registration.yaml"
+ "/var/lib/matrix-synapse/signal-registration.yaml"
+ "/var/lib/matrix-synapse/doublepuppet.yaml"
+ ]
- users.groups.vpn = {};
+#+end_src
- users.users.vpn = {
- isNormalUser = true;
- group = "vpn";
- home = "/home/vpn";
- };
+need to be moved to the corresponding location. The below files are created as soon as the appservice is run once. This means that matrix will crash on the first startup; afterwards run these commands and restart the service.
- boot.kernelModules = [ "tun" ];
+#+begin_src shell :tangle no
- services.radarr = {
- enable = true;
- };
+ cp /var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse/
+ chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/telegram-registration.yaml
+ cp /var/lib/mautrix-signal/signal-registration.yaml /var/lib/matrix-synapse/
+ chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/signal-registration.yaml
+ cp /var/lib/mautrix-whatsapp/whatsapp-registration.yaml /var/lib/matrix-synapse/
+ chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/whatsapp-registration.yaml
- services.readarr = {
- enable = true;
- };
- services.sonarr = {
- enable = true;
- };
- services.lidarr = {
- enable = true;
- };
- services.prowlarr = {
- enable = true;
- };
+#+end_src
- networking.firewall.extraCommands = ''
- sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP
- '';
- networking.iproute2 = {
- enable = true;
- rttablesExtraConfig = ''
- 200 vpn
- '';
- };
- boot.kernel.sysctl = {
- "net.ipv4.conf.all.rp_filter" = 2;
- "net.ipv4.conf.default.rp_filter" = 2;
- "net.ipv4.conf.enp7s0.rp_filter" = 2;
- };
- environment.etc = {
- "openvpn/iptables.sh" =
- { source = ../../scripts/server1/iptables.sh;
- mode = "0755";
- };
- "openvpn/update-resolv-conf" =
- { source = ../../scripts/server1/update-resolv-conf;
- mode = "0755";
- };
- "openvpn/routing.sh" =
- { source = ../../scripts/server1/routing.sh;
- mode = "0755";
- };
- "openvpn/ca.rsa.2048.crt" =
- { source = ../../secrets/certs/ca.rsa.2048.crt;
- mode = "0644";
- };
- "openvpn/crl.rsa.2048.pem" =
- { source = ../../secrets/certs/crl.rsa.2048.pem;
- mode = "0644";
- };
- };
+as for the contents of doublepuppet.yaml:
- sops.secrets.vpnuser = {};
- sops.secrets.rpcuser = {owner="vpn";};
- sops.secrets.vpnpass = {};
- sops.secrets.rpcpass = {owner="vpn";};
- sops.secrets.vpnprot = {};
- sops.secrets.vpnloc = {};
- # sops.secrets.crlpem = {};
- # sops.secrets.capem = {};
- sops.templates."transmission-rpc".owner = "vpn";
- sops.templates."transmission-rpc".content = builtins.toJSON {
- rpc-username = config.sops.placeholder.rpcuser;
- rpc-password = config.sops.placeholder.rpcpass;
- };
+#+begin_src yaml :tangle no
+id: doublepuppet
+url:
+as_token: doublepuppet
+hs_token: notused
+sender_localpart: notused
+rate_limited: false
+namespaces:
+ users:
+ - regex: '@.*:matrix2\.swarsel\.win'
+ exclusive: false
+#+end_src
- sops.templates.pia.content = ''
- ${config.sops.placeholder.vpnuser}
- ${config.sops.placeholder.vpnpass}
- '';
+Lastly, the machine that runs matrix needs to regularly update, as otherwise you will lose connectivity to the bridges.
- sops.templates.vpn.content = ''
- client
- dev tun
- proto ${config.sops.placeholder.vpnprot}
- remote ${config.sops.placeholder.vpnloc}
- resolv-retry infinite
- nobind
- persist-key
- persist-tun
- cipher aes-128-cbc
- auth sha1
- tls-client
- remote-cert-tls server
+#+begin_src nix :tangle profiles/remote/oracle/matrix/nixos.nix
- auth-user-pass ${config.sops.templates.pia.path}
- compress
- verb 1
- reneg-sec 0
-
- crl-verify /etc/openvpn/crl.rsa.2048.pem
- ca /etc/openvpn/ca.rsa.2048.crt
+ { config, pkgs, modulesPath, unstable, sops, ... }: let
+ matrixDomain = "swatrix.swarsel.win";
+ in {
- disable-occ
- '';
+ imports = [
+ ./hardware-configuration.nix
+ # (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix") # no longer needed; mautrix-signal was added to nixpkgs
+ ];
- services.openvpn.servers = {
- pia = {
- autoStart = true;
- updateResolvConf = false;
- config = "config ${config.sops.templates.vpn.path}";
- };
- };
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ matrix-synapse
+ lottieconverter
+ ffmpeg
+ ];
- services.transmission = {
- enable = true;
- credentialsFile = config.sops.templates."transmission-rpc".path;
- user = "vpn";
- settings = {
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
- alt-speed-down= 8000;
- alt-speed-enabled= false;
- alt-speed-time-begin= 0;
- alt-speed-time-day= 127;
- alt-speed-time-enabled= true;
- alt-speed-time-end= 360;
- alt-speed-up= 2000;
- bind-address-ipv4= "0.0.0.0";
- bind-address-ipv6= "::";
- blocklist-enabled= false;
- blocklist-url= "http://www.example.com/blocklist";
- cache-size-mb= 256;
- dht-enabled= false;
- download-dir= "/test";
- download-limit= 100;
- download-limit-enabled= 0;
- download-queue-enabled= true;
- download-queue-size= 5;
- encryption= 2;
- idle-seeding-limit= 30;
- idle-seeding-limit-enabled= false;
- incomplete-dir= "/var/lib/transmission-daemon/Downloads";
- incomplete-dir-enabled= false;
- lpd-enabled= false;
- max-peers-global= 200;
- message-level= 1;
- peer-congestion-algorithm= "";
- peer-id-ttl-hours= 6;
- peer-limit-global= 100;
- peer-limit-per-torrent= 40;
- peer-port= 22371;
- peer-port-random-high= 65535;
- peer-port-random-low= 49152;
- peer-port-random-on-start= false;
- peer-socket-tos= "default";
- pex-enabled= false;
- port-forwarding-enabled= false;
- preallocation= 1;
- prefetch-enabled= true;
- queue-stalled-enabled= true;
- queue-stalled-minutes= 30;
- ratio-limit= 2;
- ratio-limit-enabled= false;
- rename-partial-files= true;
- rpc-authentication-required= true;
- rpc-bind-address= "0.0.0.0";
- rpc-enabled= true;
- rpc-host-whitelist= "";
- rpc-host-whitelist-enabled= true;
- rpc-port= 9091;
- rpc-url= "/transmission/";
- rpc-whitelist= "127.0.0.1,192.168.3.2";
- rpc-whitelist-enabled= true;
- scrape-paused-torrents-enabled= true;
- script-torrent-done-enabled= false;
- seed-queue-enabled= false;
- seed-queue-size= 10;
- speed-limit-down= 6000;
- speed-limit-down-enabled= true;
- speed-limit-up= 500;
- speed-limit-up-enabled= true;
- start-added-torrents= true;
- trash-original-torrent-files= false;
- umask= 2;
- upload-limit= 100;
- upload-limit-enabled= 0;
- upload-slots-per-torrent= 14;
- utp-enabled= false;
- };
- };
+ nix.settings.experimental-features = ["nix-command" "flakes"];
- # services.nginx = {
- # enable = true;
- # virtualHosts = {
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/root/.dotfiles/secrets/omatrix/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.dnstokenfull = {owner="acme";};
+ sops.templates."certs.secret".content = ''
+ CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
+ '';
- # "192.168.1.192" = {
- # locations = {
- # "/transmission" = {
- # proxyPass = "http://127.0.0.1:9091";
- # extraConfig = ''
- # proxy_set_header Host $host;
- # proxy_set_header X-Real-IP $remote_addr;
- # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- # '';
- # };
- # };
- # };
- # };
- # };
+ documentation = {
+ enable = false;
+ };
+ security.acme = {
+ acceptTerms = true;
+ preliminarySelfsigned = false;
+ defaults.email = "mrswarsel@gmail.com";
+ defaults.dnsProvider = "cloudflare";
+ defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
+ };
- # sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
- # sops.templates."matrix_user_register.sh".content = ''
- # register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
- # '';
- # sops.templates.matrixshared.owner = "matrix-synapse";
- # sops.templates.matrixshared.content = ''
- # registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
- # '';
- # sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
- # sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
- # sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
- # sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
- # sops.templates.mautrixtelegram.owner = "matrix-synapse";
- # sops.templates.mautrixtelegram.content = ''
- # MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
- # MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
- # MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
- # MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
- # '';
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ virtualHosts = {
+ "swatrix.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "~ ^(/_matrix|/_synapse/client)" = {
+ proxyPass = "http://localhost:8008";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+ };
+ };
+ boot.tmp.cleanOnBoot = true;
+ zramSwap.enable = false;
+ networking.hostName = "swatrix";
+ networking.enableIPv6 = false;
+ # networking.domain = "subnet03112148.vcn03112148.oraclevcn.com";
+ networking.domain = "swarsel.win";
+ networking.firewall.extraCommands = ''
+ iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 8008 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 29317 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 29318 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 29328 -j ACCEPT
+ '';
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../../secrets/keys/authorized_keys
+ ];
+ system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change
- # ----------------
- # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
- # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
- # sops.templates.mautrixwhatsapp.content = ''
- # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
- # '';
+ environment.shellAliases = {
+ nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
- services.postgresql.enable = true;
- services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
- CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
- CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
- CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
- CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
- CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- '';
+ boot.loader.grub.device = "nodev";
- services.matrix-synapse = {
- settings.app_service_config_files = [
- "/var/lib/matrix-synapse/telegram-registration.yaml"
- "/var/lib/matrix-synapse/whatsapp-registration.yaml"
- "/var/lib/matrix-synapse/signal-registration.yaml"
- "/var/lib/matrix-synapse/doublepuppet.yaml"
- ];
- enable = false;
- settings.server_name = matrixDomain;
- settings.public_baseurl = "https://${matrixDomain}";
- extraConfigFiles = [
- config.sops.templates.matrixshared.path
- ];
- settings.listeners = [
- { port = 8008;
- bind_addresses = [ "0.0.0.0" ];
- type = "http";
- tls = false;
- x_forwarded = true;
- resources = [
- {
- names = [ "client" "federation" ];
- compress = true;
- }
- ];
- }
- ];
- };
+ sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
+ sops.templates."matrix_user_register.sh".content = ''
+ register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
+ '';
+ sops.templates.matrixshared.owner = "matrix-synapse";
+ sops.templates.matrixshared.content = ''
+ registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
+ '';
+ sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
+ sops.templates.mautrixtelegram.owner = "matrix-synapse";
+ sops.templates.mautrixtelegram.content = ''
+ MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
+ MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
+ MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
+ MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
+ '';
+ # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
+ # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
+ # sops.templates.mautrixwhatsapp.content = ''
+ # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
+ # '';
- services.mautrix-telegram = {
- enable = false;
- environmentFile = config.sops.templates.mautrixtelegram.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29317";
- hostname = "0.0.0.0";
- port = "29317";
- provisioning.enabled = true;
- id = "telegram";
- # ephemeral_events = true; # not needed due to double puppeting
- public = {
- enabled = false;
- };
- database = "postgresql:///mautrix-telegram?host=/run/postgresql";
- };
- bridge = {
- # login_shared_secret_map = {
- # matrixDomain = "as_token:doublepuppet";
- # };
- relaybot.authless_portals = true;
- allow_avatar_remove = true;
- allow_contact_info = true;
- sync_channel_members = true;
- startup_sync = true;
- sync_create_limit = 0;
- sync_direct_chats = true;
- telegram_link_preview = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- # Animated stickers conversion requires additional packages in the
- # service's path.
- # If this isn't a fresh installation, clearing the bridge's uploaded
- # file cache might be necessary (make a database backup first!):
- # delete from telegram_file where \
- # mime_type in ('application/gzip', 'application/octet-stream')
- animated_sticker = {
- target = "gif";
- args = {
- width = 256;
- height = 256;
- fps = 30; # only for webm
- background = "020202"; # only for gif, transparency not supported
- };
- };
- };
- };
- };
- # systemd.services.mautrix-telegram.path = with pkgs; [
- # lottieconverter # for animated stickers conversion, unfree package
- # ffmpeg # if converting animated stickers to webm (very slow!)
- # ];
+ services.postgresql.enable = true;
+ services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
+ CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
+ CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
+ CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
+ CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
+ CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ '';
- services.mautrix-whatsapp = {
- enable = false;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
+ services.matrix-synapse = {
+ settings.app_service_config_files = [
+ "/var/lib/matrix-synapse/telegram-registration.yaml"
+ "/var/lib/matrix-synapse/whatsapp-registration.yaml"
+ "/var/lib/matrix-synapse/signal-registration.yaml"
+ "/var/lib/matrix-synapse/doublepuppet.yaml"
+ ];
+ enable = true;
+ settings.server_name = matrixDomain;
+ settings.public_baseurl = "https://${matrixDomain}";
+ extraConfigFiles = [
+ config.sops.templates.matrixshared.path
+ ];
+ settings.listeners = [
+ { port = 8008;
+ bind_addresses = [ "0.0.0.0" ];
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [
+ {
+ names = [ "client" "federation" ];
+ compress = true;
+ }
+ ];
+ }
+ ];
+ };
+
+ services.mautrix-telegram = {
+ enable = true;
+ environmentFile = config.sops.templates.mautrixtelegram.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
+ address= "http://localhost:29317";
+ hostname = "0.0.0.0";
+ port = "29317";
+ provisioning.enabled = true;
+ id = "telegram";
+ # ephemeral_events = true; # not needed due to double puppeting
+ public = {
+ enabled = false;
};
- appservice = {
- address= "http://localhost:29318";
- hostname = "0.0.0.0";
- port = 29318;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
- };
+ database = "postgresql:///mautrix-telegram?host=/run/postgresql";
+ };
+ bridge = {
+ # login_shared_secret_map = {
+ # matrixDomain = "as_token:doublepuppet";
+ # };
+ relaybot.authless_portals = true;
+ allow_avatar_remove = true;
+ allow_contact_info = true;
+ sync_channel_members = true;
+ startup_sync = true;
+ sync_create_limit = 0;
+ sync_direct_chats = true;
+ telegram_link_preview = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
};
- bridge = {
- displayname_template = "{{or .FullName .PushName .JID}} (WA)";
- history_sync = {
- backfill = true;
- max_initial_conversations = -1;
- message_count = -1;
- request_full_sync = true;
- full_sync_config = {
- days_limit = 900;
- size_mb_limit = 5000;
- storage_quota_mb = 5000;
- };
- };
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- sync_manual_marked_unread = true;
- send_presence_on_typing = true;
- parallel_member_sync = true;
- url_previews = true;
- caption_in_message = true;
- extev_polls = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
+ # Animated stickers conversion requires additional packages in the
+ # service's path.
+ # If this isn't a fresh installation, clearing the bridge's uploaded
+ # file cache might be necessary (make a database backup first!):
+ # delete from telegram_file where \
+ # mime_type in ('application/gzip', 'application/octet-stream')
+ animated_sticker = {
+ target = "gif";
+ args = {
+ width = 256;
+ height = 256;
+ fps = 30; # only for webm
+ background = "020202"; # only for gif, transparency not supported
};
};
};
};
+ };
+ systemd.services.mautrix-telegram.path = with pkgs; [
+ lottieconverter # for animated stickers conversion, unfree package
+ ffmpeg # if converting animated stickers to webm (very slow!)
+ ];
- services.mautrix-signal = {
- enable = false;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
-
- address= "http://localhost:29328";
- hostname = "0.0.0.0";
- port = 29328;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-signal?host=/run/postgresql";
- };
+ services.mautrix-whatsapp = {
+ enable = true;
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
+ address= "http://localhost:29318";
+ hostname = "0.0.0.0";
+ port = 29318;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
};
- bridge = {
- displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- caption_in_message = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
+ };
+ bridge = {
+ displayname_template = "{{or .FullName .PushName .JID}} (WA)";
+ history_sync = {
+ backfill = true;
+ max_initial_conversations = -1;
+ message_count = -1;
+ request_full_sync = true;
+ full_sync_config = {
+ days_limit = 900;
+ size_mb_limit = 5000;
+ storage_quota_mb = 5000;
};
};
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ sync_manual_marked_unread = true;
+ send_presence_on_typing = true;
+ parallel_member_sync = true;
+ url_previews = true;
+ caption_in_message = true;
+ extev_polls = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
};
};
+ };
- # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
- # messages out after a while.
-
- systemd.timers."restart-bridges" = {
- wantedBy = [ "timers.target" ];
- timerConfig = {
- OnBootSec = "1d";
- OnUnitActiveSec = "1d";
- Unit = "restart-bridges.service";
- };
- };
-
- systemd.services."restart-bridges" = {
- script = ''
- systemctl restart mautrix-whatsapp.service
- systemctl restart mautrix-signal.service
- systemctl restart mautrix-telegram.service
- '';
- serviceConfig = {
- Type = "oneshot";
- User = "root";
+ services.mautrix-signal = {
+ enable = true;
+ registerToSynapse = false; # this has the same effect as registering to app_service_config_file above
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
};
- };
-
-
- users.groups.navidrome = {
- gid = 61593;
- };
-
- users.groups.mpd = {};
-
- users.users.navidrome = {
- isSystemUser = true;
- uid = 61593;
- group = "navidrome";
- extraGroups = [ "audio" "utmp" ];
- };
-
- users.users.mpd = {
- isSystemUser = true;
- group = "mpd";
- extraGroups = [ "audio" "utmp" ];
- };
-
- sound = {
- enable = true;
- };
-
- hardware.enableAllFirmware = true;
-
- sops.secrets.mpdpass = { owner = "mpd";};
+ appservice = {
- services.navidrome = {
- enable = true;
- settings = {
- Address = "0.0.0.0";
- Port = 4040;
- MusicFolder = "/mnt/";
- EnableSharing = true;
- EnableTranscodingConfig = true;
- Scanner.GroupAlbumReleases = true;
- ScanSchedule = "@every 24h";
- # Insert these values locally as sops-nix does not work for them
- # LastFM.ApiKey = TEMPLATE;
- # LastFM.Secret = TEMPLATE;
- # Spotify.ID = TEMPLATE;
- # Spotify.Secret = TEMPLATE;
- UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png";
- UIWelcomeMessage = "~SwarselSound~";
+ address= "http://localhost:29328";
+ hostname = "0.0.0.0";
+ port = 29328;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-signal?host=/run/postgresql";
+ };
};
- };
- services.mpd = {
- enable = true;
- musicDirectory = "/mnt/Eternor/Musik";
- user = "mpd";
- group = "mpd";
- network = {
- port = 3254;
- listenAddress = "any";
+ bridge = {
+ displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ caption_in_message = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
};
- credentials = [
- {
- passwordFile = config.sops.secrets.mpdpass.path;
- permissions = [
- "read"
- "add"
- "control"
- "admin"
- ];
- }
- ];
};
+ };
+ # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
+ # messages out after a while.
- users.groups.spotifyd = {
- gid = 65136;
- };
-
- users.users.spotifyd = {
- isSystemUser = true;
- uid = 65136;
- group = "spotifyd";
- extraGroups = [ "audio" "utmp" ];
+ systemd.timers."restart-bridges" = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnBootSec = "1d";
+ OnUnitActiveSec = "1d";
+ Unit = "restart-bridges.service";
};
+ };
- services.spotifyd = {
- enable = true;
- settings = {
- global = {
- dbus_type = "session";
- use_mpris = false;
- device = "default:CARD=PCH";
- device_name = "SwarselSpot";
- mixer = "alsa";
- zeroconf_port = 1025;
- };
- };
+ systemd.services."restart-bridges" = {
+ script = ''
+ systemctl restart mautrix-whatsapp.service
+ systemctl restart mautrix-signal.service
+ systemctl restart mautrix-telegram.service
+ '';
+ serviceConfig = {
+ Type = "oneshot";
+ User = "root";
};
+ };
- # Network shares
- # add a user with sudo smbpasswd -a
- services.samba = {
- package = pkgs.samba4Full;
- extraConfig = ''
- workgroup = WORKGROUP
- server role = standalone server
- dns proxy = no
-
- pam password change = yes
- map to guest = bad user
- create mask = 0664
- force create mode = 0664
- directory mask = 0775
- force directory mode = 0775
- follow symlinks = yes
- '';
-
- # ^^ `samba4Full` is compiled with avahi, ldap, AD etc support compared to the default package, `samba`
- # Required for samba to register mDNS records for auto discovery
- # See https://github.com/NixOS/nixpkgs/blob/592047fc9e4f7b74a4dc85d1b9f5243dfe4899e3/pkgs/top-level/all-packages.nix#L27268
- enable = true;
- # openFirewall = true;
- shares.test = {
- browseable = "yes";
- "read only" = "no";
- "guest ok" = "no";
- path = "/test2";
- writable = "true";
- comment = "Eternor";
- "valid users" = "@smbtest2";
- };
- };
-
-
- services.avahi = {
- publish.enable = true;
- publish.userServices = true;
- # ^^ Needed to allow samba to automatically register mDNS records without the need for an `extraServiceFile`
- nssmdns = true;
- # ^^ Not one hundred percent sure if this is needed- if it aint broke, don't fix it
- enable = true;
- };
+ }
- services.samba-wsdd = {
- # This enables autodiscovery on windows since SMB1 (and thus netbios) support was discontinued
- enable = true;
- };
+#+end_src
+**** Paperless
+:PROPERTIES:
+:CUSTOM_ID: h:17b9ba9d-94c9-44d5-99dd-776174d4bcc9
+:END:
+***** NixOS
+:PROPERTIES:
+:CUSTOM_ID: h:1fc355ca-ca8c-4b02-ab3f-5656f2992112
+:END:
+#+begin_src nix :noweb yes :tangle profiles/server1/paperless/nixos.nix
+ { config, pkgs, modulesPath, ... }:
+ {
+ <>
+ users.groups.lxc_shares = {
+ gid = 10000;
+ members = [
+ "paperless"
+ "root"
+ ];
+ };
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ ];
+ networking.hostName = "paperless"; # Define your hostname.
+ networking.firewall.enable = false;
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/root/.dotfiles/secrets/paperless/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.admin = { owner = "paperless";};
+ services.paperless = {
+ enable = true;
+ mediaDir = "/media";
+ user = "paperless";
+ port = 28981;
+ passwordFile = config.sops.secrets.admin.path;
+ address = "0.0.0.0";
+ extraConfig = {
+ PAPERLESS_OCR_LANGUAGE = "deu+eng";
+ PAPERLESS_URL = "scan.swarsel.win";
+ PAPERLESS_OCR_USER_ARGS = builtins.toJSON {
+ optimize = 1;
+ pdfa_image_compression = "lossless";
+ };
+ };
+ };
- }
+ }
#+end_src
+
** Common NixOS
:PROPERTIES:
:CUSTOM_ID: h:1c1250cd-e9b4-4715-8d9f-eb09e64bfc7f
@@ -4470,6 +4470,9 @@ Next, we need to make sure that flakes stay enabled when we rebuild the configur
#+end_src
**** Make users non-mutable
+:PROPERTIES:
+:CUSTOM_ID: h:48959890-fbc7-4d28-b33c-f33e028ab473
+:END:
This ensures that all user-configuration happens here in the config file.
@@ -4544,6 +4547,9 @@ Needed for control over system-wide privileges etc.
#+end_src
**** Enable automatic garbage collection
+:PROPERTIES:
+:CUSTOM_ID: h:9a3b7f1f-d0c3-417e-a262-c920fb25f3ee
+:END:
The nix store fills up over time, until =/boot/efi= is filled. This snippet cleans it automatically on a weekly basis.
@@ -4559,6 +4565,9 @@ The nix store fills up over time, until =/boot/efi= is filled. This snippet clea
#+end_src
**** Enable automatic store optimisation
+:PROPERTIES:
+:CUSTOM_ID: h:97a2b9f7-c835-4db8-a0e9-e923bab69ee8
+:END:
This enables hardlinking identical files in the nix store, to save on disk space. I have read this incurs a significant I/O overhead, I need to keep an eye on this.
@@ -7890,2545 +7899,3112 @@ I also define some keybinds to some combinations directly. Those are used mostly
"" 'down-list
))
- ;; General often used hotkeys
- (general-define-key
- "C-M-a" (lambda () (interactive) (org-capture nil "a")) ; make new anki card
- ;; "C-M-d" 'swarsel-obsidian-daily ; open daily obsidian file and create if not exist
- ;; "C-M-S" 'swarsel-anki-set-deck-and-notetype ; switch deck and notetype for new anki cards
- ;; "C-M-s" 'markdown-download-screenshot ; wrapper for org-download-screenshot
- "C-c d" 'crux-duplicate-current-line-or-region
- "C-c D" 'crux-duplicate-and-comment-current-line-or-region
- "" 'swarsel/last-buffer
- "M-\\" 'indent-region
- "C-" 'my-python-shell-run
- )
+ ;; General often used hotkeys
+ (general-define-key
+ "C-M-a" (lambda () (interactive) (org-capture nil "a")) ; make new anki card
+ ;; "C-M-d" 'swarsel-obsidian-daily ; open daily obsidian file and create if not exist
+ ;; "C-M-S" 'swarsel-anki-set-deck-and-notetype ; switch deck and notetype for new anki cards
+ ;; "C-M-s" 'markdown-download-screenshot ; wrapper for org-download-screenshot
+ "C-c d" 'crux-duplicate-current-line-or-region
+ "C-c D" 'crux-duplicate-and-comment-current-line-or-region
+ "" 'swarsel/last-buffer
+ "M-\\" 'indent-region
+ "C-" 'my-python-shell-run
+ )
+
+#+end_src
+*** Directory setup / File structure
+:PROPERTIES:
+:CUSTOM_ID: h:07951589-54ba-4e3e-bd7b-4106cd22ff6a
+:END:
+
+In this section I setup some aliases that I use for various directories on my system. Some of these are actually used for magit repository finding etc., but many of them serve no real use and I need to clean this up someday.
+
+#+begin_src emacs-lisp
+
+ ;; set Nextcloud directory for journals etc.
+ (setq swarsel-sync-directory "~/Nextcloud"
+ swarsel-emacs-directory "~/.emacs.d"
+ swarsel-dotfiles-directory "~/.dotfiles"
+ swarsel-projects-directory "~/Documents/GitHub")
+
+ (setq swarsel-emacs-org-filepath (expand-file-name "Emacs.org" swarsel-dotfiles-directory)
+ swarsel-nix-org-filepath (expand-file-name "Nix.org" swarsel-dotfiles-directory)
+ swarsel-swarsel-org-filepath (expand-file-name "SwarselSystems.org" swarsel-dotfiles-directory)
+ )
+
+
+ ;; set Emacs main configuration .org names
+ (setq swarsel-emacs-org-file "Emacs.org"
+ swarsel-anki-org-file "Anki.org"
+ swarsel-tasks-org-file "Tasks.org"
+ swarsel-archive-org-file "Archive.org"
+ swarsel-org-folder-name "Org"
+ swarsel-obsidian-daily-folder-name "⭐ Personal/Journal"
+ swarsel-obsidian-folder-name "Obsidian"
+ swarsel-obsidian-vault-name "Main")
+
+
+ ;; set directory paths
+ (setq swarsel-org-directory (expand-file-name swarsel-org-folder-name swarsel-sync-directory)) ; path to org folder
+ (setq swarsel-obsidian-directory (expand-file-name swarsel-obsidian-folder-name swarsel-sync-directory)) ; path to obsidian
+ (setq swarsel-obsidian-vault-directory (expand-file-name swarsel-obsidian-vault-name swarsel-obsidian-directory)) ; path to obsidian vault
+ (setq swarsel-obsidian-daily-directory (expand-file-name swarsel-obsidian-daily-folder-name swarsel-obsidian-vault-directory)) ; path to obsidian daily folder
+
+ ;; filepaths to certain documents
+ (setq swarsel-org-anki-filepath (expand-file-name swarsel-anki-org-file swarsel-org-directory) ; path to anki export file
+ swarsel-org-tasks-filepath (expand-file-name swarsel-tasks-org-file swarsel-org-directory)
+ swarsel-org-archive-filepath (expand-file-name swarsel-archive-org-file swarsel-org-directory))
+
+
+
+#+end_src
+
+*** Unclutter .emacs.d
+:PROPERTIES:
+:CUSTOM_ID: h:0cf30b76-91d9-41da-a10b-74199bc36d40
+:END:
+
+In this section I move the =custom.el= out of it's standard location in =.emacs.d=. Firstly, I dislike using this file at all since I would rather have fully stateful configuration as commanded by this file. Secondly, this file is too easily permanently changed. Recently I figured out the last bits that I needed to remove from custom.el to no longer be reliant on it, so I now just write it to a temporary file (through =make-temp=file=) which will be cleaned on shutdown. However, I like to retain the custom framework because it is nice for testing out theme customizations, hence why I still load the file.
+
+This section also sets the emacs directory to the =~/.cache/= directory which is useful for files that I do not want to have lying around in my =.emacs.d=.
+
+#+begin_src emacs-lisp
+
+ ;; Change the user-emacs-directory to keep unwanted things out of ~/.emacs.d
+ (setq user-emacs-directory (expand-file-name "~/.cache/emacs/")
+ url-history-file (expand-file-name "url/history" user-emacs-directory))
+
+ ;; Use no-littering to automatically set common paths to the new user-emacs-directory
+ (use-package no-littering)
+ (setq custom-file (make-temp-file "emacs-custom-"))
+ (load custom-file t)
+
+#+end_src
+
+*** Move backup files to another location
+:PROPERTIES:
+:CUSTOM_ID: h:329f529a-ef9f-4787-b311-1c485e05b754
+:END:
+
+Many people dislike the Emacs backup files; I do enjoy them, but have to admit that they clutter the filesystem a little too much. Also, I rarely need to access these over different sessions. Hence I move them to =/tmp= - if Emacs unexpectedly crashes, the files can be recovered, but the backup files will not gather everywhere and will be deleted upon shutdown.
+
+#+begin_src emacs-lisp
+
+ (let ((backup-dir "~/tmp/emacs/backups")
+ (auto-saves-dir "~/tmp/emacs/auto-saves/"))
+ (dolist (dir (list backup-dir auto-saves-dir))
+ (when (not (file-directory-p dir))
+ (make-directory dir t)))
+ (setq backup-directory-alist `(("." . ,backup-dir))
+ auto-save-file-name-transforms `((".*" ,auto-saves-dir t))
+ auto-save-list-file-prefix (concat auto-saves-dir ".saves-")
+ tramp-backup-directory-alist `((".*" . ,backup-dir))
+ tramp-auto-save-directory auto-saves-dir))
+
+ (setq backup-by-copying t ; Don't delink hardlinks
+ delete-old-versions t ; Clean up the backups
+ version-control t ; Use version numbers on backups,
+ kept-new-versions 5 ; keep some new versions
+ kept-old-versions 2) ; and some old ones, too
+
+#+end_src
+** General init.el setup + UI
+:PROPERTIES:
+:CUSTOM_ID: h:786b447d-03ad-4c1d-b114-c37caa2d591c
+:END:
+
+In this general section I have settings that I either consider to be integral to my experience when using emacs or have no other section that I feel they belong to.
+
+*** General setup
+:PROPERTIES:
+:CUSTOM_ID: h:76a5bd78-a20d-4068-bea8-a38fdb26428e
+:END:
+
+Here I set up some things that are too minor to put under other categories.
+- Firstly we disable to having to type `yes` and `no` and switch it to `y` and `n`.
+- We also enable the marking of trailing whitespaces.
+- Also, make emacs highlight the current line globally
+- Emacs defaults to pausing all display redrawing on any input. This may have been useful previously, but is not necessary nowadays.
+- I also disable the suspend-frame function, as I never use it and it is quite confusing when accidentally hitting the keys for it.
+
+#+begin_src emacs-lisp
+
+ ;; use UTF-8 everywhere
+ (set-language-environment "UTF-8")
+
+ ;; set default font size
+ (defvar swarsel/default-font-size 130)
+ (setq swarsel-standard-font "FiraCode Nerd Font Mono"
+ swarsel-alt-font "FiraCode Nerd Font Mono")
+
+ ;; (defalias 'yes-or-no-p 'y-or-n-p)
+ ;;(setq-default show-trailing-whitespace t)
+ (add-hook 'before-save-hook 'delete-trailing-whitespace)
+ (global-hl-line-mode 1)
+ ;; (setq redisplay-dont-pause t) ;; obsolete
+ (setq blink-cursor-mode nil) ;; blink-cursor is an unexpected source of slowdown
+ (global-subword-mode 1) ; Iterate through CamelCase words
+ (setq blink-matching-paren nil) ;; this makes the cursor jump around annoyingly
+ (delete-selection-mode 1)
+ (setq vc-follow-symlinks t)
+ (setq require-final-newline t)
+ (winner-mode 1)
+ (setq load-prefer-newer t)
+
+ (setq undo-limit 80000000
+ evil-want-fine-undo t
+ auto-save-default t
+ password-cache-expiry nil
+ )
+ (setq browse-url-browser-function 'browse-url-firefox)
+ ;; disable a keybind that does more harm than good
+ (global-set-key [remap suspend-frame]
+ (lambda ()
+ (interactive)
+ (message "This keybinding is disabled (was 'suspend-frame')")))
+
+ (setq visible-bell nil)
+ (setq initial-major-mode 'fundamental-mode
+ initial-scratch-message nil)
+
+ (add-hook 'prog-mode-hook 'display-line-numbers-mode)
+ (add-hook 'text-mode-hook 'display-line-numbers-mode)
+ (global-visual-line-mode 1)
+
+#+end_src
+
+*** Mark all themes as safe
+:PROPERTIES:
+:CUSTOM_ID: h:0debe8fd-b319-4ab7-a92c-784fa7896b75
+:END:
+
+Normally when switching themes in emacs, the user will be warned that themes can run malicious code. I only run one theme really and deem it safe. It is however annoying to be asked this on every new system and it also creates lines in custom.el to answer that query, so here I declare all themes as safe.
+
+#+begin_src emacs-lisp
+
+ (setq custom-safe-themes t)
+
+#+end_src
+*** Show less compilation warnings
+:PROPERTIES:
+:CUSTOM_ID: h:b587e869-9911-443b-bc6d-8fb3ce31908d
+:END:
+
+When Emacs compiles stuff, it often shows a bunch of warnings that I do not need to deal with. Here we silence those. Some will be disabled completely, and some only when we have native compilation available (which should be most of the time, however).
+
+#+begin_src emacs-lisp
+
+ (setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
+ ;; Make native compilation silent and prune its cache.
+ (when (native-comp-available-p)
+ (setq native-comp-async-report-warnings-errors 'silent) ; Emacs 28 with native compilation
+ (setq native-compile-prune-cache t)) ; Emacs 29
+
+#+end_src
+
+*** Indentation
+:PROPERTIES:
+:CUSTOM_ID: h:6527b3ce-b76d-431a-9960-a57da7c53e1b
+:END:
+
+Here I define several options related to indentation; I first make it so that only whitespace will be used instead of tab characters for indentation, and I also set a small standard indent.
+
+We set =tab-always-indent= to ='complete= in order to indent first and then do completion if there are any. Also we make it so that python will not complain about missing indentation info.
+
+Lastly, I load the =highlight-indent-guides= package. This adds a neat visual indicator of the indentation level, which is useful for languages like python.
+
+#+begin_src emacs-lisp
+
+ (setq-default indent-tabs-mode nil
+ tab-width 2)
+
+ (setq tab-always-indent 'complete)
+ (setq python-indent-guess-indent-offset-verbose nil)
+
+ (use-package highlight-indent-guides
+ :hook (prog-mode . highlight-indent-guides-mode)
+ :init
+ (setq highlight-indent-guides-method 'column)
+ (setq highlight-indent-guides-responsive 'top)
+ )
+ (with-eval-after-load 'highlight-indent-guides
+ (set-face-attribute 'highlight-indent-guides-even-face nil :background "gray10")
+ (set-face-attribute 'highlight-indent-guides-odd-face nil :background "gray20")
+ (set-face-attribute 'highlight-indent-guides-stack-even-face nil :background "gray40")
+ (set-face-attribute 'highlight-indent-guides-stack-odd-face nil :background "gray50"))
#+end_src
-*** Directory setup / File structure
+
+*** Scrolling
:PROPERTIES:
-:CUSTOM_ID: h:07951589-54ba-4e3e-bd7b-4106cd22ff6a
+:CUSTOM_ID: h:3dc9fb1d-cd16-4bd0-a9ac-55a944415a90
:END:
-In this section I setup some aliases that I use for various directories on my system. Some of these are actually used for magit repository finding etc., but many of them serve no real use and I need to clean this up someday.
+By default, emacs scrolls half a page when reaching the bottom of the buffer. This is extremely annoying. This sets up more granular scrolling that allows scrolling with a mouse wheel or the two-finger touchscreen gesture. This now also works in buffers with a very small frame.
#+begin_src emacs-lisp
- ;; set Nextcloud directory for journals etc.
- (setq swarsel-sync-directory "~/Nextcloud"
- swarsel-emacs-directory "~/.emacs.d"
- swarsel-dotfiles-directory "~/.dotfiles"
- swarsel-projects-directory "~/Documents/GitHub")
+ (setq mouse-wheel-scroll-amount
+ '(1
+ ((shift) . 5)
+ ((meta) . 0.5)
+ ((control) . text-scale))
+ mouse-drag-copy-region nil
+ make-pointer-invisible t
+ mouse-wheel-progressive-speed t
+ mouse-wheel-follow-mouse t)
- (setq swarsel-emacs-org-filepath (expand-file-name "Emacs.org" swarsel-dotfiles-directory)
- swarsel-nix-org-filepath (expand-file-name "Nix.org" swarsel-dotfiles-directory)
- swarsel-swarsel-org-filepath (expand-file-name "SwarselSystems.org" swarsel-dotfiles-directory)
- )
+ (setq-default scroll-preserve-screen-position t
+ scroll-conservatively 1
+ scroll-margin 0
+ next-screen-context-lines 0)
+ (pixel-scroll-precision-mode 1)
- ;; set Emacs main configuration .org names
- (setq swarsel-emacs-org-file "Emacs.org"
- swarsel-anki-org-file "Anki.org"
- swarsel-tasks-org-file "Tasks.org"
- swarsel-archive-org-file "Archive.org"
- swarsel-org-folder-name "Org"
- swarsel-obsidian-daily-folder-name "⭐ Personal/Journal"
- swarsel-obsidian-folder-name "Obsidian"
- swarsel-obsidian-vault-name "Main")
+#+end_src
+*** Evil
+:PROPERTIES:
+:CUSTOM_ID: h:5bf9f014-ee96-42da-b285-7b34f04e6bb1
+:END:
- ;; set directory paths
- (setq swarsel-org-directory (expand-file-name swarsel-org-folder-name swarsel-sync-directory)) ; path to org folder
- (setq swarsel-obsidian-directory (expand-file-name swarsel-obsidian-folder-name swarsel-sync-directory)) ; path to obsidian
- (setq swarsel-obsidian-vault-directory (expand-file-name swarsel-obsidian-vault-name swarsel-obsidian-directory)) ; path to obsidian vault
- (setq swarsel-obsidian-daily-directory (expand-file-name swarsel-obsidian-daily-folder-name swarsel-obsidian-vault-directory)) ; path to obsidian daily folder
+**** General evil
+:PROPERTIES:
+:CUSTOM_ID: h:218376e8-086b-46bf-91b3-78295d5d440f
+:END:
- ;; filepaths to certain documents
- (setq swarsel-org-anki-filepath (expand-file-name swarsel-anki-org-file swarsel-org-directory) ; path to anki export file
- swarsel-org-tasks-filepath (expand-file-name swarsel-tasks-org-file swarsel-org-directory)
- swarsel-org-archive-filepath (expand-file-name swarsel-archive-org-file swarsel-org-directory))
+This setups up evil, which brings vim-like keybindings to emacs. In the same location, I also unbind the =C-z= key (I am very unhappy with this implementation, but it is the only thing that works consistently so far) to make it available for [[#h:c3cc1c12-3ab8-42b7-be07-63f54eac397f][cape]] later.
+Also, I setup initial modes for several major-modes depending on what I deem fit.
+#+begin_src emacs-lisp
-#+end_src
+ ;; Emulate vim in emacs
+ (use-package evil
+ :init
+ (setq evil-want-integration t) ; loads evil
+ (setq evil-want-keybinding nil) ; loads "helpful bindings" for other modes
+ (setq evil-want-C-u-scroll t) ; scrolling using C-u
+ (setq evil-want-C-i-jump nil) ; jumping with C-i
+ (setq evil-want-Y-yank-to-eol t) ; give Y some utility
+ (setq evil-shift-width 2) ; uniform indent
+ (setq evil-respect-visual-line-mode t) ; i am torn on this one
+ (setq evil-split-window-below t)
+ (setq evil-vsplit-window-right t)
+ :config
+ (evil-mode 1)
+ (define-key evil-normal-state-map (kbd "C-z") nil)
+ (define-key evil-insert-state-map (kbd "C-z") nil)
+ (define-key evil-visual-state-map (kbd "C-z") nil)
+ (define-key evil-motion-state-map (kbd "C-z") nil)
+ (define-key evil-operator-state-map (kbd "C-z") nil)
+ (define-key evil-replace-state-map (kbd "C-z") nil)
+ (define-key global-map (kbd "C-z") nil)
+ (evil-set-undo-system 'undo-tree)
-*** Unclutter .emacs.d
+ ;; Don't use evil-mode in these contexts, or use it in a specific mode
+ (evil-set-initial-state 'messages-buffer-mode 'emacs)
+ (evil-set-initial-state 'dashboard-mode 'emacs)
+ (evil-set-initial-state 'dired-mode 'emacs)
+ (evil-set-initial-state 'cfw:details-mode 'emacs)
+ (evil-set-initial-state 'Custom-mode 'emacs) ; god knows why this mode is in uppercase
+ (evil-set-initial-state 'mu4e-headers-mode 'normal)
+ (evil-set-initial-state 'python-inferior-mode 'normal)
+ (add-hook 'org-capture-mode-hook 'evil-insert-state)
+ (add-to-list 'evil-buffer-regexps '("COMMIT_EDITMSG" . insert)))
+
+#+end_src
+**** evil-collection
:PROPERTIES:
-:CUSTOM_ID: h:0cf30b76-91d9-41da-a10b-74199bc36d40
+:CUSTOM_ID: h:bde208f3-01ef-4dc6-9981-65f3d2a8189b
:END:
-In this section I move the =custom.el= out of it's standard location in =.emacs.d=. Firstly, I dislike using this file at all since I would rather have fully stateful configuration as commanded by this file. Secondly, this file is too easily permanently changed. Recently I figured out the last bits that I needed to remove from custom.el to no longer be reliant on it, so I now just write it to a temporary file (through =make-temp=file=) which will be cleaned on shutdown. However, I like to retain the custom framework because it is nice for testing out theme customizations, hence why I still load the file.
+This gives support for many different modes, and works beautifully out of the box.
-This section also sets the emacs directory to the =~/.cache/= directory which is useful for files that I do not want to have lying around in my =.emacs.d=.
+#+begin_src emacs-lisp
+
+ (use-package evil-collection
+ :after evil
+ :config
+ (evil-collection-init)
+ (setq forge-add-default-bindings nil))
+#+end_src
+**** evil-snipe
+:PROPERTIES:
+:CUSTOM_ID: h:d80e3f7d-0185-4a15-832b-d756e576265c
+:END:
+
+This package changes the char-search commands like =f= by showing the results in a more visual manner. It also gives a 2-character search using =s= and =S=.
#+begin_src emacs-lisp
+ ;; enables 2-char inline search
+ (use-package evil-snipe
+ :after evil
+ :demand
+ :config
+ (evil-snipe-mode +1)
+ ;; replace 1-char searches (f&t) with this better UI
+ (evil-snipe-override-mode +1))
+#+end_src
- ;; Change the user-emacs-directory to keep unwanted things out of ~/.emacs.d
- (setq user-emacs-directory (expand-file-name "~/.cache/emacs/")
- url-history-file (expand-file-name "url/history" user-emacs-directory))
+**** evil-cleverparens
+:PROPERTIES:
+:CUSTOM_ID: h:b06a378d-5248-4451-8eee-e65a3a768b1d
+:END:
- ;; Use no-littering to automatically set common paths to the new user-emacs-directory
- (use-package no-littering)
- (setq custom-file (make-temp-file "emacs-custom-"))
- (load custom-file t)
+This helps keeping parentheses balanced which is useful when writing in languages like Elisp. I do not activate this by default, as most languages do not profit from this enough in my eyes.
+
+#+begin_src emacs-lisp
+ ;; for parentheses-heavy languades modify evil commands to keep balance of parantheses
+ (use-package evil-cleverparens)
#+end_src
-*** Move backup files to another location
+**** evil-surround
:PROPERTIES:
-:CUSTOM_ID: h:329f529a-ef9f-4787-b311-1c485e05b754
+:CUSTOM_ID: h:aac82e5e-d882-4870-b644-ebdd0a2daae3
:END:
-Many people dislike the Emacs backup files; I do enjoy them, but have to admit that they clutter the filesystem a little too much. Also, I rarely need to access these over different sessions. Hence I move them to =/tmp= - if Emacs unexpectedly crashes, the files can be recovered, but the backup files will not gather everywhere and will be deleted upon shutdown.
+This minor-mode adds functionality for doing better surround-commands; for example =ci[= will let you change the word within square brackets.
#+begin_src emacs-lisp
- (let ((backup-dir "~/tmp/emacs/backups")
- (auto-saves-dir "~/tmp/emacs/auto-saves/"))
- (dolist (dir (list backup-dir auto-saves-dir))
- (when (not (file-directory-p dir))
- (make-directory dir t)))
- (setq backup-directory-alist `(("." . ,backup-dir))
- auto-save-file-name-transforms `((".*" ,auto-saves-dir t))
- auto-save-list-file-prefix (concat auto-saves-dir ".saves-")
- tramp-backup-directory-alist `((".*" . ,backup-dir))
- tramp-auto-save-directory auto-saves-dir))
+ ;; enables surrounding text with S
+ (use-package evil-surround
+ :config
+ (global-evil-surround-mode 1))
- (setq backup-by-copying t ; Don't delink hardlinks
- delete-old-versions t ; Clean up the backups
- version-control t ; Use version numbers on backups,
- kept-new-versions 5 ; keep some new versions
- kept-old-versions 2) ; and some old ones, too
+#+end_src
+
+*** ispell
+:PROPERTIES:
+:CUSTOM_ID: h:e888d7a7-1755-4109-af11-5358b8cf140e
+:END:
+
+This should setup a wordlist that can be used as a dictionary. However, for some reason this does not work, and I will need to further investigate this issue.
+
+#+begin_src emacs-lisp
+
+ ;; set the NixOS wordlist by hand
+ (setq ispell-alternate-dictionary "/nix/store/gjmvnbs97cnw19wnqh9m075cdbhy8r8g-wordlist-WORDLIST")
#+end_src
-** General init.el setup + UI
+
+*** Font Configuration
:PROPERTIES:
-:CUSTOM_ID: h:786b447d-03ad-4c1d-b114-c37caa2d591c
+:CUSTOM_ID: h:60f87342-0491-4c56-8057-6f075cf35753
:END:
-In this general section I have settings that I either consider to be integral to my experience when using emacs or have no other section that I feel they belong to.
+Here I define my fonts to be used. Honestly I do not understand the face-attributes and pitches of emacs all too well. It seems this configuration works fine, but I might have to revisit this at some point in the future.
-*** General setup
+#+begin_src emacs-lisp
+
+ (dolist (face '(default fixed-pitch))
+ (set-face-attribute face nil
+ :font "FiraCode Nerd Font Mono"))
+ (add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono"))
+
+ (set-face-attribute 'default nil :height 100)
+ (set-face-attribute 'fixed-pitch nil :height 1.0)
+
+ (set-face-attribute 'variable-pitch nil
+ :family "IBM Plex Sans"
+ :weight 'regular
+ :height 1.06)
+
+ ;; these settings used to be in custom.el
+
+#+end_src
+
+*** Theme
:PROPERTIES:
-:CUSTOM_ID: h:76a5bd78-a20d-4068-bea8-a38fdb26428e
+:CUSTOM_ID: h:72a9704b-83d2-4b74-a1f6-d333203f62db
:END:
-Here I set up some things that are too minor to put under other categories.
-- Firstly we disable to having to type `yes` and `no` and switch it to `y` and `n`.
-- We also enable the marking of trailing whitespaces.
-- Also, make emacs highlight the current line globally
-- Emacs defaults to pausing all display redrawing on any input. This may have been useful previously, but is not necessary nowadays.
-- I also disable the suspend-frame function, as I never use it and it is quite confusing when accidentally hitting the keys for it.
+I have grown to love the =doom-citylights= theme and have modeled my whole system after it. Also solaire-mode is a nice mode that inverts the alt-faces with the normal faces for specific 'minor' buffers (like Help-buffers).
#+begin_src emacs-lisp
- ;; use UTF-8 everywhere
- (set-language-environment "UTF-8")
+ (use-package solaire-mode
+ :custom
+ (solaire-global-mode +1))
+
+ (use-package doom-themes
+ :hook
+ (server-after-make-frame . (lambda () (load-theme
+ 'doom-city-lights t)))
+ :config
+ (load-theme 'doom-city-lights t)
+ (doom-themes-treemacs-config)
+ (doom-themes-org-config))
+
+#+end_src
- ;; set default font size
- (defvar swarsel/default-font-size 130)
- (setq swarsel-standard-font "FiraCode Nerd Font Mono"
- swarsel-alt-font "FiraCode Nerd Font Mono")
+*** Icons
+:PROPERTIES:
+:CUSTOM_ID: h:eb0ea526-a83a-4664-b3a1-2b40d3a31493
+:END:
- ;; (defalias 'yes-or-no-p 'y-or-n-p)
- ;;(setq-default show-trailing-whitespace t)
- (add-hook 'before-save-hook 'delete-trailing-whitespace)
- (global-hl-line-mode 1)
- ;; (setq redisplay-dont-pause t) ;; obsolete
- (setq blink-cursor-mode nil) ;; blink-cursor is an unexpected source of slowdown
- (global-subword-mode 1) ; Iterate through CamelCase words
- (setq blink-matching-paren nil) ;; this makes the cursor jump around annoyingly
- (delete-selection-mode 1)
- (setq vc-follow-symlinks t)
- (setq require-final-newline t)
- (winner-mode 1)
- (setq load-prefer-newer t)
+This section loads the base icons used in my configuration. I am using =nerd-icons= over =all-the-icons= since the former seems to have more integrations with different packages than the latter.
- (setq undo-limit 80000000
- evil-want-fine-undo t
- auto-save-default t
- password-cache-expiry nil
- )
- (setq browse-url-browser-function 'browse-url-firefox)
- ;; disable a keybind that does more harm than good
- (global-set-key [remap suspend-frame]
- (lambda ()
- (interactive)
- (message "This keybinding is disabled (was 'suspend-frame')")))
+Used in:
+- [[#h:b190d512-bfb5-42ec-adec-8d86bab726ce][Vertico and friends]]
+- [[#h:5653d693-ecca-4c95-9633-66b9e3241070][IN USE Corfu]]
- (setq visible-bell nil)
- (setq initial-major-mode 'fundamental-mode
- initial-scratch-message nil)
+#+begin_src emacs-lisp
- (add-hook 'prog-mode-hook 'display-line-numbers-mode)
- (add-hook 'text-mode-hook 'display-line-numbers-mode)
- (global-visual-line-mode 1)
+ (use-package nerd-icons)
#+end_src
-*** Mark all themes as safe
+*** Variable Pitch Mode
:PROPERTIES:
-:CUSTOM_ID: h:0debe8fd-b319-4ab7-a92c-784fa7896b75
+:CUSTOM_ID: h:455ed7ac-ee7f-4f94-b857-f2c58b2282d0
:END:
-Normally when switching themes in emacs, the user will be warned that themes can run malicious code. I only run one theme really and deem it safe. It is however annoying to be asked this on every new system and it also creates lines in custom.el to answer that query, so here I declare all themes as safe.
+This minor mode allows mixing fixed and variable pitch fonts within the same buffer.
#+begin_src emacs-lisp
- (setq custom-safe-themes t)
+(use-package mixed-pitch
+ :custom
+ (mixed-pitch-set-height nil)
+ (mixed-pitch-variable-pitch-cursor nil)
+ :hook
+ (text-mode . mixed-pitch-mode))
+
#+end_src
-*** Show less compilation warnings
+
+*** Modeline
:PROPERTIES:
-:CUSTOM_ID: h:b587e869-9911-443b-bc6d-8fb3ce31908d
+:CUSTOM_ID: h:ed585848-875a-4673-910c-d2e1901dd95b
:END:
-When Emacs compiles stuff, it often shows a bunch of warnings that I do not need to deal with. Here we silence those. Some will be disabled completely, and some only when we have native compilation available (which should be most of the time, however).
+Here I set up the modeline with some information that I find useful. Specficially I am using the doom modeline. Most informations I disable for it, except for the cursor information (row + column) as well as a widget for =mu4e= and git information.
#+begin_src emacs-lisp
- (setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
- ;; Make native compilation silent and prune its cache.
- (when (native-comp-available-p)
- (setq native-comp-async-report-warnings-errors 'silent) ; Emacs 28 with native compilation
- (setq native-compile-prune-cache t)) ; Emacs 29
+ (use-package doom-modeline
+ :init
+ (doom-modeline-mode)
+ (column-number-mode)
+ :custom
+ ((doom-modeline-height 22)
+ (doom-modeline-indent-info nil)
+ (doom-modeline-buffer-encoding nil)))
+
#+end_src
-*** Indentation
+*** Helper Modes
:PROPERTIES:
-:CUSTOM_ID: h:6527b3ce-b76d-431a-9960-a57da7c53e1b
+:CUSTOM_ID: h:39ae01e9-8053-4f76-aa77-8cbbbcff9652
+:END:
+**** Vertico, Orderless, Marginalia, Consult, Embark
+:PROPERTIES:
+:CUSTOM_ID: h:b190d512-bfb5-42ec-adec-8d86bab726ce
:END:
-Here I define several options related to indentation; I first make it so that only whitespace will be used instead of tab characters for indentation, and I also set a small standard indent.
+This set of packages uses the default emacs completion framework and works together to provide a very nice user experience:
-We set =tab-always-indent= to ='complete= in order to indent first and then do completion if there are any. Also we make it so that python will not complain about missing indentation info.
+- Vertico simply provides a vertically stacking completion
+- Marginalia adds more information to completion results
+- Orderless allows for fuzzy matching
+- Consult provides better implementations for several user functions, e.g. =consult-line= or =consult-outline=
+- Embark allows acting on the results in the minibuffer while the completion is still ongoing - this is extremely useful since it allows to, for example, read the documentation for several functions without closing the help search. It can also collect the results of a grep operation into a seperate buffer that edits the result in their original location.
-Lastly, I load the =highlight-indent-guides= package. This adds a neat visual indicator of the indentation level, which is useful for languages like python.
+Nerd icons is originally enabled here: [[#h:eb0ea526-a83a-4664-b3a1-2b40d3a31493][Icons]]
-#+begin_src emacs-lisp
+***** vertico
+:PROPERTIES:
+:CUSTOM_ID: h:d7c7f597-f870-4e01-8f7e-27dd31dd245d
+:END:
- (setq-default indent-tabs-mode nil
- tab-width 2)
+#+begin_src emacs-lisp
- (setq tab-always-indent 'complete)
- (setq python-indent-guess-indent-offset-verbose nil)
+ (setq read-buffer-completion-ignore-case t
+ read-file-name-completion-ignore-case t
+ completion-ignore-case t)
- (use-package highlight-indent-guides
- :hook (prog-mode . highlight-indent-guides-mode)
+ (use-package vertico
+ :custom
+ (vertico-scroll-margin 0)
+ (vertico-count 10)
+ (vertico-resize t)
+ (vertico-cycle t)
:init
- (setq highlight-indent-guides-method 'column)
- (setq highlight-indent-guides-responsive 'top)
- )
-
- (with-eval-after-load 'highlight-indent-guides
- (set-face-attribute 'highlight-indent-guides-even-face nil :background "gray10")
- (set-face-attribute 'highlight-indent-guides-odd-face nil :background "gray20")
- (set-face-attribute 'highlight-indent-guides-stack-even-face nil :background "gray40")
- (set-face-attribute 'highlight-indent-guides-stack-odd-face nil :background "gray50"))
+ (vertico-mode)
+ (vertico-mouse-mode))
#+end_src
-*** Scrolling
+***** vertico-directory
:PROPERTIES:
-:CUSTOM_ID: h:3dc9fb1d-cd16-4bd0-a9ac-55a944415a90
+:CUSTOM_ID: h:10d4f2bd-8c72-430b-a9ed-9b5e279ec0b4
:END:
-By default, emacs scrolls half a page when reaching the bottom of the buffer. This is extremely annoying. This sets up more granular scrolling that allows scrolling with a mouse wheel or the two-finger touchscreen gesture. This now also works in buffers with a very small frame.
+This package allows for =Ido=-like directory navigation.
#+begin_src emacs-lisp
+ (use-package vertico-directory
+ :ensure nil
+ :after vertico
+ :bind (:map vertico-map
+ ("RET" . vertico-directory-enter)
+ ("C-DEL" . vertico-directory-delete-word)
+ ("DEL" . vertico-directory-delete-char))
+ ;; Tidy shadowed file names
+ :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
- (setq mouse-wheel-scroll-amount
- '(1
- ((shift) . 5)
- ((meta) . 0.5)
- ((control) . text-scale))
- mouse-drag-copy-region nil
- make-pointer-invisible t
- mouse-wheel-progressive-speed t
- mouse-wheel-follow-mouse t)
+#+end_src
- (setq-default scroll-preserve-screen-position t
- scroll-conservatively 1
- scroll-margin 0
- next-screen-context-lines 0)
+***** orderless
+:PROPERTIES:
+:CUSTOM_ID: h:211fc0bd-0d64-4577-97d8-6abc94435f04
+:END:
- (pixel-scroll-precision-mode 1)
+The completion styles that I chose here can possibly still be improved. I need to spend more time on this.
+
+#+begin_src emacs-lisp
+
+ (use-package orderless
+ :custom
+ (completion-styles '(orderless flex basic))
+ (completion-category-overrides '((file (styles . (partial-completion)))
+ (eglot (styles orderless)))))
#+end_src
-*** Evil
+***** consult
:PROPERTIES:
-:CUSTOM_ID: h:5bf9f014-ee96-42da-b285-7b34f04e6bb1
+:CUSTOM_ID: h:49ab82bf-812d-4fbe-a5b6-d3ad703fe32c
:END:
-**** General evil
+The big winner here are the convenient keybinds being setup here for general use. Also, I setup vim-navigation for minibuffer completions. =consult-buffer= is set twice because I am still used to that weird =C-M-j= command that I chose for =ivy-switch-buffer= when I first started using Emacs. I want to move to the other command but for now it is not feasible to delete the other one.
+
+#+begin_src emacs-lisp
+
+ (use-package consult
+ :config
+ (setq consult-fontify-max-size 1024)
+ :bind
+ (("C-x b" . consult-buffer)
+ ("C-c " . consult-global-mark)
+ ("C-c C-a" . consult-org-agenda)
+ ("C-x O" . consult-org-heading)
+ ("C-M-j" . consult-buffer)
+ ("C-s" . consult-line)
+ ("M-g M-g" . consult-goto-line)
+ ("M-g i" . consult-imenu)
+ ("M-s M-s" . consult-line-multi)
+ :map minibuffer-local-map
+ ("C-j" . next-line)
+ ("C-k" . previous-line)))
+
+#+end_src
+***** embark
:PROPERTIES:
-:CUSTOM_ID: h:218376e8-086b-46bf-91b3-78295d5d440f
+:CUSTOM_ID: h:1c564ee5-ccd7-48be-b69a-d963400c4704
:END:
-This setups up evil, which brings vim-like keybindings to emacs. In the same location, I also unbind the =C-z= key (I am very unhappy with this implementation, but it is the only thing that works consistently so far) to make it available for [[#h:c3cc1c12-3ab8-42b7-be07-63f54eac397f][cape]] later.
-
-Also, I setup initial modes for several major-modes depending on what I deem fit.
+I have stripped down the embark keybinds heavily. It is very useful to me even in it's current state, but it quickly becomes overwhelming. =embark-dwim= acts on a candidate without closing the minibuffer, which is very useful. =embark-act= lets the user choose from all actions, but has an overwhelming interface.
#+begin_src emacs-lisp
- ;; Emulate vim in emacs
- (use-package evil
- :init
- (setq evil-want-integration t) ; loads evil
- (setq evil-want-keybinding nil) ; loads "helpful bindings" for other modes
- (setq evil-want-C-u-scroll t) ; scrolling using C-u
- (setq evil-want-C-i-jump nil) ; jumping with C-i
- (setq evil-want-Y-yank-to-eol t) ; give Y some utility
- (setq evil-shift-width 2) ; uniform indent
- (setq evil-respect-visual-line-mode t) ; i am torn on this one
- (setq evil-split-window-below t)
- (setq evil-vsplit-window-right t)
- :config
- (evil-mode 1)
- (define-key evil-normal-state-map (kbd "C-z") nil)
- (define-key evil-insert-state-map (kbd "C-z") nil)
- (define-key evil-visual-state-map (kbd "C-z") nil)
- (define-key evil-motion-state-map (kbd "C-z") nil)
- (define-key evil-operator-state-map (kbd "C-z") nil)
- (define-key evil-replace-state-map (kbd "C-z") nil)
- (define-key global-map (kbd "C-z") nil)
- (evil-set-undo-system 'undo-tree)
-
- ;; Don't use evil-mode in these contexts, or use it in a specific mode
- (evil-set-initial-state 'messages-buffer-mode 'emacs)
- (evil-set-initial-state 'dashboard-mode 'emacs)
- (evil-set-initial-state 'dired-mode 'emacs)
- (evil-set-initial-state 'cfw:details-mode 'emacs)
- (evil-set-initial-state 'Custom-mode 'emacs) ; god knows why this mode is in uppercase
- (evil-set-initial-state 'mu4e-headers-mode 'normal)
- (evil-set-initial-state 'python-inferior-mode 'normal)
- (add-hook 'org-capture-mode-hook 'evil-insert-state)
- (add-to-list 'evil-buffer-regexps '("COMMIT_EDITMSG" . insert)))
+ (use-package embark
+ :bind
+ (("C-." . embark-act)
+ ("M-." . embark-dwim)
+ ("C-h B" . embark-bindings)
+ ("C-c c" . embark-collect))
+ :custom
+ (prefix-help-command #'embark-prefix-help-command)
+ (embark-quit-after-action '((t . nil)))
+ :config
+ (add-to-list 'display-buffer-alist
+ '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
+ nil
+ (window-parameters (mode-line-format . none)))))
#+end_src
-**** evil-collection
+***** embark-consult
:PROPERTIES:
-:CUSTOM_ID: h:bde208f3-01ef-4dc6-9981-65f3d2a8189b
+:CUSTOM_ID: h:6287551c-a6f7-4870-b3f3-210d6f038b6f
:END:
-This gives support for many different modes, and works beautifully out of the box.
+Provides previews for embark.
#+begin_src emacs-lisp
- (use-package evil-collection
- :after evil
- :config
- (evil-collection-init)
- (setq forge-add-default-bindings nil))
+ (use-package embark-consult
+ :after (embark consult)
+ :demand t ; only necessary if you have the hook below
+ ;; if you want to have consult previews as you move around an
+ ;; auto-updating embark collect buffer
+ :hook
+ (embark-collect-mode . consult-preview-at-point-mode))
#+end_src
-**** evil-snipe
+***** marginalia
:PROPERTIES:
-:CUSTOM_ID: h:d80e3f7d-0185-4a15-832b-d756e576265c
+:CUSTOM_ID: h:f32040a4-882f-4e6b-97f1-a0105c44c034
:END:
-This package changes the char-search commands like =f= by showing the results in a more visual manner. It also gives a 2-character search using =s= and =S=.
+I set the annotation-mode of marginalia to =heavy=. This gives even more information on the stuff that you are looking at. One thing I am missing from ivy is the highlighting on =mode=-commands based on the current state of the mode. Also, I do not understand all the shorthands used by marginalia yet.
#+begin_src emacs-lisp
- ;; enables 2-char inline search
- (use-package evil-snipe
- :after evil
- :demand
- :config
- (evil-snipe-mode +1)
- ;; replace 1-char searches (f&t) with this better UI
- (evil-snipe-override-mode +1))
-#+end_src
+ (use-package marginalia
+ :after vertico
+ :init
+ (marginalia-mode)
+ (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))
-**** evil-cleverparens
+#+end_src
+***** nerd-icons-completion
:PROPERTIES:
-:CUSTOM_ID: h:b06a378d-5248-4451-8eee-e65a3a768b1d
+:CUSTOM_ID: h:d70ec2fb-da43-4523-9ee4-774ececdb80e
:END:
-This helps keeping parentheses balanced which is useful when writing in languages like Elisp. I do not activate this by default, as most languages do not profit from this enough in my eyes.
+As stated above, this simply provides nerd-icons to the completion framework.
#+begin_src emacs-lisp
- ;; for parentheses-heavy languades modify evil commands to keep balance of parantheses
- (use-package evil-cleverparens)
+
+ (use-package nerd-icons-completion
+ :after (marginalia nerd-icons)
+ :hook (marginalia-mode . nerd-icons-completion-marginalia-setup)
+ :init
+ (nerd-icons-completion-mode))
+
#+end_src
-**** evil-surround
+**** Helpful + which-key: Better help defaults
:PROPERTIES:
-:CUSTOM_ID: h:aac82e5e-d882-4870-b644-ebdd0a2daae3
+:CUSTOM_ID: h:cbf6bd48-2503-489a-89da-e3359564e989
:END:
-This minor-mode adds functionality for doing better surround-commands; for example =ci[= will let you change the word within square brackets.
+This pair of packages provides information on keybinds in addition to function names, which makes it easier to remember keybinds (=which-key=). The =helpful= package provides a better =Help= framework for Emacs. For some reason, the Help windows are always being focused by the cursor even though I have set =help-window-select= to nil. I do not understand why.
#+begin_src emacs-lisp
- ;; enables surrounding text with S
- (use-package evil-surround
+ (use-package which-key
+ :init (which-key-mode)
+ :diminish which-key-mode
:config
- (global-evil-surround-mode 1))
+ (setq which-key-idle-delay 0.3))
+ (use-package helpful
+ :bind
+ (("C-h f" . helpful-callable)
+ ("C-h v" . helpful-variable)
+ ("C-h k" . helpful-key)
+ ("C-h C-." . helpful-at-point))
+ :config
+ (setq help-window-select nil))
#+end_src
-*** ispell
+*** Ligatures
:PROPERTIES:
-:CUSTOM_ID: h:e888d7a7-1755-4109-af11-5358b8cf140e
+:CUSTOM_ID: h:bbbd9cc8-3a84-4810-a3d5-b8536a5fbda1
:END:
-This should setup a wordlist that can be used as a dictionary. However, for some reason this does not work, and I will need to further investigate this issue.
+Personally, I think ligatures are fancy. With this mode, they stay 'cursorable'. However, I do not need them in all modes, so I only use them in programming modes.
#+begin_src emacs-lisp
- ;; set the NixOS wordlist by hand
- (setq ispell-alternate-dictionary "/nix/store/gjmvnbs97cnw19wnqh9m075cdbhy8r8g-wordlist-WORDLIST")
+ (use-package ligature
+ :init
+ (global-ligature-mode t)
+ :config
+ (ligature-set-ligatures 'prog-mode
+ '("|||>" "<|||" "<==>" "" "---" "-<<"
+ "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
+ "<--" "<-<" "<<=" "<<-" "<<<" "<+>" ">" "###" "#_(" "..<"
+ "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
+ "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
+ "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
+ ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
+ "<$" "<=" "<>" "<-" "<<" "<+" "" "#{" "#[" "#:" "#=" "#!"
+ "##" "#(" "#?" "#_" "%%" ".=" ".." ".?" "+>" "++" "?:" "?="
+ "?." "??" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)" "\\\\"
+ "://" ";;")))
#+end_src
-*** Font Configuration
+*** Popup (popper) + Shackle Buffers
:PROPERTIES:
-:CUSTOM_ID: h:60f87342-0491-4c56-8057-6f075cf35753
+:CUSTOM_ID: h:e9d40e63-0e1f-47df-98f7-5427992588a4
:END:
-Here I define my fonts to be used. Honestly I do not understand the face-attributes and pitches of emacs all too well. It seems this configuration works fine, but I might have to revisit this at some point in the future.
+The popper package allows to declare different buffers as 'popup-type', which sort of acts like a scratchpad. It can be toggled at any time using =popper-toggle= and the resulting frame can be freely customized (with =shackle=) to a certain size. It is also possible to prevent a buffer from appearing - I do this for example to the =*Warnings*= buffer, since usually I am not interested in it's output.
+
+=popper-echo-mode= shows all buffers that are currently stored as a popup in the echo area when a popup is opened - this is useful since you can cycle between all popup buffers.
#+begin_src emacs-lisp
- (dolist (face '(default fixed-pitch))
- (set-face-attribute face nil
- :font "FiraCode Nerd Font Mono"))
- (add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono"))
+ (use-package popper
+ :bind (("M-[" . popper-toggle))
+ :init
+ (setq popper-reference-buffers
+ '("\\*Messages\\*"
+ ("\\*Warnings\\*" . hide)
+ "Output\\*$"
+ "\\*Async Shell Command\\*"
+ "\\*Async-native-compile-log\\*"
+ help-mode
+ helpful-mode
+ "*Occur*"
+ "*scratch*"
+ "*julia*"
+ "*Python*"
+ "*rustic-compilation*"
+ "*cargo-run*"
+ ;; ("*tex-shell*" . hide)
+ (compilation-mode . hide)))
+ (popper-mode +1)
+ (popper-echo-mode +1))
- (set-face-attribute 'default nil :height 100)
- (set-face-attribute 'fixed-pitch nil :height 1.0)
+ (use-package shackle
+ :config
+ (setq shackle-rules '(("*Messages*" :select t :popup t :align right :size 0.3)
+ ("*Warnings*" :ignore t :popup t :align right :size 0.3)
+ ("*Occur*" :select t :popup t :align below :size 0.2)
+ ("*scratch*" :select t :popup t :align below :size 0.2)
+ ("*Python*" :select t :popup t :align below :size 0.2)
+ ("*rustic-compilation*" :select t :popup t :align below :size 0.4)
+ ("*cargo-run*" :select t :popup t :align below :size 0.2)
+ ("*tex-shell*" :ignore t :popup t :align below :size 0.2)
+ (helpful-mode :select t :popup t :align right :size 0.35)
+ (help-mode :select t :popup t :align right :size 0.4)))
+ (shackle-mode 1))
- (set-face-attribute 'variable-pitch nil
- :family "IBM Plex Sans"
- :weight 'regular
- :height 1.06)
+#+end_src
+*** Indicate first and last line of buffer
+:PROPERTIES:
+:CUSTOM_ID: h:a6d23c8c-125f-4e36-af30-ff0a1e0d5a28
+:END:
- ;; these settings used to be in custom.el
+This places little angled indicators on the fringe of a window which indicate buffer boundaries. This is not super useful, but makes use of a space that I want to keep for aesthetic reasons anyways and makes it a bit more useful in the process.
-#+end_src
+#+begin_src emacs-lisp
-*** Theme
+(setq-default indicate-buffer-boundaries t)
+
+#+end_src
+*** Authentication
:PROPERTIES:
-:CUSTOM_ID: h:72a9704b-83d2-4b74-a1f6-d333203f62db
+:CUSTOM_ID: h:053a36bf-168f-4f63-a0c4-f0139dc6cc3b
:END:
-I have grown to love the =doom-citylights= theme and have modeled my whole system after it. Also solaire-mode is a nice mode that inverts the alt-faces with the normal faces for specific 'minor' buffers (like Help-buffers).
+This defines the authentication sources used by =org-calfw= ([[#h:c760f04e-622f-4b3e-8916-53ca8cce6edc][Calendar]]) and [[#h:1a8585ed-d9f2-478f-a132-440ada1cde2c][Forge]].
#+begin_src emacs-lisp
- (use-package solaire-mode
- :custom
- (solaire-global-mode +1))
-
- (use-package doom-themes
- :hook
- (server-after-make-frame . (lambda () (load-theme
- 'doom-city-lights t)))
- :config
- (load-theme 'doom-city-lights t)
- (doom-themes-treemacs-config)
- (doom-themes-org-config))
+ (setq auth-sources '( "~/.emacs.d/.caldav" "~/.emacs.d/.authinfo.gpg")
+ auth-source-cache-expiry nil) ; default is 2h
#+end_src
+** Modules
+:PROPERTIES:
+:CUSTOM_ID: h:f2622fd3-7f14-47a8-8c21-33574fcbf14b
+:END:
-*** Icons
+This section houses all configuration bits that are related to a specific package that is not fundamental to my Emacs experience.
+
+At some point this will receive further sorting, but for now this is good enough.
+
+*** Org Mode
:PROPERTIES:
-:CUSTOM_ID: h:eb0ea526-a83a-4664-b3a1-2b40d3a31493
+:CUSTOM_ID: h:99544398-72af-4382-b8e1-01b2221baff4
:END:
-This section loads the base icons used in my configuration. I am using =nerd-icons= over =all-the-icons= since the former seems to have more integrations with different packages than the latter.
+org-mode is probably my most-used mode in Emcas. It acts as my organizer, config management tool and calender even.
-Used in:
-- [[#h:b190d512-bfb5-42ec-adec-8d86bab726ce][Vertico and friends]]
-- [[#h:5653d693-ecca-4c95-9633-66b9e3241070][IN USE Corfu]]
+Note that nearly all headings within the =Org-mode= heading are coded within the =use-package= setup, so be very careful about moving stuff about here.
+
+**** General org-mode
+:PROPERTIES:
+:CUSTOM_ID: h:877c9401-a354-4e44-a235-db1a90d19e00
+:END:
+
+This sets up the basic org-mode. I wrote a function to handle some of the initial org-mode behaviour in [[#h:06b77d28-3fd5-4554-8c7d-32c1b0ec8da5][org-mode setup.
+]]
+This part of the configuration mostly makes some aesthetic changes, enables neat LaTeX and points Emacs to some files that it needs for org-mode
+
+#+begin_src emacs-lisp
+
+ (use-package org
+ ;;:diminish (org-indent-mode)
+ :hook (org-mode . swarsel/org-mode-setup)
+ :bind
+ (("C-" . org-fold-outer)
+ ("C-c s" . org-store-link))
+ :config
+ (setq org-ellipsis " ⤵"
+ org-link-descriptive t
+ org-hide-emphasis-markers t)
+ (setq org-startup-folded t)
+ (setq org-support-shift-select t)
+
+ ;; (setq org-agenda-start-with-log-mode t)
+ ;; (setq org-log-done 'time)
+ ;; (setq org-log-into-drawer t)
+ (setq org-startup-with-inline-images t)
+ (setq org-image-actual-width nil)
+ (setq org-format-latex-options '(:foreground "White" :background default :scale 2.0 :html-foreground "Black" :html-background "Transparent" :html-scale 1.0 :matchers ("begin" "$1" "$" "$$" "\\(" "\\[")))
+
+#+end_src
+**** org-agenda
+:PROPERTIES:
+:CUSTOM_ID: h:2b3b4eb6-68a1-476d-b5d1-940a21484f1d
+:END:
+
+Here I setup a plethora of keywords, keybinds and paths to give my org-agenda more power.
#+begin_src emacs-lisp
- (use-package nerd-icons)
+ (setq org-agenda-files '("/home/swarsel/Nextcloud/Org/Tasks.org"
+ "/home/swarsel/Nextcloud/Org/Archive.org"
+ "/home/swarsel/Nextcloud/Org/Anki.org"
+ "/home/swarsel/Calendars/leon_cal.org"))
+
+ (setq org-refile-targets
+ '((swarsel-archive-org-file :maxlevel . 1)
+ (swarsel-anki-org-file :maxlevel . 1)
+ (swarsel-tasks-org-file :maxlevel . 1)))
+
+ (setq org-todo-keywords
+ '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)")
+ (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)" "WAIT(w@/!)" "HOLD(h)" "|" "COMPLETED(c)" "CANC(k@)")))
+
-#+end_src
+ ;; Configure custom agenda views
+ (setq org-agenda-custom-commands
+ '(("d" "Dashboard"
+ ((agenda "" ((org-deadline-warning-days 7)))
+ (todo "NEXT"
+ ((org-agenda-overriding-header "Next Tasks")))
+ (tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects")))))
-*** Variable Pitch Mode
-:PROPERTIES:
-:CUSTOM_ID: h:455ed7ac-ee7f-4f94-b857-f2c58b2282d0
-:END:
+ ("n" "Next Tasks"
+ ((todo "NEXT"
+ ((org-agenda-overriding-header "Next Tasks")))))
-This minor mode allows mixing fixed and variable pitch fonts within the same buffer.
+ ("W" "Work Tasks" tags-todo "+work-email")
-#+begin_src emacs-lisp
-(use-package mixed-pitch
- :custom
- (mixed-pitch-set-height nil)
- (mixed-pitch-variable-pitch-cursor nil)
- :hook
- (text-mode . mixed-pitch-mode))
+ ("w" "Workflow Status"
+ ((todo "WAIT"
+ ((org-agenda-overriding-header "Waiting on External")
+ (org-agenda-files org-agenda-files)))
+ (todo "REVIEW"
+ ((org-agenda-overriding-header "In Review")
+ (org-agenda-files org-agenda-files)))
+ (todo "PLAN"
+ ((org-agenda-overriding-header "In Planning")
+ (org-agenda-todo-list-sublevels nil)
+ (org-agenda-files org-agenda-files)))
+ (todo "BACKLOG"
+ ((org-agenda-overriding-header "Project Backlog")
+ (org-agenda-todo-list-sublevels nil)
+ (org-agenda-files org-agenda-files)))
+ (todo "READY"
+ ((org-agenda-overriding-header "Ready for Work")
+ (org-agenda-files org-agenda-files)))
+ (todo "ACTIVE"
+ ((org-agenda-overriding-header "Active Projects")
+ (org-agenda-files org-agenda-files)))
+ (todo "COMPLETED"
+ ((org-agenda-overriding-header "Completed Projects")
+ (org-agenda-files org-agenda-files)))
+ (todo "CANC"
+ ((org-agenda-overriding-header "Cancelled Projects")
+ (org-agenda-files org-agenda-files)))))))
#+end_src
-
-*** Modeline
+**** org capture templates
:PROPERTIES:
-:CUSTOM_ID: h:ed585848-875a-4673-910c-d2e1901dd95b
+:CUSTOM_ID: h:23183635-3d46-4d7d-8eda-e0a085b335ef
:END:
-Here I set up the modeline with some information that I find useful. Specficially I am using the doom modeline. Most informations I disable for it, except for the cursor information (row + column) as well as a widget for =mu4e= and git information.
+I wrote these capture templates to allow myself to quickly create Anki cards from within Emacs. I nearly never use this feature, but it cannot hurt to have.
#+begin_src emacs-lisp
- (use-package doom-modeline
- :init
- (doom-modeline-mode)
- (column-number-mode)
- :custom
- ((doom-modeline-height 22)
- (doom-modeline-indent-info nil)
- (doom-modeline-buffer-encoding nil)))
-
+ (setq org-capture-templates
+ `(
+ ("a" "Anki basic"
+ entry
+ (file+headline swarsel-org-anki-filepath "Dispatch")
+ (function swarsel-anki-make-template-string))
+ ("A" "Anki cloze"
+ entry
+ (file+headline org-swarsel-anki-file "Dispatch")
+ "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: Cloze\n:ANKI_DECK: 🦁 All::01 ❤️ Various::00 ✨ Allgemein\n:END:\n** Text\n%?\n** Extra\n")
+ ("t" "Tasks / Projects")
+ ("tt" "Task" entry (file+olp swarsel-org-tasks-filepath "Inbox")
+ "* TODO %?\n %U\n %a\n %i" :empty-lines 1)
+ ))
+ )
#+end_src
-*** Helper Modes
-:PROPERTIES:
-:CUSTOM_ID: h:39ae01e9-8053-4f76-aa77-8cbbbcff9652
-:END:
-**** Vertico, Orderless, Marginalia, Consult, Embark
+**** Font Faces
:PROPERTIES:
-:CUSTOM_ID: h:b190d512-bfb5-42ec-adec-8d86bab726ce
+:CUSTOM_ID: h:40528f5a-c8cd-471b-b862-4088e8e61860
:END:
-This set of packages uses the default emacs completion framework and works together to provide a very nice user experience:
+Again, my understanding of the font-faces in Emacs is limited. This is mostly just tuned so that my org-files look acceptable.
-- Vertico simply provides a vertically stacking completion
-- Marginalia adds more information to completion results
-- Orderless allows for fuzzy matching
-- Consult provides better implementations for several user functions, e.g. =consult-line= or =consult-outline=
-- Embark allows acting on the results in the minibuffer while the completion is still ongoing - this is extremely useful since it allows to, for example, read the documentation for several functions without closing the help search. It can also collect the results of a grep operation into a seperate buffer that edits the result in their original location.
+#+begin_src emacs-lisp
-Nerd icons is originally enabled here: [[#h:eb0ea526-a83a-4664-b3a1-2b40d3a31493][Icons]]
-***** vertico
-:PROPERTIES:
-:CUSTOM_ID: h:d7c7f597-f870-4e01-8f7e-27dd31dd245d
-:END:
-#+begin_src emacs-lisp
+ ;; Set faces for heading levels
+ (with-eval-after-load 'org-faces (dolist (face '((org-level-1 . 1.1)
+ (org-level-2 . 0.9)
+ (org-level-3 . 0.9)
+ (org-level-4 . 0.9)
+ (org-level-5 . 0.9)
+ (org-level-6 . 0.9)
+ (org-level-7 . 0.9)
+ (org-level-8 . 0.9)))
+ (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
- (setq read-buffer-completion-ignore-case t
- read-file-name-completion-ignore-case t
- completion-ignore-case t)
+ ;; Ensure that anything that should be fixed-pitch in Org files appears that way
+ (set-face-attribute 'org-block nil :inherit 'fixed-pitch)
+ (set-face-attribute 'org-table nil :inherit 'fixed-pitch)
+ (set-face-attribute 'org-formula nil :inherit 'fixed-pitch)
+ (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch))
+ (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
+ (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
+ (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
+ (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch))
- (use-package vertico
- :custom
- (vertico-scroll-margin 0)
- (vertico-count 10)
- (vertico-resize t)
- (vertico-cycle t)
- :init
- (vertico-mode)
- (vertico-mouse-mode))
#+end_src
-***** vertico-directory
+**** org-appear
:PROPERTIES:
-:CUSTOM_ID: h:10d4f2bd-8c72-430b-a9ed-9b5e279ec0b4
+:CUSTOM_ID: h:62829574-a069-44b8-afb3-401a268d2747
:END:
-This package allows for =Ido=-like directory navigation.
+This package makes emphasis-markers appear when the cursor moves over them. Very useful as I enjoy the clean look of not always seeing them, but it is annoying not to be able to edit them properly.
#+begin_src emacs-lisp
- (use-package vertico-directory
- :ensure nil
- :after vertico
- :bind (:map vertico-map
- ("RET" . vertico-directory-enter)
- ("C-DEL" . vertico-directory-delete-word)
- ("DEL" . vertico-directory-delete-char))
- ;; Tidy shadowed file names
- :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
+
+ (use-package org-appear
+ :hook (org-mode . org-appear-mode)
+ :init
+ (setq org-appear-autolinks t)
+ (setq org-appear-autokeywords t)
+ (setq org-appear-autoentities t)
+ (setq org-appear-autosubmarkers t))
#+end_src
-***** orderless
+**** Centered org-mode Buffers
:PROPERTIES:
-:CUSTOM_ID: h:211fc0bd-0d64-4577-97d8-6abc94435f04
+:CUSTOM_ID: h:bbcfa895-4d46-4b1d-b84e-f634e982c46e
:END:
-The completion styles that I chose here can possibly still be improved. I need to spend more time on this.
+I like org-mode buffers to be centered, as I do not find that enormous lines are of big use.
+
+Function definition in: [[#h:fa710375-2efe-49b4-af6a-a875aca6e4a2][Visual-fill column]]
#+begin_src emacs-lisp
- (use-package orderless
- :custom
- (completion-styles '(orderless flex basic))
- (completion-category-overrides '((file (styles . (partial-completion)))
- (eglot (styles orderless)))))
+ (use-package visual-fill-column
+ :hook (org-mode . swarsel/org-mode-visual-fill))
#+end_src
-***** consult
+**** Fix headings not folding sometimes
:PROPERTIES:
-:CUSTOM_ID: h:49ab82bf-812d-4fbe-a5b6-d3ad703fe32c
+:CUSTOM_ID: h:c1a0adea-ca97-43d7-b5a0-b856d2ebc9a8
:END:
-The big winner here are the convenient keybinds being setup here for general use. Also, I setup vim-navigation for minibuffer completions. =consult-buffer= is set twice because I am still used to that weird =C-M-j= command that I chose for =ivy-switch-buffer= when I first started using Emacs. I want to move to the other command but for now it is not feasible to delete the other one.
+There is a weird bug in org-mode that makes it so that headings were not folding correctly sometimes. This setting seems to fix it.
#+begin_src emacs-lisp
- (use-package consult
- :config
- (setq consult-fontify-max-size 1024)
- :bind
- (("C-x b" . consult-buffer)
- ("C-c " . consult-global-mark)
- ("C-c C-a" . consult-org-agenda)
- ("C-x O" . consult-org-heading)
- ("C-M-j" . consult-buffer)
- ("C-s" . consult-line)
- ("M-g M-g" . consult-goto-line)
- ("M-g i" . consult-imenu)
- ("M-s M-s" . consult-line-multi)
- :map minibuffer-local-map
- ("C-j" . next-line)
- ("C-k" . previous-line)))
+ (setq org-fold-core-style 'overlays)
#+end_src
-***** embark
+
+**** Babel
:PROPERTIES:
-:CUSTOM_ID: h:1c564ee5-ccd7-48be-b69a-d963400c4704
+:CUSTOM_ID: h:3e0b6da3-0497-4080-bb49-bab949c03bc4
:END:
-I have stripped down the embark keybinds heavily. It is very useful to me even in it's current state, but it quickly becomes overwhelming. =embark-dwim= acts on a candidate without closing the minibuffer, which is very useful. =embark-act= lets the user choose from all actions, but has an overwhelming interface.
-
-#+begin_src emacs-lisp
+org-babel allows to run blocks in other programming languages within an org-mode buffer, similar to what e.g. jupyterhub offers for python.
- (use-package embark
- :bind
- (("C-." . embark-act)
- ("M-." . embark-dwim)
- ("C-h B" . embark-bindings)
- ("C-c c" . embark-collect))
- :custom
- (prefix-help-command #'embark-prefix-help-command)
- (embark-quit-after-action '((t . nil)))
- :config
- (add-to-list 'display-buffer-alist
- '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
- nil
- (window-parameters (mode-line-format . none)))))
+It also offers a very useful utility of exporting org-mode buffers to different formats; the feature I enjoy most is what makes this file useful: the tangling functionality.
-#+end_src
-***** embark-consult
+***** Language Configuration
:PROPERTIES:
-:CUSTOM_ID: h:6287551c-a6f7-4870-b3f3-210d6f038b6f
+:CUSTOM_ID: h:5d5ed7be-ec5f-4e17-bbb8-820ab6a9961c
:END:
-Provides previews for embark.
+- This configures the languages that babel recognizes.
#+begin_src emacs-lisp
- (use-package embark-consult
- :after (embark consult)
- :demand t ; only necessary if you have the hook below
- ;; if you want to have consult previews as you move around an
- ;; auto-updating embark collect buffer
- :hook
- (embark-collect-mode . consult-preview-at-point-mode))
-#+end_src
-***** marginalia
-:PROPERTIES:
-:CUSTOM_ID: h:f32040a4-882f-4e6b-97f1-a0105c44c034
-:END:
-
-I set the annotation-mode of marginalia to =heavy=. This gives even more information on the stuff that you are looking at. One thing I am missing from ivy is the highlighting on =mode=-commands based on the current state of the mode. Also, I do not understand all the shorthands used by marginalia yet.
+ (org-babel-do-load-languages
+ 'org-babel-load-languages
+ '((emacs-lisp . t)
+ (python . t)
+ (js . t)
+ (shell . t)
+ ))
-#+begin_src emacs-lisp
- (use-package marginalia
- :after vertico
- :init
- (marginalia-mode)
- (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))
+ (push '("conf-unix" . conf-unix) org-src-lang-modes)
#+end_src
-***** nerd-icons-completion
+
+***** old easy structure templates
:PROPERTIES:
-:CUSTOM_ID: h:d70ec2fb-da43-4523-9ee4-774ececdb80e
+:CUSTOM_ID: h:d112ed66-b2dd-45cc-8d70-9cf6631f28a9
:END:
-As stated above, this simply provides nerd-icons to the completion framework.
+- org 9.2 changed the way structure templates work. This brings back the old way it worked.
-#+begin_src emacs-lisp
+ Usage: Type =<=, followed by one of the below keywords and press =RET=. The corresponding source block should appear.
- (use-package nerd-icons-completion
- :after (marginalia nerd-icons)
- :hook (marginalia-mode . nerd-icons-completion-marginalia-setup)
- :init
- (nerd-icons-completion-mode))
+ #+begin_src emacs-lisp
+ (require 'org-tempo)
+ (add-to-list 'org-structure-template-alist '("sh" . "src shell"))
+ (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
+ (add-to-list 'org-structure-template-alist '("py" . "src python :results output"))
+ (add-to-list 'org-structure-template-alist '("nix" . "src nix :tangle"))
-#+end_src
+ #+end_src
-**** Helpful + which-key: Better help defaults
+**** aucTex
:PROPERTIES:
-:CUSTOM_ID: h:cbf6bd48-2503-489a-89da-e3359564e989
+:CUSTOM_ID: h:4696e2fc-3296-47dc-8fc3-66912c329d4c
:END:
-This pair of packages provides information on keybinds in addition to function names, which makes it easier to remember keybinds (=which-key=). The =helpful= package provides a better =Help= framework for Emacs. For some reason, the Help windows are always being focused by the cursor even though I have set =help-window-select= to nil. I do not understand why.
+This provides several utilities for LaTeX in Emacs, including many completions and convenience functions for math-mode.
#+begin_src emacs-lisp
- (use-package which-key
- :init (which-key-mode)
- :diminish which-key-mode
- :config
- (setq which-key-idle-delay 0.3))
+ (use-package auctex)
+ (setq TeX-auto-save t)
+ (setq TeX-save-query nil)
+ (setq TeX-parse-self t)
+ (setq-default TeX-master nil)
+
+ (add-hook 'LaTeX-mode-hook 'visual-line-mode)
+ (add-hook 'LaTeX-mode-hook 'flyspell-mode)
+ (add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)
+ (add-hook 'LaTeX-mode-hook 'reftex-mode)
+ (setq LaTeX-electric-left-right-brace t)
+ (setq font-latex-fontify-script nil)
+ (setq TeX-electric-sub-and-superscript t)
+ ;; (setq reftex-plug-into-AUCTeX t)
- (use-package helpful
- :bind
- (("C-h f" . helpful-callable)
- ("C-h v" . helpful-variable)
- ("C-h k" . helpful-key)
- ("C-h C-." . helpful-at-point))
- :config
- (setq help-window-select nil))
#+end_src
-*** Ligatures
+**** org-download
:PROPERTIES:
-:CUSTOM_ID: h:bbbd9cc8-3a84-4810-a3d5-b8536a5fbda1
+:CUSTOM_ID: h:406e5ecb-66f0-49bf-85ca-8b499f73ec5b
:END:
-Personally, I think ligatures are fancy. With this mode, they stay 'cursorable'. However, I do not need them in all modes, so I only use them in programming modes.
+This package allows to download and copy images into org-mode buffers. Sadly it does not work in a very stable manner - if you copy images that are also links to another page (like is often the case in a Google image search), Emacs might crash from this.
#+begin_src emacs-lisp
- (use-package ligature
- :init
- (global-ligature-mode t)
+ (use-package org-download
+ :after org
+ :defer nil
+ :custom
+ (org-download-method 'directory)
+ (org-download-image-dir "./images")
+ (org-download-heading-lvl 0)
+ (org-download-timestamp "org_%Y%m%d-%H%M%S_")
+ ;;(org-image-actual-width 500)
+ (org-download-screenshot-method "grim -g \"$(slurp)\" %s")
+ :bind
+ ("C-M-y" . org-download-screenshot)
:config
- (ligature-set-ligatures 'prog-mode
- '("|||>" "<|||" "<==>" "" "---" "-<<"
- "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
- "<--" "<-<" "<<=" "<<-" "<<<" "<+>" ">" "###" "#_(" "..<"
- "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
- "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
- "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
- ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
- "<$" "<=" "<>" "<-" "<<" "<+" "" "#{" "#[" "#:" "#=" "#!"
- "##" "#(" "#?" "#_" "%%" ".=" ".." ".?" "+>" "++" "?:" "?="
- "?." "??" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)" "\\\\"
- "://" ";;")))
+ (require 'org-download))
#+end_src
-*** Popup (popper) + Shackle Buffers
+**** org-fragtog
:PROPERTIES:
-:CUSTOM_ID: h:e9d40e63-0e1f-47df-98f7-5427992588a4
+:CUSTOM_ID: h:a02b1162-3e19-46f1-8efc-9f375971645c
:END:
-The popper package allows to declare different buffers as 'popup-type', which sort of acts like a scratchpad. It can be toggled at any time using =popper-toggle= and the resulting frame can be freely customized (with =shackle=) to a certain size. It is also possible to prevent a buffer from appearing - I do this for example to the =*Warnings*= buffer, since usually I am not interested in it's output.
-
-=popper-echo-mode= shows all buffers that are currently stored as a popup in the echo area when a popup is opened - this is useful since you can cycle between all popup buffers.
+This package automatically toggles LaTeX-fragments in org-files. It seems to also work in markdown-files which is a nice addition, as my Obsidian notes are held in markdown.
#+begin_src emacs-lisp
- (use-package popper
- :bind (("M-[" . popper-toggle))
- :init
- (setq popper-reference-buffers
- '("\\*Messages\\*"
- ("\\*Warnings\\*" . hide)
- "Output\\*$"
- "\\*Async Shell Command\\*"
- "\\*Async-native-compile-log\\*"
- help-mode
- helpful-mode
- "*Occur*"
- "*scratch*"
- "*julia*"
- "*Python*"
- "*rustic-compilation*"
- "*cargo-run*"
- ;; ("*tex-shell*" . hide)
- (compilation-mode . hide)))
- (popper-mode +1)
- (popper-echo-mode +1))
-
- (use-package shackle
- :config
- (setq shackle-rules '(("*Messages*" :select t :popup t :align right :size 0.3)
- ("*Warnings*" :ignore t :popup t :align right :size 0.3)
- ("*Occur*" :select t :popup t :align below :size 0.2)
- ("*scratch*" :select t :popup t :align below :size 0.2)
- ("*Python*" :select t :popup t :align below :size 0.2)
- ("*rustic-compilation*" :select t :popup t :align below :size 0.4)
- ("*cargo-run*" :select t :popup t :align below :size 0.2)
- ("*tex-shell*" :ignore t :popup t :align below :size 0.2)
- (helpful-mode :select t :popup t :align right :size 0.35)
- (help-mode :select t :popup t :align right :size 0.4)))
- (shackle-mode 1))
+ (use-package org-fragtog)
+ (add-hook 'org-mode-hook 'org-fragtog-mode)
+ (add-hook 'markdown-mode-hook 'org-fragtog-mode)
#+end_src
-*** Indicate first and last line of buffer
+
+**** org-modern
:PROPERTIES:
-:CUSTOM_ID: h:a6d23c8c-125f-4e36-af30-ff0a1e0d5a28
+:CUSTOM_ID: h:95b42e77-767c-4461-9ba8-b1c1cd18266c
:END:
-This places little angled indicators on the fringe of a window which indicate buffer boundaries. This is not super useful, but makes use of a space that I want to keep for aesthetic reasons anyways and makes it a bit more useful in the process.
+This just makes org-mode a little bit more beautiful, mostly by making the =begin_src= and =end_src= tags in source-blocks turn into more beautiful icons, as well as hiding =#+= tags before them, as well as in the properties section of the file.
#+begin_src emacs-lisp
-(setq-default indicate-buffer-boundaries t)
+ (use-package org-modern
+ :config (setq org-modern-block-name
+ '((t . t)
+ ("src" "»" "∥")))
+ :hook (org-mode . org-modern-mode))
#+end_src
-*** Authentication
+
+**** Presentations
:PROPERTIES:
-:CUSTOM_ID: h:053a36bf-168f-4f63-a0c4-f0139dc6cc3b
+:CUSTOM_ID: h:4e11a845-a7bb-4eb5-b4ce-5b2f52e07425
:END:
-This defines the authentication sources used by =org-calfw= ([[#h:c760f04e-622f-4b3e-8916-53ca8cce6edc][Calendar]]) and [[#h:1a8585ed-d9f2-478f-a132-440ada1cde2c][Forge]].
+Recently I have grown fond of holding presentations using Emacs :)
#+begin_src emacs-lisp
- (setq auth-sources '( "~/.emacs.d/.caldav" "~/.emacs.d/.authinfo.gpg")
- auth-source-cache-expiry nil) ; default is 2h
+ (use-package org-present
+ :bind (:map org-present-mode-keymap
+ ("q" . org-present-quit)
+ ("" . swarsel/org-present-prev)
+ ("" . 'ignore)
+ ("" . 'ignore)
+ ("" . swarsel/org-present-next))
+ :hook ((org-present-mode . swarsel/org-present-start)
+ (org-present-mode-quit . swarsel/org-present-end))
+ )
-#+end_src
-** Modules
-:PROPERTIES:
-:CUSTOM_ID: h:f2622fd3-7f14-47a8-8c21-33574fcbf14b
-:END:
-This section houses all configuration bits that are related to a specific package that is not fundamental to my Emacs experience.
+ (use-package hide-mode-line)
-At some point this will receive further sorting, but for now this is good enough.
+ (defun swarsel/org-present-start ()
+ (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch)
+ (header-line (:height 4.0) variable-pitch)
+ (org-document-title (:height 1.75) org-document-title)
+ (org-code (:height 1.55) org-code)
+ (org-verbatim (:height 1.55) org-verbatim)
+ (org-block (:height 1.25) org-block)
+ (org-block-begin-line (:height 0.7) org-block)
+ ))
+ (dolist (face '((org-level-1 . 1.1)
+ (org-level-2 . 1.2)
+ (org-level-3 . 1.2)
+ (org-level-4 . 1.2)
+ (org-level-5 . 1.2)
+ (org-level-6 . 1.2)
+ (org-level-7 . 1.2)
+ (org-level-8 . 1.2)))
+ (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
-*** Org Mode
-:PROPERTIES:
-:CUSTOM_ID: h:99544398-72af-4382-b8e1-01b2221baff4
-:END:
+ (setq header-line-format " ")
+ (setq visual-fill-column-width 90)
+ (setq indicate-buffer-boundaries nil)
+ (setq inhibit-message nil)
+ (breadcrumb-mode 0)
+ (org-display-inline-images)
+ (global-hl-line-mode 0)
+ (display-line-numbers-mode 0)
+ (org-modern-mode 0)
+ (evil-insert-state 1)
+ (beginning-of-buffer)
+ (org-present-read-only)
+ ;; (org-present-hide-cursor)
+ (swarsel/org-present-slide)
+ )
+
+ (defun swarsel/org-present-end ()
+ (setq-local face-remapping-alist '((default variable-pitch default)))
+ (dolist (face '((org-level-1 . 1.1)
+ (org-level-2 . 0.9)
+ (org-level-3 . 0.9)
+ (org-level-4 . 0.9)
+ (org-level-5 . 0.9)
+ (org-level-6 . 0.9)
+ (org-level-7 . 0.9)
+ (org-level-8 . 0.9)))
+ (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
+ (setq header-line-format nil)
+ (setq visual-fill-column-width 150)
+ (setq indicate-buffer-boundaries t)
+ (setq inhibit-message nil)
+ (breadcrumb-mode 1)
+ (global-hl-line-mode 1)
+ (display-line-numbers-mode 1)
+ (org-remove-inline-images)
+ (org-modern-mode 1)
+ (evil-normal-state 1)
+ ;; (org-present-show-cursor)
+ )
+
+ (defun swarsel/org-present-slide ()
+ (org-overview)
+ (org-show-entry)
+ (org-show-children)
+ )
+
+ (defun swarsel/org-present-prev ()
+ (interactive)
+ (org-present-prev)
+ (swarsel/org-present-slide))
+
+ (defun swarsel/org-present-next ()
+ (interactive)
+ (unless (eobp)
+ (org-next-visible-heading 1)
+ (org-fold-show-entry))
+ (when (eobp)
+ (org-present-next)
+ (swarsel/org-present-slide)
+ ))
-org-mode is probably my most-used mode in Emcas. It acts as my organizer, config management tool and calender even.
+ (defun clojure-leave-clojure-mode-function ()
+ )
-Note that nearly all headings within the =Org-mode= heading are coded within the =use-package= setup, so be very careful about moving stuff about here.
+ (add-hook 'buffer-list-update-hook #'clojure-leave-clojure-mode-function)
+ (add-hook 'org-present-mode-hook 'swarsel/org-present-start)
+ (add-hook 'org-present-mode-quit-hook 'swarsel/org-present-end)
+ (add-hook 'org-present-after-navigate-functions 'swarsel/org-present-slide)
-**** General org-mode
+#+end_src
+*** Nix Mode
:PROPERTIES:
-:CUSTOM_ID: h:877c9401-a354-4e44-a235-db1a90d19e00
+:CUSTOM_ID: h:406c2ecc-0e3e-4d9f-9ae3-3eb1f8b87d1b
:END:
-This sets up the basic org-mode. I wrote a function to handle some of the initial org-mode behaviour in [[#h:06b77d28-3fd5-4554-8c7d-32c1b0ec8da5][org-mode setup.
-]]
-This part of the configuration mostly makes some aesthetic changes, enables neat LaTeX and points Emacs to some files that it needs for org-mode
+This adds a rudimentary nix-mode to Emacs. I have not really tried this out, as I am mostly editing nix-files in org-mode anyways.
#+begin_src emacs-lisp
- (use-package org
- ;;:diminish (org-indent-mode)
- :hook (org-mode . swarsel/org-mode-setup)
- :bind
- (("C-" . org-fold-outer)
- ("C-c s" . org-store-link))
- :config
- (setq org-ellipsis " ⤵"
- org-link-descriptive t
- org-hide-emphasis-markers t)
- (setq org-startup-folded t)
- (setq org-support-shift-select t)
-
- ;; (setq org-agenda-start-with-log-mode t)
- ;; (setq org-log-done 'time)
- ;; (setq org-log-into-drawer t)
- (setq org-startup-with-inline-images t)
- (setq org-image-actual-width nil)
- (setq org-format-latex-options '(:foreground "White" :background default :scale 2.0 :html-foreground "Black" :html-background "Transparent" :html-scale 1.0 :matchers ("begin" "$1" "$" "$$" "\\(" "\\[")))
+ (use-package nix-mode
+ :mode "\\.nix\\'")
#+end_src
-**** org-agenda
+
+*** Markdown Mode
:PROPERTIES:
-:CUSTOM_ID: h:2b3b4eb6-68a1-476d-b5d1-940a21484f1d
+:CUSTOM_ID: h:50327461-a11b-4e81-830a-90febc720cfa
+:END:
+**** Mode
+:PROPERTIES:
+:CUSTOM_ID: h:734dc40a-a2c4-4839-b884-cb99b81aa6fe
:END:
-
-Here I setup a plethora of keywords, keybinds and paths to give my org-agenda more power.
#+begin_src emacs-lisp
- (setq org-agenda-files '("/home/swarsel/Nextcloud/Org/Tasks.org"
- "/home/swarsel/Nextcloud/Org/Archive.org"
- "/home/swarsel/Nextcloud/Org/Anki.org"
- "/home/swarsel/Calendars/leon_cal.org"))
-
- (setq org-refile-targets
- '((swarsel-archive-org-file :maxlevel . 1)
- (swarsel-anki-org-file :maxlevel . 1)
- (swarsel-tasks-org-file :maxlevel . 1)))
-
- (setq org-todo-keywords
- '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)")
- (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)" "WAIT(w@/!)" "HOLD(h)" "|" "COMPLETED(c)" "CANC(k@)")))
-
-
- ;; Configure custom agenda views
- (setq org-agenda-custom-commands
- '(("d" "Dashboard"
- ((agenda "" ((org-deadline-warning-days 7)))
- (todo "NEXT"
- ((org-agenda-overriding-header "Next Tasks")))
- (tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects")))))
+ (setq markdown-command "pandoc")
- ("n" "Next Tasks"
- ((todo "NEXT"
- ((org-agenda-overriding-header "Next Tasks")))))
+ (use-package markdown-mode
+ :ensure t
+ :mode ("README\\.md\\'" . gfm-mode)
+ :init (setq markdown-command "multimarkdown")
+ :bind (:map markdown-mode-map
+ ("C-c C-e" . markdown-do)))
- ("W" "Work Tasks" tags-todo "+work-email")
+#+end_src
+**** LaTeX in Markdown
+:PROPERTIES:
+:CUSTOM_ID: h:8d90fe51-0b32-423a-a159-4f853bc29b68
+:END:
- ("w" "Workflow Status"
- ((todo "WAIT"
- ((org-agenda-overriding-header "Waiting on External")
- (org-agenda-files org-agenda-files)))
- (todo "REVIEW"
- ((org-agenda-overriding-header "In Review")
- (org-agenda-files org-agenda-files)))
- (todo "PLAN"
- ((org-agenda-overriding-header "In Planning")
- (org-agenda-todo-list-sublevels nil)
- (org-agenda-files org-agenda-files)))
- (todo "BACKLOG"
- ((org-agenda-overriding-header "Project Backlog")
- (org-agenda-todo-list-sublevels nil)
- (org-agenda-files org-agenda-files)))
- (todo "READY"
- ((org-agenda-overriding-header "Ready for Work")
- (org-agenda-files org-agenda-files)))
- (todo "ACTIVE"
- ((org-agenda-overriding-header "Active Projects")
- (org-agenda-files org-agenda-files)))
- (todo "COMPLETED"
- ((org-agenda-overriding-header "Completed Projects")
- (org-agenda-files org-agenda-files)))
- (todo "CANC"
- ((org-agenda-overriding-header "Cancelled Projects")
- (org-agenda-files org-agenda-files)))))))
+#+begin_src emacs-lisp
+ (add-hook 'markdown-mode-hook
+ (lambda ()
+ (local-set-key (kbd "C-c C-x C-l") 'org-latex-preview)
+ (local-set-key (kbd "C-c C-x C-u") 'markdown-toggle-url-hiding)
+ ))
#+end_src
-**** org capture templates
+
+*** Olivetti
:PROPERTIES:
-:CUSTOM_ID: h:23183635-3d46-4d7d-8eda-e0a085b335ef
+:CUSTOM_ID: h:65e69741-9860-4ed0-bbed-7b7be9a2a9d6
:END:
-I wrote these capture templates to allow myself to quickly create Anki cards from within Emacs. I nearly never use this feature, but it cannot hurt to have.
+Olivetti is a mode specialized for writing prose in Emacs. I went for a very simple setup with little distractions.
+
+This mode is not automatically activated anywhere because I only rarely need it.
#+begin_src emacs-lisp
- (setq org-capture-templates
- `(
- ("a" "Anki basic"
- entry
- (file+headline swarsel-org-anki-filepath "Dispatch")
- (function swarsel-anki-make-template-string))
+ (use-package olivetti
+ :init
+ (setq olivetti-body-width 100)
+ (setq olivetti-recall-visual-line-mode-entry-state t))
- ("A" "Anki cloze"
- entry
- (file+headline org-swarsel-anki-file "Dispatch")
- "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: Cloze\n:ANKI_DECK: 🦁 All::01 ❤️ Various::00 ✨ Allgemein\n:END:\n** Text\n%?\n** Extra\n")
- ("t" "Tasks / Projects")
- ("tt" "Task" entry (file+olp swarsel-org-tasks-filepath "Inbox")
- "* TODO %?\n %U\n %a\n %i" :empty-lines 1)
- ))
- )
#+end_src
-**** Font Faces
+*** darkroom
:PROPERTIES:
-:CUSTOM_ID: h:40528f5a-c8cd-471b-b862-4088e8e61860
+:CUSTOM_ID: h:94d4a0dc-b0d7-4702-b760-beeaa6da2b8f
:END:
-Again, my understanding of the font-faces in Emacs is limited. This is mostly just tuned so that my org-files look acceptable.
+Darkroom is package that reduces all forms of distraction to a minimum - this can be useful when simply reading a file for example. For this mode I have increased the text scale by a large margin to make for comfortable reading
+This mode is not automatically activated anywhere because I only rarely need it.
#+begin_src emacs-lisp
-
-
- ;; Set faces for heading levels
- (with-eval-after-load 'org-faces (dolist (face '((org-level-1 . 1.1)
- (org-level-2 . 0.9)
- (org-level-3 . 0.9)
- (org-level-4 . 0.9)
- (org-level-5 . 0.9)
- (org-level-6 . 0.9)
- (org-level-7 . 0.9)
- (org-level-8 . 0.9)))
- (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
-
- ;; Ensure that anything that should be fixed-pitch in Org files appears that way
- (set-face-attribute 'org-block nil :inherit 'fixed-pitch)
- (set-face-attribute 'org-table nil :inherit 'fixed-pitch)
- (set-face-attribute 'org-formula nil :inherit 'fixed-pitch)
- (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch))
- (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
- (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
- (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
- (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch))
+(use-package darkroom
+ :init
+ (setq darkroom-text-scale-increase 3))
#+end_src
-**** org-appear
+*** Ripgrep
:PROPERTIES:
-:CUSTOM_ID: h:62829574-a069-44b8-afb3-401a268d2747
+:CUSTOM_ID: h:87453f1c-8ea5-4d0a-862d-8973d5bc5405
:END:
-This package makes emphasis-markers appear when the cursor moves over them. Very useful as I enjoy the clean look of not always seeing them, but it is annoying not to be able to edit them properly.
+This is the ripgrep command for Emacs.
#+begin_src emacs-lisp
- (use-package org-appear
- :hook (org-mode . org-appear-mode)
- :init
- (setq org-appear-autolinks t)
- (setq org-appear-autokeywords t)
- (setq org-appear-autoentities t)
- (setq org-appear-autosubmarkers t))
+ (use-package rg)
#+end_src
-
-**** Centered org-mode Buffers
+*** Tree-sitter
:PROPERTIES:
-:CUSTOM_ID: h:bbcfa895-4d46-4b1d-b84e-f634e982c46e
+:CUSTOM_ID: h:543641d0-02a9-459e-a2d6-96c8fcc06864
:END:
-I like org-mode buffers to be centered, as I do not find that enormous lines are of big use.
+Tree-sitter is a parsing library integrated into Emacs to provide better syntax highlighting and code analysis. It generates concrete syntax trees for source code, enabling more accurate and efficient text processing. Emacs' tree-sitter integration enhances language support, offering features like incremental parsing and precise syntax-aware editing. This improves the development experience by providing robust and dynamic syntax features, making it easier for me to navigate and manipulate code.
-Function definition in: [[#h:fa710375-2efe-49b4-af6a-a875aca6e4a2][Visual-fill column]]
+In order to update the language grammars, run the next command below.
-#+begin_src emacs-lisp
+#+begin_src emacs-lisp :tangle no :export both
- (use-package visual-fill-column
- :hook (org-mode . swarsel/org-mode-visual-fill))
+ (mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))
#+end_src
-**** Fix headings not folding sometimes
-:PROPERTIES:
-:CUSTOM_ID: h:c1a0adea-ca97-43d7-b5a0-b856d2ebc9a8
-:END:
-
-There is a weird bug in org-mode that makes it so that headings were not folding correctly sometimes. This setting seems to fix it.
+#+RESULTS:
+| bash | c | cmake | cpp | css | elisp | go | html | javascript | json | julia | latex | make | markdown | R | python | typescript | rust | sql | toml | tsx | yaml |
#+begin_src emacs-lisp
- (setq org-fold-core-style 'overlays)
-
-#+end_src
+ (use-package emacs
+ :ensure nil
+ :init
+ (setq treesit-language-source-alist
+ '((bash . ("https://github.com/tree-sitter/tree-sitter-bash"))
+ (c . ("https://github.com/tree-sitter/tree-sitter-c"))
+ (cmake . ("https://github.com/uyha/tree-sitter-cmake"))
+ (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp"))
+ (css . ("https://github.com/tree-sitter/tree-sitter-css"))
+ (elisp . ("https://github.com/Wilfred/tree-sitter-elisp"))
+ (go . ("https://github.com/tree-sitter/tree-sitter-go"))
+ (html . ("https://github.com/tree-sitter/tree-sitter-html"))
+ (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript"))
+ (json . ("https://github.com/tree-sitter/tree-sitter-json"))
+ (julia . ("https://github.com/tree-sitter/tree-sitter-julia"))
+ (latex . ("https://github.com/latex-lsp/tree-sitter-latex"))
+ (make . ("https://github.com/alemuller/tree-sitter-make"))
+ (markdown . ("https://github.com/ikatyang/tree-sitter-markdown"))
+ (R . ("https://github.com/r-lib/tree-sitter-r"))
+ (python . ("https://github.com/tree-sitter/tree-sitter-python"))
+ (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "typescript/src" "typescript"))
+ (rust . ("https://github.com/tree-sitter/tree-sitter-rust"))
+ (sql . ("https://github.com/m-novikov/tree-sitter-sql"))
+ (toml . ("https://github.com/tree-sitter/tree-sitter-toml"))
+ (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src"))
+ (yaml . ("https://github.com/ikatyang/tree-sitter-yaml"))))
+ )
-**** Babel
-:PROPERTIES:
-:CUSTOM_ID: h:3e0b6da3-0497-4080-bb49-bab949c03bc4
-:END:
+ (use-package treesit-auto
+ :config
+ (global-treesit-auto-mode)
+ (setq treesit-auto-install 'prompt))
-org-babel allows to run blocks in other programming languages within an org-mode buffer, similar to what e.g. jupyterhub offers for python.
-It also offers a very useful utility of exporting org-mode buffers to different formats; the feature I enjoy most is what makes this file useful: the tangling functionality.
+#+end_src
-***** Language Configuration
+*** direnv (envrc)
:PROPERTIES:
-:CUSTOM_ID: h:5d5ed7be-ec5f-4e17-bbb8-820ab6a9961c
+:CUSTOM_ID: h:82ddeef2-99f8-465b-ba36-07c3eaad717b
:END:
-- This configures the languages that babel recognizes.
-
#+begin_src emacs-lisp
- (org-babel-do-load-languages
- 'org-babel-load-languages
- '((emacs-lisp . t)
- (python . t)
- (js . t)
- (shell . t)
- ))
-
- (push '("conf-unix" . conf-unix) org-src-lang-modes)
+ (use-package direnv
+ :custom (direnv-always-show-summary nil)
+ :config (direnv-mode))
#+end_src
-***** old easy structure templates
+*** avy
:PROPERTIES:
-:CUSTOM_ID: h:d112ed66-b2dd-45cc-8d70-9cf6631f28a9
+:CUSTOM_ID: h:efb3f0fd-e846-4df9-ba48-2e45d776f68f
:END:
-- org 9.2 changed the way structure templates work. This brings back the old way it worked.
-
- Usage: Type =<=, followed by one of the below keywords and press =RET=. The corresponding source block should appear.
+=avy= provides the ability to search for any character on the screen (not only in the current buffer!) - I enjoy this utility a lot and use it possibly even more often than the native vim commands.
- #+begin_src emacs-lisp
+#+begin_src emacs-lisp
- (require 'org-tempo)
- (add-to-list 'org-structure-template-alist '("sh" . "src shell"))
- (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
- (add-to-list 'org-structure-template-alist '("py" . "src python :results output"))
- (add-to-list 'org-structure-template-alist '("nix" . "src nix :tangle"))
+ (use-package avy
+ :bind
+ (("M-o" . avy-goto-char-timer))
+ :config
+ (setq avy-all-windows 'all-frames))
- #+end_src
+#+end_src
-**** aucTex
+*** crdt (Collaborative Editing)
:PROPERTIES:
-:CUSTOM_ID: h:4696e2fc-3296-47dc-8fc3-66912c329d4c
+:CUSTOM_ID: h:1c1821c6-98de-4079-a4f3-6ba6e6dcb668
:END:
-This provides several utilities for LaTeX in Emacs, including many completions and convenience functions for math-mode.
+With this it is possible to work on the same file collaboratively. I have never tried it out, but it sounds cool.
#+begin_src emacs-lisp
- (use-package auctex)
- (setq TeX-auto-save t)
- (setq TeX-save-query nil)
- (setq TeX-parse-self t)
- (setq-default TeX-master nil)
-
- (add-hook 'LaTeX-mode-hook 'visual-line-mode)
- (add-hook 'LaTeX-mode-hook 'flyspell-mode)
- (add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)
- (add-hook 'LaTeX-mode-hook 'reftex-mode)
- (setq LaTeX-electric-left-right-brace t)
- (setq font-latex-fontify-script nil)
- (setq TeX-electric-sub-and-superscript t)
- ;; (setq reftex-plug-into-AUCTeX t)
+(use-package crdt)
#+end_src
-**** org-download
+*** devdocs
:PROPERTIES:
-:CUSTOM_ID: h:406e5ecb-66f0-49bf-85ca-8b499f73ec5b
+:CUSTOM_ID: h:d9a6cb44-736e-4608-951f-e928e1b757c0
:END:
-This package allows to download and copy images into org-mode buffers. Sadly it does not work in a very stable manner - if you copy images that are also links to another page (like is often the case in a Google image search), Emacs might crash from this.
+=devdocs= is a very nice package that provides documentation from [[https:devdocs.io]]. This is very useful since e.g. =pyright= provides only a very bad documentation and I do not want to leave Emacs all the time just to read documentation.
-#+begin_src emacs-lisp
+To install a documentation, use the =devdocs=install= command and select the appropriate version. =devdocs-update-all= can be used to download and reinstall all installed documents if a newer version is available. Check documentation with =devdocs-lookup= (=C-SPC h d=).
- (use-package org-download
- :after org
- :defer nil
- :custom
- (org-download-method 'directory)
- (org-download-image-dir "./images")
- (org-download-heading-lvl 0)
- (org-download-timestamp "org_%Y%m%d-%H%M%S_")
- ;;(org-image-actual-width 500)
- (org-download-screenshot-method "grim -g \"$(slurp)\" %s")
- :bind
- ("C-M-y" . org-download-screenshot)
- :config
- (require 'org-download))
+#+begin_src emacs-lisp
-#+end_src
+ (use-package devdocs)
-**** org-fragtog
-:PROPERTIES:
-:CUSTOM_ID: h:a02b1162-3e19-46f1-8efc-9f375971645c
-:END:
+ (add-hook 'python-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1"))))
+ (add-hook 'python-ts-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1"))))
-This package automatically toggles LaTeX-fragments in org-files. It seems to also work in markdown-files which is a nice addition, as my Obsidian notes are held in markdown.
+ (add-hook 'c-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("c"))))
+ (add-hook 'c-ts-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("c"))))
-#+begin_src emacs-lisp
+ (add-hook 'c++-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("cpp"))))
+ (add-hook 'c++-ts-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("cpp"))))
- (use-package org-fragtog)
- (add-hook 'org-mode-hook 'org-fragtog-mode)
- (add-hook 'markdown-mode-hook 'org-fragtog-mode)
+ ; (devdocs-update-all)
#+end_src
-**** org-modern
+*** Projectile
:PROPERTIES:
-:CUSTOM_ID: h:95b42e77-767c-4461-9ba8-b1c1cd18266c
+:CUSTOM_ID: h:5cde5032-251e-4cc4-9202-b4ce996f92c2
:END:
-This just makes org-mode a little bit more beautiful, mostly by making the =begin_src= and =end_src= tags in source-blocks turn into more beautiful icons, as well as hiding =#+= tags before them, as well as in the properties section of the file.
+projectile is useful for keeping track of your git projects within Emacs. I mostly use it to quickly switch between projects.
#+begin_src emacs-lisp
- (use-package org-modern
- :config (setq org-modern-block-name
- '((t . t)
- ("src" "»" "∥")))
- :hook (org-mode . org-modern-mode))
+ (use-package projectile
+ :diminish projectile-mode
+ :config (projectile-mode)
+ :custom ((projectile-completion-system 'auto)) ;; integrate ivy into completion system
+ :bind-keymap
+ ("C-c p" . projectile-command-map) ; all projectile commands under this
+ :init
+ ;; NOTE: Set this to the folder where you keep your Git repos!
+ (when (file-directory-p swarsel-projects-directory)
+ (setq projectile-project-search-path (list swarsel-projects-directory)))
+ (setq projectile-switch-project-action #'magit-status))
#+end_src
-**** Presentations
+*** Magit
:PROPERTIES:
-:CUSTOM_ID: h:4e11a845-a7bb-4eb5-b4ce-5b2f52e07425
+:CUSTOM_ID: h:d2c7323d-f8c6-4f23-b70a-930e3e4ecce5
:END:
-Recently I have grown fond of holding presentations using Emacs :)
-
-#+begin_src emacs-lisp
-
- (use-package org-present
- :bind (:map org-present-mode-keymap
- ("q" . org-present-quit)
- ("" . swarsel/org-present-prev)
- ("" . 'ignore)
- ("" . 'ignore)
- ("" . swarsel/org-present-next))
- :hook ((org-present-mode . swarsel/org-present-start)
- (org-present-mode-quit . swarsel/org-present-end))
- )
-
-
- (use-package hide-mode-line)
-
- (defun swarsel/org-present-start ()
- (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch)
- (header-line (:height 4.0) variable-pitch)
- (org-document-title (:height 1.75) org-document-title)
- (org-code (:height 1.55) org-code)
- (org-verbatim (:height 1.55) org-verbatim)
- (org-block (:height 1.25) org-block)
- (org-block-begin-line (:height 0.7) org-block)
- ))
- (dolist (face '((org-level-1 . 1.1)
- (org-level-2 . 1.2)
- (org-level-3 . 1.2)
- (org-level-4 . 1.2)
- (org-level-5 . 1.2)
- (org-level-6 . 1.2)
- (org-level-7 . 1.2)
- (org-level-8 . 1.2)))
- (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
-
- (setq header-line-format " ")
- (setq visual-fill-column-width 90)
- (setq indicate-buffer-boundaries nil)
- (setq inhibit-message nil)
- (breadcrumb-mode 0)
- (org-display-inline-images)
- (global-hl-line-mode 0)
- (display-line-numbers-mode 0)
- (org-modern-mode 0)
- (evil-insert-state 1)
- (beginning-of-buffer)
- (org-present-read-only)
- ;; (org-present-hide-cursor)
- (swarsel/org-present-slide)
- )
-
- (defun swarsel/org-present-end ()
- (setq-local face-remapping-alist '((default variable-pitch default)))
- (dolist (face '((org-level-1 . 1.1)
- (org-level-2 . 0.9)
- (org-level-3 . 0.9)
- (org-level-4 . 0.9)
- (org-level-5 . 0.9)
- (org-level-6 . 0.9)
- (org-level-7 . 0.9)
- (org-level-8 . 0.9)))
- (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
- (setq header-line-format nil)
- (setq visual-fill-column-width 150)
- (setq indicate-buffer-boundaries t)
- (setq inhibit-message nil)
- (breadcrumb-mode 1)
- (global-hl-line-mode 1)
- (display-line-numbers-mode 1)
- (org-remove-inline-images)
- (org-modern-mode 1)
- (evil-normal-state 1)
- ;; (org-present-show-cursor)
- )
-
- (defun swarsel/org-present-slide ()
- (org-overview)
- (org-show-entry)
- (org-show-children)
- )
-
- (defun swarsel/org-present-prev ()
- (interactive)
- (org-present-prev)
- (swarsel/org-present-slide))
-
- (defun swarsel/org-present-next ()
- (interactive)
- (unless (eobp)
- (org-next-visible-heading 1)
- (org-fold-show-entry))
- (when (eobp)
- (org-present-next)
- (swarsel/org-present-slide)
- ))
+magit is the best git utility I have ever used - it has a beautiful interface and is very verbose. Here I mostly just setup the list of repositories that I want to expost to magit.
- (defun clojure-leave-clojure-mode-function ()
- )
+Also, Emacs needs a little extra love to accept my Yubikey for git commits etc. We also set that here.
- (add-hook 'buffer-list-update-hook #'clojure-leave-clojure-mode-function)
- (add-hook 'org-present-mode-hook 'swarsel/org-present-start)
- (add-hook 'org-present-mode-quit-hook 'swarsel/org-present-end)
- (add-hook 'org-present-after-navigate-functions 'swarsel/org-present-slide)
+#+begin_src emacs-lisp
+ (use-package magit
+ :config
+ (setq magit-repository-directories `((,swarsel-projects-directory . 1)
+ (,swarsel-emacs-directory . 0)
+ (,swarsel-obsidian-directory . 0)
+ ("~/.dotfiles/" . 0)))
+ :custom
+ (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) ; stay in the same window
#+end_src
-*** Nix Mode
+
+*** Yubikey support
:PROPERTIES:
-:CUSTOM_ID: h:406c2ecc-0e3e-4d9f-9ae3-3eb1f8b87d1b
+:CUSTOM_ID: h:d78709dd-4f79-441c-9166-76f61f90359a
:END:
-This adds a rudimentary nix-mode to Emacs. I have not really tried this out, as I am mostly editing nix-files in org-mode anyways.
+The following settings are needed to make sure emacs works for magit commits and pushes. It is not a beautiful solution since commiting uses pinentry-emacs and pushing uses pinentry-gtk2, but it works for now at least.
#+begin_src emacs-lisp
- (use-package nix-mode
- :mode "\\.nix\\'")
+ ;; yubikey support for pushing commits
+ ;; commiting is enabled through nixos gpg-agent config
+ (use-package pinentry)
+ (pinentry-start)
+ (setq epg-pinentry-mode 'loopback)
+ (setenv "SSH_AUTH_SOCK" (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))
#+end_src
-*** Markdown Mode
-:PROPERTIES:
-:CUSTOM_ID: h:50327461-a11b-4e81-830a-90febc720cfa
-:END:
-**** Mode
+*** Forge
:PROPERTIES:
-:CUSTOM_ID: h:734dc40a-a2c4-4839-b884-cb99b81aa6fe
+:CUSTOM_ID: h:1a8585ed-d9f2-478f-a132-440ada1cde2c
:END:
-#+begin_src emacs-lisp
+NOTE: Make sure to configure a GitHub token before using this package!
+- https://magit.vc/manual/forge/Token-Creation.html#Token-Creation
+- https://magit.vc/manual/ghub/Getting-Started.html#Getting-Started
+- https://magit.vc/manual/ghub/Storing-a-Token.html
+- https://www.emacswiki.org/emacs/GnuPG
- (setq markdown-command "pandoc")
+ (1) in practice: github -<> settings -<> developer option -<>
+ create classic token with repo; user; read:org permissions
+ (2) install GnuGP (and add to PATH)
+ (3) create ~/.authinfo.gpg with the following info scheme:
+ machine api.github.com login USERNAME^forge password 012345abcdef...
- (use-package markdown-mode
- :ensure t
- :mode ("README\\.md\\'" . gfm-mode)
- :init (setq markdown-command "multimarkdown")
- :bind (:map markdown-mode-map
- ("C-c C-e" . markdown-do)))
+#+begin_src emacs-lisp
+ (use-package forge
+ :after magit)
+
+ (with-eval-after-load 'forge
+ (add-to-list 'forge-alist
+ '("sgit.iue.tuwien.ac.at"
+ "sgit.iue.tuwien.ac.at/api/v1"
+ "sgit.iue.tuwien.ac.at"
+ forge-gitea-repository)))
#+end_src
-**** LaTeX in Markdown
+*** git-timemachine
:PROPERTIES:
-:CUSTOM_ID: h:8d90fe51-0b32-423a-a159-4f853bc29b68
+:CUSTOM_ID: h:cf5b0e6b-56a5-4a93-99fb-258eb7cb2eb4
:END:
+This is just a nice utility to browse different versions of a file of a git project within Emacs.
+
#+begin_src emacs-lisp
- (add-hook 'markdown-mode-hook
- (lambda ()
- (local-set-key (kbd "C-c C-x C-l") 'org-latex-preview)
- (local-set-key (kbd "C-c C-x C-u") 'markdown-toggle-url-hiding)
- ))
+ (use-package git-timemachine
+ :hook (git-time-machine-mode . evil-normalize-keymaps)
+ :init (setq git-timemachine-show-minibuffer-details t))
#+end_src
-*** Olivetti
+*** Delimiters (brackets): rainbow-delimiters, highlight-parentheses
:PROPERTIES:
-:CUSTOM_ID: h:65e69741-9860-4ed0-bbed-7b7be9a2a9d6
+:CUSTOM_ID: h:d9671ab7-a75a-47c6-a1f4-376d126c9b0a
:END:
-Olivetti is a mode specialized for writing prose in Emacs. I went for a very simple setup with little distractions.
+- rainbow-delimiters colors all delimiters, also ones not in current selection
+- paren highlights the current delimiter selection especially bold
+- highlight-parentheses boldly highlights all delimiters in current selection
-This mode is not automatically activated anywhere because I only rarely need it.
+I am not completely sure on electric-pair-mode yet, sometimes it is very helpful, sometimes it annoys me to no end.
#+begin_src emacs-lisp
- (use-package olivetti
- :init
- (setq olivetti-body-width 100)
- (setq olivetti-recall-visual-line-mode-entry-state t))
+ (use-package rainbow-delimiters
+ :hook (prog-mode . rainbow-delimiters-mode))
-#+end_src
+ (use-package highlight-parentheses
+ :config
+ (setq highlight-parentheses-colors '("black" "white" "black" "black" "black" "black" "black"))
+ (setq highlight-parentheses-background-colors '("magenta" "blue" "cyan" "green" "yellow" "orange" "red"))
+ (global-highlight-parentheses-mode t))
-*** darkroom
-:PROPERTIES:
-:CUSTOM_ID: h:94d4a0dc-b0d7-4702-b760-beeaa6da2b8f
-:END:
+ (electric-pair-mode 1)
+ (setq electric-pair-preserve-balance t)
+ (setq electric-pair-skip-self nil)
+ (setq electric-pair-delete-adjacent-pairs t)
+ ;; don't skip newline when auto-pairing parenthesis
+ (setq electric-pair-skip-whitespace-chars '(9 32))
-Darkroom is package that reduces all forms of distraction to a minimum - this can be useful when simply reading a file for example. For this mode I have increased the text scale by a large margin to make for comfortable reading
-This mode is not automatically activated anywhere because I only rarely need it.
+ ;; in org-mode buffers, do not pair < and > in order not to interfere with org-tempo
+ (add-hook 'org-mode-hook (lambda ()
+ (setq-local electric-pair-inhibit-predicate
+ `(lambda (c)
+ (if (char-equal c ?<) t (,electric-pair-inhibit-predicate c))))))
-#+begin_src emacs-lisp
-(use-package darkroom
- :init
- (setq darkroom-text-scale-increase 3))
#+end_src
-*** Ripgrep
+*** rainbow-mode
:PROPERTIES:
-:CUSTOM_ID: h:87453f1c-8ea5-4d0a-862d-8973d5bc5405
+:CUSTOM_ID: h:d1a32a69-2f9a-45ef-95fe-a00e3551dc94
:END:
-This is the ripgrep command for Emacs.
+Complimentary to the delimiters-packages above, this package sets the background color of the delimiters, which makes it easier to see at a glance where we are in a delimiter-tree.
#+begin_src emacs-lisp
- (use-package rg)
+ (use-package rainbow-mode
+ :config (rainbow-mode))
#+end_src
-*** Tree-sitter
+*** Corfu
:PROPERTIES:
-:CUSTOM_ID: h:543641d0-02a9-459e-a2d6-96c8fcc06864
+:CUSTOM_ID: h:5653d693-ecca-4c95-9633-66b9e3241070
:END:
-Tree-sitter is a parsing library integrated into Emacs to provide better syntax highlighting and code analysis. It generates concrete syntax trees for source code, enabling more accurate and efficient text processing. Emacs' tree-sitter integration enhances language support, offering features like incremental parsing and precise syntax-aware editing. This improves the development experience by providing robust and dynamic syntax features, making it easier for me to navigate and manipulate code.
-
-In order to update the language grammars, run the next command below.
-
-#+begin_src emacs-lisp :tangle no :export both
-
- (mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))
+This is the company equivalent to the vertico gang.
+I dislike the standard behaviour that makes the cursor move into the completion framework on presses of == and ==.
-#+end_src
+Nerd icons is originally enabled here: [[#h:eb0ea526-a83a-4664-b3a1-2b40d3a31493][Icons]]
-#+RESULTS:
-| bash | c | cmake | cpp | css | elisp | go | html | javascript | json | julia | latex | make | markdown | R | python | typescript | rust | sql | toml | tsx | yaml |
+Navigation functions defined here: [[#h:a1802f9b-bb71-4fd5-86fa-945da18e8b81][corfu: Do not interrupt navigation]]
#+begin_src emacs-lisp
- (use-package emacs
- :ensure nil
- :init
- (setq treesit-language-source-alist
- '((bash . ("https://github.com/tree-sitter/tree-sitter-bash"))
- (c . ("https://github.com/tree-sitter/tree-sitter-c"))
- (cmake . ("https://github.com/uyha/tree-sitter-cmake"))
- (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp"))
- (css . ("https://github.com/tree-sitter/tree-sitter-css"))
- (elisp . ("https://github.com/Wilfred/tree-sitter-elisp"))
- (go . ("https://github.com/tree-sitter/tree-sitter-go"))
- (html . ("https://github.com/tree-sitter/tree-sitter-html"))
- (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript"))
- (json . ("https://github.com/tree-sitter/tree-sitter-json"))
- (julia . ("https://github.com/tree-sitter/tree-sitter-julia"))
- (latex . ("https://github.com/latex-lsp/tree-sitter-latex"))
- (make . ("https://github.com/alemuller/tree-sitter-make"))
- (markdown . ("https://github.com/ikatyang/tree-sitter-markdown"))
- (R . ("https://github.com/r-lib/tree-sitter-r"))
- (python . ("https://github.com/tree-sitter/tree-sitter-python"))
- (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "typescript/src" "typescript"))
- (rust . ("https://github.com/tree-sitter/tree-sitter-rust"))
- (sql . ("https://github.com/m-novikov/tree-sitter-sql"))
- (toml . ("https://github.com/tree-sitter/tree-sitter-toml"))
- (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src"))
- (yaml . ("https://github.com/ikatyang/tree-sitter-yaml"))))
- )
-
- (use-package treesit-auto
- :config
- (global-treesit-auto-mode)
- (setq treesit-auto-install 'prompt))
-
+ ;; (use-package corfu
+ ;; :custom
+ ;; (corfu-cycle t)
+ ;; :init
+ ;; (global-corfu-mode))
-#+end_src
+ (use-package corfu
+ :init
+ (global-corfu-mode)
+ (corfu-history-mode)
+ (corfu-popupinfo-mode) ; Popup completion info
+ :custom
+ (corfu-auto t)
+ (corfu-auto-prefix 3)
+ (corfu-auto-delay 0.3)
+ (corfu-cycle t)
+ (corfu-quit-no-match 'separator)
+ (corfu-separator ?\s)
+ ;; (corfu-quit-no-match t)
+ (corfu-popupinfo-max-height 70)
+ (corfu-popupinfo-delay '(0.5 . 0.2))
+ ;; (corfu-preview-current 'insert) ; insert previewed candidate
+ (corfu-preselect 'prompt)
+ (corfu-on-exact-match nil) ; Don't auto expand tempel snippets
+ ;; Optionally use TAB for cycling, default is `corfu-complete'.
+ :bind (:map corfu-map
+ ("M-SPC" . corfu-insert-separator)
+ ("" . swarsel/corfu-normal-return)
+ ;; ("C-" . swarsel/corfu-complete)
+ ("S-" . corfu-popupinfo-scroll-down)
+ ("S-" . corfu-popupinfo-scroll-up)
+ ("C-" . corfu-previous)
+ ("C-" . corfu-next)
+ (" " . swarsel/corfu-quit-and-up)
+ (" " . swarsel/corfu-quit-and-down))
+ )
-*** direnv (envrc)
-:PROPERTIES:
-:CUSTOM_ID: h:82ddeef2-99f8-465b-ba36-07c3eaad717b
-:END:
+ (use-package nerd-icons-corfu)
-#+begin_src emacs-lisp
+ (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)
- (use-package direnv
- :custom (direnv-always-show-summary nil)
- :config (direnv-mode))
+ (setq nerd-icons-corfu-mapping
+ '((array :style "cod" :icon "symbol_array" :face font-lock-type-face)
+ (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face)
+ ;; ...
+ (t :style "cod" :icon "code" :face font-lock-warning-face)))
#+end_src
-*** avy
+*** cape
:PROPERTIES:
-:CUSTOM_ID: h:efb3f0fd-e846-4df9-ba48-2e45d776f68f
+:CUSTOM_ID: h:c3cc1c12-3ab8-42b7-be07-63f54eac397f
:END:
-=avy= provides the ability to search for any character on the screen (not only in the current buffer!) - I enjoy this utility a lot and use it possibly even more often than the native vim commands.
+cape adds even more completion capabilities by adding a lot of completion logic that is exposed as separate functions. I tried out adding these to the =completion-at-points-functions= alist, but I felt like it cluttered my suggestions too much. Hence I now just call the respective functions when I need them. For this I setup the =C-z= keybinding in [[#h:218376e8-086b-46bf-91b3-78295d5d440f][General evil]].
+
+I leave the commented out alist extensions here in case I want to try them out at some point in the future.
#+begin_src emacs-lisp
- (use-package avy
+ (use-package cape
:bind
- (("M-o" . avy-goto-char-timer))
- :config
- (setq avy-all-windows 'all-frames))
+ ("C-z p" . completion-at-point) ;; capf
+ ("C-z t" . complete-tag) ;; etags
+ ("C-z d" . cape-dabbrev) ;; or dabbrev-completion
+ ("C-z h" . cape-history)
+ ("C-z f" . cape-file)
+ ("C-z k" . cape-keyword)
+ ("C-z s" . cape-elisp-symbol)
+ ("C-z e" . cape-elisp-block)
+ ("C-z a" . cape-abbrev)
+ ("C-z l" . cape-line)
+ ("C-z w" . cape-dict)
+ ("C-z :" . cape-emoji)
+ ("C-z \\" . cape-tex)
+ ("C-z _" . cape-tex)
+ ("C-z ^" . cape-tex)
+ ("C-z &" . cape-sgml)
+ ("C-z r" . cape-rfc1345)
+ ;; Add to the global default value of `completion-at-point-functions' which is
+ ;; used by `completion-at-point'. The order of the functions matters, the
+ ;; first function returning a result wins. Note that the list of buffer-local
+ ;; completion functions takes precedence over the global list.
+ ;; (add-to-list 'completion-at-point-functions #'cape-dabbrev)
+ ;; (add-to-list 'completion-at-point-functions #'cape-file)
+ ;; (add-to-list 'completion-at-point-functions #'cape-elisp-block)
+ ;; (add-to-list 'completion-at-point-functions #'cape-history)
+ ;; (add-to-list 'completion-at-point-functions #'cape-keyword)
+ ;; (add-to-list 'completion-at-point-functions #'cape-tex)
+ ;; (add-to-list 'completion-at-point-functions #'cape-sgml)
+ ;; (add-to-list 'completion-at-point-functions #'cape-rfc1345)
+ ;; (add-to-list 'completion-at-point-functions #'cape-abbrev)
+ ;; (add-to-list 'completion-at-point-functions #'cape-dict)
+ ;; (add-to-list 'completion-at-point-functions #'cape-elisp-symbol)
+ ;; (add-to-list 'completion-at-point-functions #'cape-line)
+ )
#+end_src
-*** crdt (Collaborative Editing)
+*** rust
:PROPERTIES:
-:CUSTOM_ID: h:1c1821c6-98de-4079-a4f3-6ba6e6dcb668
+:CUSTOM_ID: h:3aa20438-edf6-4b13-a90d-3d5c51239c44
:END:
-With this it is possible to work on the same file collaboratively. I have never tried it out, but it sounds cool.
+This sets up rustic-mode with tree-sitter support - there is still one issue to iron out with automatic adding of dependency crates, but everything else works fine now.
#+begin_src emacs-lisp
-(use-package crdt)
+ (use-package rustic
+ :init
+ (setq rust-mode-treesitter-derive t)
+ :config
+ (define-key rust-ts-mode-map (kbd "C-c C-c C-r") 'rustic-cargo-run)
+ (define-key rust-ts-mode-map (kbd "C-c C-c C-b") 'rustic-cargo-build)
+ (define-key rust-ts-mode-map (kbd "C-c C-c C-k") 'rustic-cargo-check)
+ (define-key rust-ts-mode-map (kbd "C-c C-c d") 'rustic-cargo-doc)
+ (define-key rust-ts-mode-map (kbd "C-c C-c a") 'rustic-cargo-add)
+ (setq rustic-format-on-save t)
+ (setq rustic-lsp-client 'eglot)
+ :mode ("\\.rs" . rustic-mode))
+
#+end_src
-*** devdocs
+*** Tramp
:PROPERTIES:
-:CUSTOM_ID: h:d9a6cb44-736e-4608-951f-e928e1b757c0
+:CUSTOM_ID: h:b9b27a88-06f3-470b-a604-a20b2079bc26
:END:
-=devdocs= is a very nice package that provides documentation from [[https:devdocs.io]]. This is very useful since e.g. =pyright= provides only a very bad documentation and I do not want to leave Emacs all the time just to read documentation.
-
-To install a documentation, use the =devdocs=install= command and select the appropriate version. =devdocs-update-all= can be used to download and reinstall all installed documents if a newer version is available. Check documentation with =devdocs-lookup= (=C-SPC h d=).
+Tramp allows for SSH access of files over Emacs. I have no ideas what the options here mean, but this is a recommended configuration that I found (sadly I lost the link). I need to research more what these options really do.
#+begin_src emacs-lisp
- (use-package devdocs)
- (add-hook 'python-mode-hook
- (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1"))))
- (add-hook 'python-ts-mode-hook
- (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1"))))
- (add-hook 'c-mode-hook
- (lambda () (setq-local devdocs-current-docs '("c"))))
- (add-hook 'c-ts-mode-hook
- (lambda () (setq-local devdocs-current-docs '("c"))))
+(use-package tramp
+ :init
+ (setq vc-ignore-dir-regexp
+ (format "\\(%s\\)\\|\\(%s\\)"
+ vc-ignore-dir-regexp
+ tramp-file-name-regexp))
+ (setq tramp-default-method "ssh")
+ (setq tramp-auto-save-directory
+ (expand-file-name "tramp-auto-save" user-emacs-directory))
+ (setq tramp-persistency-file-name
+ (expand-file-name "tramp-connection-history" user-emacs-directory))
+ (setq password-cache-expiry nil)
+ (setq tramp-use-ssh-controlmaster-options nil)
+ (setq remote-file-name-inhibit-cache nil)
+ :config
+ (customize-set-variable 'tramp-ssh-controlmaster-options
+ (concat
+ "-o ControlPath=/tmp/ssh-tramp-%%r@%%h:%%p "
+ "-o ControlMaster=auto -o ControlPersist=yes"))
+)
- (add-hook 'c++-mode-hook
- (lambda () (setq-local devdocs-current-docs '("cpp"))))
- (add-hook 'c++-ts-mode-hook
- (lambda () (setq-local devdocs-current-docs '("cpp"))))
- ; (devdocs-update-all)
#+end_src
-*** Projectile
+*** diff-hl
:PROPERTIES:
-:CUSTOM_ID: h:5cde5032-251e-4cc4-9202-b4ce996f92c2
+:CUSTOM_ID: h:58415e95-8a7a-4517-acbb-5f1bb1028603
:END:
-projectile is useful for keeping track of your git projects within Emacs. I mostly use it to quickly switch between projects.
+This is a simple highlighting utility that uses the margin to visually show the differences since the last git commit.
#+begin_src emacs-lisp
- (use-package projectile
- :diminish projectile-mode
- :config (projectile-mode)
- :custom ((projectile-completion-system 'auto)) ;; integrate ivy into completion system
- :bind-keymap
- ("C-c p" . projectile-command-map) ; all projectile commands under this
+ (use-package diff-hl
+ :hook
+ ((prog-mode
+ org-mode) . diff-hl-mode)
:init
- ;; NOTE: Set this to the folder where you keep your Git repos!
- (when (file-directory-p swarsel-projects-directory)
- (setq projectile-project-search-path (list swarsel-projects-directory)))
- (setq projectile-switch-project-action #'magit-status))
+ (diff-hl-flydiff-mode)
+ (diff-hl-margin-mode)
+ (diff-hl-show-hunk-mouse-mode))
#+end_src
-
-*** Magit
+*** Commenting
:PROPERTIES:
-:CUSTOM_ID: h:d2c7323d-f8c6-4f23-b70a-930e3e4ecce5
+:CUSTOM_ID: h:d60ce0b1-cabf-43f5-a236-a1e4b400d2f5
:END:
-magit is the best git utility I have ever used - it has a beautiful interface and is very verbose. Here I mostly just setup the list of repositories that I want to expost to magit.
+This package allows for swift commenting out and in of code snippets. For some reason, it is a bit broken in my config, as it sometimes comments out too much, sometimes too little, and sometimes it splits lines during commenting. Also, in org-mode when inside a src-block, it often times jumps to the top of the block.
-Also, Emacs needs a little extra love to accept my Yubikey for git commits etc. We also set that here.
+Still, this is avery convenient package.
#+begin_src emacs-lisp
- (use-package magit
- :config
- (setq magit-repository-directories `((,swarsel-projects-directory . 1)
- (,swarsel-emacs-directory . 0)
- (,swarsel-obsidian-directory . 0)
- ("~/.dotfiles/" . 0)))
- :custom
- (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) ; stay in the same window
+ (use-package evil-nerd-commenter
+ :bind ("M-/" . evilnc-comment-or-uncomment-lines))
+
#+end_src
-* Yubikey support
+*** yasnippet
+:PROPERTIES:
+:CUSTOM_ID: h:9ec11ee4-2250-414a-87b5-73ee680a3a4a
+:END:
+
+yasnippet allows to define snippets that can be quickly expanded by hitting the =TAB= key after inputting a keyword.
-The following settings are needed to make sure emacs works for magit commits and pushes. It is not a beautiful solution since commiting uses pinentry-emacs and pushing uses pinentry-gtk2, but it works for now at least.
+I used to run this together with the =yasnippet-snippets= package, but the snippets in there I did not find all too useful for myself. I need to create some custom snippets here one day.
#+begin_src emacs-lisp
+ (use-package yasnippet
+ :init (yas-global-mode 1)
+ :config
+ (yas-reload-all))
- ;; yubikey support for pushing commits
- ;; commiting is enabled through nixos gpg-agent config
- (use-package pinentry)
- (pinentry-start)
- (setq epg-pinentry-mode 'loopback)
- (setenv "SSH_AUTH_SOCK" (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))
#+end_src
-*** Forge
+***** yasnippet math-snippets
:PROPERTIES:
-:CUSTOM_ID: h:1a8585ed-d9f2-478f-a132-440ada1cde2c
+:CUSTOM_ID: h:af0a78a5-17c2-4e13-b64a-772c27c4dee2
:END:
-NOTE: Make sure to configure a GitHub token before using this package!
-- https://magit.vc/manual/forge/Token-Creation.html#Token-Creation
-- https://magit.vc/manual/ghub/Getting-Started.html#Getting-Started
-- https://magit.vc/manual/ghub/Storing-a-Token.html
-- https://www.emacswiki.org/emacs/GnuPG
-
- (1) in practice: github -<> settings -<> developer option -<>
- create classic token with repo; user; read:org permissions
- (2) install GnuGP (and add to PATH)
- (3) create ~/.authinfo.gpg with the following info scheme:
- machine api.github.com login USERNAME^forge password 012345abcdef...
+The following block is mostly inspired from [[https://code.kulupu.party/thesuess/WTFmacs/]] and sets up a few prefixes that make LaTeX-math-mode nicer to use even with auctex and cape enabled.
#+begin_src emacs-lisp
- (use-package forge
- :after magit)
- (with-eval-after-load 'forge
- (add-to-list 'forge-alist
- '("sgit.iue.tuwien.ac.at"
- "sgit.iue.tuwien.ac.at/api/v1"
- "sgit.iue.tuwien.ac.at"
- forge-gitea-repository)))
-#+end_src
+ (setq wtf/latex-mathbb-prefix "''")
+ (setq swarsel/latex-mathcal-prefix "``")
-*** git-timemachine
-:PROPERTIES:
-:CUSTOM_ID: h:cf5b0e6b-56a5-4a93-99fb-258eb7cb2eb4
-:END:
+ (use-package yasnippet
+ :config
-This is just a nice utility to browse different versions of a file of a git project within Emacs.
+ (setq wtf/english-alphabet
+ '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"))
-#+begin_src emacs-lisp
+ (dolist (elem wtf/english-alphabet)
+ (when (string-equal elem (downcase elem))
+ (add-to-list 'wtf/english-alphabet (upcase elem))))
- (use-package git-timemachine
- :hook (git-time-machine-mode . evil-normalize-keymaps)
- :init (setq git-timemachine-show-minibuffer-details t))
-#+end_src
+ (yas-define-snippets
+ 'latex-mode
+ (mapcar
+ (lambda (elem)
+ (list (concat wtf/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem)))
+ wtf/english-alphabet))
-*** Delimiters (brackets): rainbow-delimiters, highlight-parentheses
-:PROPERTIES:
-:CUSTOM_ID: h:d9671ab7-a75a-47c6-a1f4-376d126c9b0a
-:END:
+ (yas-define-snippets
+ 'latex-mode
+ (mapcar
+ (lambda (elem)
+ (list (concat swarsel/latex-mathcal-prefix elem) (concat "\\mathcal{" elem "}") (concat "Mathcal letter " elem)))
+ wtf/english-alphabet))
-- rainbow-delimiters colors all delimiters, also ones not in current selection
-- paren highlights the current delimiter selection especially bold
-- highlight-parentheses boldly highlights all delimiters in current selection
+ (setq swtf/latex-math-symbols
+ '(("x" . "\\times")
+ ("*" . "\\cdot")
+ ("." . "\\ldots")
+ ("op" . "\\operatorname{$1}$0")
+ ("o" . "\\circ")
+ ("V" . "\\forall")
+ ("v" . "\\vee")
+ ("w" . "\\wedge")
+ ("q" . "\\quad")
+ ("f" . "\\frac{$1}{$2}$0")
+ ("s" . "\\sum_{$1}^{$2}$0")
+ ("p" . "\\prod_{$1}^{$2}$0")
+ ("e" . "\\exists")
+ ("i" . "\\int_{$1}^{$2}$0")
+ ("c" . "\\cap")
+ ("u" . "\\cup")
+ ("0" . "\\emptyset")))
-I am not completely sure on electric-pair-mode yet, sometimes it is very helpful, sometimes it annoys me to no end.
+ )
-#+begin_src emacs-lisp
- (use-package rainbow-delimiters
- :hook (prog-mode . rainbow-delimiters-mode))
+#+end_src
- (use-package highlight-parentheses
- :config
- (setq highlight-parentheses-colors '("black" "white" "black" "black" "black" "black" "black"))
- (setq highlight-parentheses-background-colors '("magenta" "blue" "cyan" "green" "yellow" "orange" "red"))
- (global-highlight-parentheses-mode t))
+*** eglot
+:PROPERTIES:
+:CUSTOM_ID: h:316857e7-4df8-4ec5-b22e-6dac918fa937
+:END:
- (electric-pair-mode 1)
- (setq electric-pair-preserve-balance t)
- (setq electric-pair-skip-self nil)
- (setq electric-pair-delete-adjacent-pairs t)
- ;; don't skip newline when auto-pairing parenthesis
- (setq electric-pair-skip-whitespace-chars '(9 32))
+After having tried out =lsp-mode= and =lsp-bridge= for a while each, I must say that =eglot= feels the most clean and fast to me.
- ;; in org-mode buffers, do not pair < and > in order not to interfere with org-tempo
- (add-hook 'org-mode-hook (lambda ()
- (setq-local electric-pair-inhibit-predicate
- `(lambda (c)
- (if (char-equal c ?<) t (,electric-pair-inhibit-predicate c))))))
+:PROPERTIES:
+:CUSTOM_ID: h:424fbc62-84e2-42c7-a1ca-e43ea04c43e5
+:END:
+
+#+begin_src emacs-lisp
+ (use-package eglot
+ :ensure nil
+ :hook
+ ((python-mode
+ python-ts-mode
+ c-mode
+ c-ts-mode
+ c++-mode
+ c++-ts-mode
+ rust-ts-mode
+ rustic-mode
+ tex-mode
+ LaTeX-mode
+ ) . (lambda () (progn
+ (eglot-ensure)
+ (add-hook 'before-save-hook 'eglot-format nil 'local))))
+ :custom
+ (eldoc-echo-area-use-multiline-p nil)
+ (completion-category-defaults nil)
+ :bind (:map eglot-mode-map
+ ("M-(" . flymake-goto-next-error)
+ ("C-c ," . eglot-code-actions)))
+ (defalias 'start-lsp-server #'eglot)
#+end_src
-*** rainbow-mode
+*** Breadcrumb
:PROPERTIES:
-:CUSTOM_ID: h:d1a32a69-2f9a-45ef-95fe-a00e3551dc94
+:CUSTOM_ID: h:1de35f27-335d-4cbd-beb6-f85cf5496173
:END:
-Complimentary to the delimiters-packages above, this package sets the background color of the delimiters, which makes it easier to see at a glance where we are in a delimiter-tree.
+This simple shows the path to the current file on the top of the buffer - I just think it looks kind of neat, even though it is not extremely useful :)
#+begin_src emacs-lisp
- (use-package rainbow-mode
- :config (rainbow-mode))
+ (use-package breadcrumb
+ :config (breadcrumb-mode))
#+end_src
-*** Corfu
+
+*** Prevent breaking of hardlinks
:PROPERTIES:
-:CUSTOM_ID: h:5653d693-ecca-4c95-9633-66b9e3241070
+:CUSTOM_ID: h:e9a30d0f-423f-4e85-af4b-f8560f1c1b53
:END:
-This is the company equivalent to the vertico gang.
-I dislike the standard behaviour that makes the cursor move into the completion framework on presses of == and ==.
-
-Nerd icons is originally enabled here: [[#h:eb0ea526-a83a-4664-b3a1-2b40d3a31493][Icons]]
-
-Navigation functions defined here: [[#h:a1802f9b-bb71-4fd5-86fa-945da18e8b81][corfu: Do not interrupt navigation]]
+This setting ensures that hard links are preserved during the backup process, which is useful for maintaining the integrity of files that are linked in multiple locations.
#+begin_src emacs-lisp
- ;; (use-package corfu
- ;; :custom
- ;; (corfu-cycle t)
- ;; :init
- ;; (global-corfu-mode))
+ (setq backup-by-copying-when-linked t)
- (use-package corfu
- :init
- (global-corfu-mode)
- (corfu-history-mode)
- (corfu-popupinfo-mode) ; Popup completion info
- :custom
- (corfu-auto t)
- (corfu-auto-prefix 3)
- (corfu-auto-delay 0.3)
- (corfu-cycle t)
- (corfu-quit-no-match 'separator)
- (corfu-separator ?\s)
- ;; (corfu-quit-no-match t)
- (corfu-popupinfo-max-height 70)
- (corfu-popupinfo-delay '(0.5 . 0.2))
- ;; (corfu-preview-current 'insert) ; insert previewed candidate
- (corfu-preselect 'prompt)
- (corfu-on-exact-match nil) ; Don't auto expand tempel snippets
- ;; Optionally use TAB for cycling, default is `corfu-complete'.
- :bind (:map corfu-map
- ("M-SPC" . corfu-insert-separator)
- ("" . swarsel/corfu-normal-return)
- ;; ("C-" . swarsel/corfu-complete)
- ("S-" . corfu-popupinfo-scroll-down)
- ("S-" . corfu-popupinfo-scroll-up)
- ("C-" . corfu-previous)
- ("C-" . corfu-next)
- (" " . swarsel/corfu-quit-and-up)
- (" " . swarsel/corfu-quit-and-down))
- )
+#+end_src
- (use-package nerd-icons-corfu)
+*** Dirvish
+:PROPERTIES:
+:CUSTOM_ID: h:0918557a-8463-430c-b8df-6546dea9abd0
+:END:
- (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)
+Dirvish is an improvement upon the dired-framework and has more features like file preview etc. Sadly it has an incompatibility with =openwith= which is why I have disabled that package.
- (setq nerd-icons-corfu-mapping
- '((array :style "cod" :icon "symbol_array" :face font-lock-type-face)
- (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face)
- ;; ...
- (t :style "cod" :icon "code" :face font-lock-warning-face)))
+#+begin_src emacs-lisp
-#+end_src
+ (use-package dirvish
+ :init
+ (dirvish-override-dired-mode)
+ :config
+ (dirvish-peek-mode)
+ (dirvish-side-follow-mode)
+ (setq dirvish-open-with-programs
+ (append dirvish-open-with-programs '(
+ (("xlsx" "docx" "doc" "odt" "ods") "libreoffice" "%f")
+ (("jpg" "jpeg" "png") "imv" "%f")
+ (("pdf") "sioyek" "%f")
+ (("xopp") "xournalpp" "%f"))))
+ :custom
+ (delete-by-moving-to-trash t)
+ (dired-listing-switches
+ "-l --almost-all --human-readable --group-directories-first --no-group")
+ (dirvish-attributes
+ '(vc-state subtree-state nerd-icons collapse file-time file-size))
+ (dirvish-quick-access-entries
+ '(("h" "~/" "Home")
+ ("c" "~/.dotfiles/" "Config")
+ ("d" "~/Downloads/" "Downloads")
+ ("D" "~/Documents/" "Documents")
+ ("p" "~/Documents/GitHub/" "Projects")
+ ("/" "/" "Root")))
+ :bind
+ ((" d" . 'dirvish)
+ ("C-=" . 'dirvish-side)
+ :map dirvish-mode-map
+ ("h" . dired-up-directory)
+ ("" . dired-up-directory)
+ ("l" . dired-find-file)
+ ("" . dired-find-file)
+ ("j" . evil-next-visual-line)
+ ("k" . evil-previous-visual-line)
+ ("a" . dirvish-quick-access)
+ ("f" . dirvish-file-info-menu)
+ ("z" . dirvish-history-last)
+ ("J" . dirvish-history-jump)
+ ("y" . dirvish-yank-menu)
+ ("/" . dirvish-narrow)
+ ("TAB" . dirvish-subtree-toggle)
+ ("M-f" . dirvish-history-go-forward)
+ ("M-b" . dirvish-history-go-backward)
+ ("M-l" . dirvish-ls-switches-menu)
+ ("M-m" . dirvish-mark-menu)
+ ("M-t" . dirvish-layout-toggle)
+ ("M-s" . dirvish-setup-menu)
+ ("M-e" . dirvish-emerge-menu)
+ ("M-j" . dirvish-fd-jump)))
-*** cape
+#+end_src
+*** pdf-tools: pdf-viewer and support for dirvish
:PROPERTIES:
-:CUSTOM_ID: h:c3cc1c12-3ab8-42b7-be07-63f54eac397f
+:CUSTOM_ID: h:b108dd3e-f34d-4ed3-98df-0bf9de055889
:END:
-cape adds even more completion capabilities by adding a lot of completion logic that is exposed as separate functions. I tried out adding these to the =completion-at-points-functions= alist, but I felt like it cluttered my suggestions too much. Hence I now just call the respective functions when I need them. For this I setup the =C-z= keybinding in [[#h:218376e8-086b-46bf-91b3-78295d5d440f][General evil]].
-
-I leave the commented out alist extensions here in case I want to try them out at some point in the future.
+This enables pdf-previewing in dirvish and gives a much better pdf-viewer than is shipped normally by emacs.
#+begin_src emacs-lisp
- (use-package cape
- :bind
- ("C-z p" . completion-at-point) ;; capf
- ("C-z t" . complete-tag) ;; etags
- ("C-z d" . cape-dabbrev) ;; or dabbrev-completion
- ("C-z h" . cape-history)
- ("C-z f" . cape-file)
- ("C-z k" . cape-keyword)
- ("C-z s" . cape-elisp-symbol)
- ("C-z e" . cape-elisp-block)
- ("C-z a" . cape-abbrev)
- ("C-z l" . cape-line)
- ("C-z w" . cape-dict)
- ("C-z :" . cape-emoji)
- ("C-z \\" . cape-tex)
- ("C-z _" . cape-tex)
- ("C-z ^" . cape-tex)
- ("C-z &" . cape-sgml)
- ("C-z r" . cape-rfc1345)
- ;; Add to the global default value of `completion-at-point-functions' which is
- ;; used by `completion-at-point'. The order of the functions matters, the
- ;; first function returning a result wins. Note that the list of buffer-local
- ;; completion functions takes precedence over the global list.
- ;; (add-to-list 'completion-at-point-functions #'cape-dabbrev)
- ;; (add-to-list 'completion-at-point-functions #'cape-file)
- ;; (add-to-list 'completion-at-point-functions #'cape-elisp-block)
- ;; (add-to-list 'completion-at-point-functions #'cape-history)
- ;; (add-to-list 'completion-at-point-functions #'cape-keyword)
- ;; (add-to-list 'completion-at-point-functions #'cape-tex)
- ;; (add-to-list 'completion-at-point-functions #'cape-sgml)
- ;; (add-to-list 'completion-at-point-functions #'cape-rfc1345)
- ;; (add-to-list 'completion-at-point-functions #'cape-abbrev)
- ;; (add-to-list 'completion-at-point-functions #'cape-dict)
- ;; (add-to-list 'completion-at-point-functions #'cape-elisp-symbol)
- ;; (add-to-list 'completion-at-point-functions #'cape-line)
- )
+ (use-package pdf-tools
+ :init
+ (if (not (boundp 'pdf-tools-directory))
+ (pdf-tools-install))
+ :mode ("\\.pdf" . pdf-view-mode))
#+end_src
-*** rust
+*** Jupyter
:PROPERTIES:
-:CUSTOM_ID: h:3aa20438-edf6-4b13-a90d-3d5c51239c44
+:CUSTOM_ID: h:c15efae7-b884-4c97-8367-ccc7e7ed9ba8
:END:
-This sets up rustic-mode with tree-sitter support - there is still one issue to iron out with automatic adding of dependency crates, but everything else works fine now.
+This is a jupyter client. Using it is a bit cumbersome though, so I have not fully explored all features.
#+begin_src emacs-lisp
- (use-package rustic
- :init
- (setq rust-mode-treesitter-derive t)
- :config
- (define-key rust-ts-mode-map (kbd "C-c C-c C-r") 'rustic-cargo-run)
- (define-key rust-ts-mode-map (kbd "C-c C-c C-b") 'rustic-cargo-build)
- (define-key rust-ts-mode-map (kbd "C-c C-c C-k") 'rustic-cargo-check)
- (define-key rust-ts-mode-map (kbd "C-c C-c d") 'rustic-cargo-doc)
- (define-key rust-ts-mode-map (kbd "C-c C-c a") 'rustic-cargo-add)
- (setq rustic-format-on-save t)
- (setq rustic-lsp-client 'eglot)
- :mode ("\\.rs" . rustic-mode))
-
+ (use-package ein)
#+end_src
-*** Tramp
+*** undo-tree
:PROPERTIES:
-:CUSTOM_ID: h:b9b27a88-06f3-470b-a604-a20b2079bc26
+:CUSTOM_ID: h:1fc538d1-8c53-48b2-8652-66046f4bbbf8
:END:
-Tramp allows for SSH access of files over Emacs. I have no ideas what the options here mean, but this is a recommended configuration that I found (sadly I lost the link). I need to research more what these options really do.
+Base emacs undo logic is very useful, but not easy to understand for me. I prefer undo-tree, which makes switching between branches easier and also allows quickly switching back to a much older state using the visualizer.
+
+Evil needs to be told to use this mode, see =(evil-set-undo-system 'undo-tree)= in [[#h:218376e8-086b-46bf-91b3-78295d5d440f][Evil/General.]]
+
+By default, I am not using undo-tree-mode in every buffer. This might change in the future, but for now this is fine. It can be enabled manually should the need arise.
+
+While we are at it, we are also setting up a persistent undo-file for every file that we are working with.
#+begin_src emacs-lisp
+ (use-package undo-tree
+ ;; :init (global-undo-tree-mode)
+ :bind (:map undo-tree-visualizer-mode-map
+ ("h" . undo-tree-visualize-switch-branch-left)
+ ("l" . undo-tree-visualize-switch-branch-left)
+ ("j" . undo-tree-visualize-redo)
+ ("k" . undo-tree-visualize-undo))
+ :config
+ (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))))
+ (add-hook 'prog-mode-hook 'undo-tree-mode)
+ (add-hook 'text-mode-hook 'undo-tree-mode)
+ (add-hook 'org-mode-hook 'undo-tree-mode)
+ (add-hook 'latex-mode-hook 'undo-tree-mode)
+#+end_src
+*** Hydra
+:PROPERTIES:
+:CUSTOM_ID: h:b6c18dd0-3377-47ea-80c3-ac1486454e18
+:END:
-(use-package tramp
- :init
- (setq vc-ignore-dir-regexp
- (format "\\(%s\\)\\|\\(%s\\)"
- vc-ignore-dir-regexp
- tramp-file-name-regexp))
- (setq tramp-default-method "ssh")
- (setq tramp-auto-save-directory
- (expand-file-name "tramp-auto-save" user-emacs-directory))
- (setq tramp-persistency-file-name
- (expand-file-name "tramp-connection-history" user-emacs-directory))
- (setq password-cache-expiry nil)
- (setq tramp-use-ssh-controlmaster-options nil)
- (setq remote-file-name-inhibit-cache nil)
- :config
- (customize-set-variable 'tramp-ssh-controlmaster-options
- (concat
- "-o ControlPath=/tmp/ssh-tramp-%%r@%%h:%%p "
- "-o ControlMaster=auto -o ControlPersist=yes"))
-)
+Hydra allows for the writing of macro-style functions. I have not yet looked into this all too much, but it seems to be a potent feature.
+#+begin_src emacs-lisp
+ (use-package hydra)
#+end_src
-*** diff-hl
+**** Text scaling
:PROPERTIES:
-:CUSTOM_ID: h:58415e95-8a7a-4517-acbb-5f1bb1028603
+:CUSTOM_ID: h:c5681884-7040-4b55-ab1b-5777631a0514
:END:
-This is a simple highlighting utility that uses the margin to visually show the differences since the last git commit.
+I only wrote this in order to try out hydra; rarely do I really need this. However, it can be useful for [[#h:4e11a845-a7bb-4eb5-b4ce-5b2f52e07425][Presentations]]. It simply scales the text size.
#+begin_src emacs-lisp
- (use-package diff-hl
- :hook
- ((prog-mode
- org-mode) . diff-hl-mode)
- :init
- (diff-hl-flydiff-mode)
- (diff-hl-margin-mode)
- (diff-hl-show-hunk-mouse-mode))
+
+ ;; change the text size of the current buffer
+ (defhydra hydra-text-scale (:timeout 4)
+ "scale text"
+ ("j" text-scale-increase "in")
+ ("k" text-scale-decrease "out")
+ ("f" nil "finished" :exit t))
#+end_src
-*** Commenting
+*** External Applications
:PROPERTIES:
-:CUSTOM_ID: h:d60ce0b1-cabf-43f5-a236-a1e4b400d2f5
+:CUSTOM_ID: h:fff816a0-6d70-4bda-abab-833345e51100
+:END:
+**** Obsidian
+:PROPERTIES:
+:CUSTOM_ID: h:9335d32d-bf08-4601-820d-f3d1f33f876f
:END:
-This package allows for swift commenting out and in of code snippets. For some reason, it is a bit broken in my config, as it sometimes comments out too much, sometimes too little, and sometimes it splits lines during commenting. Also, in org-mode when inside a src-block, it often times jumps to the top of the block.
+This provides an interface to Obsidian for Emacs - as much as I want to like it, I actually enjoy using the official Obsidian app more - even though that cannot be used by Emacs directly.
-Still, this is avery convenient package.
+My workflow for Obsidian is now as follows:
+
+1) create notes either in Emacs or Obsidian
+2) look at them in the official client
+
+ I hope that this package will improve, then I will come back to it one day.
#+begin_src emacs-lisp
- (use-package evil-nerd-commenter
- :bind ("M-/" . evilnc-comment-or-uncomment-lines))
+ ;; (use-package obsidian
+ ;; :ensure t
+ ;; :demand t
+ ;; :config
+ ;; (obsidian-specify-path swarsel-obsidian-vault-directory)
+ ;; (global-obsidian-mode t)
+ ;; :custom
+ ;; ;; This directory will be used for `obsidian-capture' if set.
+ ;; (obsidian-inbox-directory "Inbox")
+ ;; (bind-key (kbd "C-c M-o") 'obsidian-hydra/body 'obsidian-mode-map)
+ ;; :bind (:map obsidian-mode-map
+ ;; ;; Replace C-c C-o with Obsidian.el's implementation. It's ok to use another key binding.
+ ;; ("C-c C-o" . obsidian-follow-link-at-point)
+ ;; ;; Jump to backlinks
+ ;; ("C-c C-b" . obsidian-backlink-jump)
+ ;; ;; If you prefer you can use `obsidian-insert-link'
+ ;; ("C-c C-l" . obsidian-insert-wikilink)))
#+end_src
-*** yasnippet
+**** Anki
:PROPERTIES:
-:CUSTOM_ID: h:9ec11ee4-2250-414a-87b5-73ee680a3a4a
+:CUSTOM_ID: h:5854c9a6-1319-4961-a112-75b1bf2e1f69
:END:
-yasnippet allows to define snippets that can be quickly expanded by hitting the =TAB= key after inputting a keyword.
+This section is here to make Anki usable from within Emacs - an endeavour that I have mostly given up on.
-I used to run this together with the =yasnippet-snippets= package, but the snippets in there I did not find all too useful for myself. I need to create some custom snippets here one day.
+***** Basic Anki setup
+:PROPERTIES:
+:CUSTOM_ID: h:d20559ed-7ada-4fea-a964-33bfd64b4549
+:END:
#+begin_src emacs-lisp
- (use-package yasnippet
- :init (yas-global-mode 1)
- :config
- (yas-reload-all))
+ ;; (use-package anki-editor
+ ;; :after org
+ ;; :bind (:map org-mode-map
+ ;; ("" . anki-editor-cloze-region-auto-incr)
+ ;; ("" . anki-editor-cloze-region-dont-incr)
+ ;; ("" . anki-editor-reset-cloze-number)
+ ;; ("" . anki-editor-push-tree))
+ ;; :hook (org-capture-after-finalize . anki-editor-reset-cloze-number) ; Reset cloze-number after each capture.
+ ;; :config
+ ;; (setq anki-editor-create-decks t ;; Allow anki-editor to create a new deck if it doesn't exist
+ ;; anki-editor-org-tags-as-anki-tags t)
+
+ ;; (defun anki-editor-cloze-region-auto-incr (&optional arg)
+ ;; "Cloze region without hint and increase card number."
+ ;; (interactive)
+ ;; (anki-editor-cloze-region swarsel-anki-editor-cloze-number "")
+ ;; (setq swarsel-anki-editor-cloze-number (1+ swarsel-anki-editor-cloze-number))
+ ;; (forward-sexp))
+ ;; (defun anki-editor-cloze-region-dont-incr (&optional arg)
+ ;; "Cloze region without hint using the previous card number."
+ ;; (interactive)
+ ;; (anki-editor-cloze-region (1- swarsel-anki-editor-cloze-number) "")
+ ;; (forward-sexp))
+ ;; (defun anki-editor-reset-cloze-number (&optional arg)
+ ;; "Reset cloze number to ARG or 1"
+ ;; (interactive)
+ ;; (setq swarsel-anki-editor-cloze-number (or arg 1)))
+ ;; (defun anki-editor-push-tree ()
+ ;; "Push all notes under a tree."
+ ;; (interactive)
+ ;; (anki-editor-push-notes '(4))
+ ;; (anki-editor-reset-cloze-number))
+ ;; ;; Initialize
+ ;; (anki-editor-reset-cloze-number)
+ ;; )
+
+ ;; (require 'anki-editor)
#+end_src
-***** yasnippet math-snippets
+***** Own Anki functions
:PROPERTIES:
-:CUSTOM_ID: h:af0a78a5-17c2-4e13-b64a-772c27c4dee2
+:CUSTOM_ID: h:64242e95-6454-4330-bcb9-15353083bade
:END:
-The following block is mostly inspired from [[https://code.kulupu.party/thesuess/WTFmacs/]] and sets up a few prefixes that make LaTeX-math-mode nicer to use even with auctex and cape enabled.
+- These functions enable you to quickly set the destination note type and deck
#+begin_src emacs-lisp
+ ;; (defvar swarsel-anki-deck nil)
+ ;; (defvar swarsel-anki-notetype nil)
+ ;; (defvar swarsel-anki-fields nil)
- (setq wtf/latex-mathbb-prefix "''")
- (setq swarsel/latex-mathcal-prefix "``")
-
- (use-package yasnippet
- :config
+ ;; (defun swarsel-anki-set-deck-and-notetype ()
+ ;; (interactive)
+ ;; (setq swarsel-anki-deck (completing-read "Choose a deck: "
+ ;; (sort (anki-editor-deck-names) #'string-lessp)))
+ ;; (setq swarsel-anki-notetype (completing-read "Choose a note type: "
+ ;; (sort (anki-editor-note-types) #'string-lessp)))
+ ;; (setq swarsel-anki-fields (progn
+ ;; (anki-editor--anki-connect-invoke-result "modelFieldNames" `((modelName . ,swarsel-anki-notetype)))))
+ ;; )
- (setq wtf/english-alphabet
- '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"))
+ ;; (defun swarsel-anki-make-template-string ()
+ ;; (if (not swarsel-anki-deck)
+ ;; (call-interactively 'swarsel-anki-set-deck-and-notetype))
+ ;; (setq swarsel-temp swarsel-anki-fields)
+ ;; (concat (concat "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: " swarsel-anki-notetype "\n:ANKI_DECK: " swarsel-anki-deck "\n:END:\n** ")(pop swarsel-temp) "\n%?\n** " (mapconcat 'identity swarsel-temp "\n\n** ") "\n\n"))
- (dolist (elem wtf/english-alphabet)
- (when (string-equal elem (downcase elem))
- (add-to-list 'wtf/english-alphabet (upcase elem))))
+ ;; (defun swarsel-today()
+ ;; (format-time-string "%Y-%m-%d"))
+ ;; (defun swarsel-obsidian-daily ()
+ ;; (interactive)
+ ;; (if (not (file-exists-p (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory)))
+ ;; (write-region "" nil (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory))
+ ;; )
+ ;; (find-file (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory)))
- (yas-define-snippets
- 'latex-mode
- (mapcar
- (lambda (elem)
- (list (concat wtf/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem)))
- wtf/english-alphabet))
+#+end_src
- (yas-define-snippets
- 'latex-mode
- (mapcar
- (lambda (elem)
- (list (concat swarsel/latex-mathcal-prefix elem) (concat "\\mathcal{" elem "}") (concat "Mathcal letter " elem)))
- wtf/english-alphabet))
+*** Email
+:PROPERTIES:
+:CUSTOM_ID: h:2f333330-b19d-4f64-85ea-146ff28667e8
+:END:
+**** make sure mu4e is found
+:PROPERTIES:
+:CUSTOM_ID: h:48fde614-7cd0-4764-a7ac-0dae60d8b65a
+:END:
- (setq swtf/latex-math-symbols
- '(("x" . "\\times")
- ("*" . "\\cdot")
- ("." . "\\ldots")
- ("op" . "\\operatorname{$1}$0")
- ("o" . "\\circ")
- ("V" . "\\forall")
- ("v" . "\\vee")
- ("w" . "\\wedge")
- ("q" . "\\quad")
- ("f" . "\\frac{$1}{$2}$0")
- ("s" . "\\sum_{$1}^{$2}$0")
- ("p" . "\\prod_{$1}^{$2}$0")
- ("e" . "\\exists")
- ("i" . "\\int_{$1}^{$2}$0")
- ("c" . "\\cap")
- ("u" . "\\cup")
- ("0" . "\\emptyset")))
+This seems not to be needed - I do not yet dare to delete it though.
- )
+#+begin_src emacs-lisp
+ ;; (let ((mu4epath
+ ;; (concat
+ ;; (f-dirname
+ ;; (file-truename
+ ;; (executable-find "mu")))
+ ;; "/../share/emacs/site-lisp/mu4e")))
+ ;; (when (and
+ ;; (string-prefix-p "/nix/store/" mu4epath)
+ ;; (file-directory-p mu4epath))
+ ;; (add-to-list 'load-path mu4epath)))
#+end_src
-*** eglot
+**** mu4e
:PROPERTIES:
-:CUSTOM_ID: h:316857e7-4df8-4ec5-b22e-6dac918fa937
+:CUSTOM_ID: h:b92a18cf-eec3-4605-a8c2-37133ade3574
:END:
-After having tried out =lsp-mode= and =lsp-bridge= for a while each, I must say that =eglot= feels the most clean and fast to me.
+In this section we are setting up mu4e, a mail client for emacs using mu with mbsync as backend. The mail accounts themselves are setup in the NixOS configuration, so we only need to add Emacs specific settings here.
-:PROPERTIES:
-:CUSTOM_ID: h:424fbc62-84e2-42c7-a1ca-e43ea04c43e5
-:END:
+The hook functions are defined here: [[#h:34506761-06b9-43b5-a818-506d9b3faf28][mu4e functions]]
#+begin_src emacs-lisp
- (use-package eglot
+ (use-package mu4e
:ensure nil
- :hook
- ((python-mode
- python-ts-mode
- c-mode
- c-ts-mode
- c++-mode
- c++-ts-mode
- rust-ts-mode
- rustic-mode
- tex-mode
- LaTeX-mode
- ) . (lambda () (progn
- (eglot-ensure)
- (add-hook 'before-save-hook 'eglot-format nil 'local))))
- :custom
- (eldoc-echo-area-use-multiline-p nil)
- (completion-category-defaults nil)
- :bind (:map eglot-mode-map
- ("M-(" . flymake-goto-next-error)
- ("C-c ," . eglot-code-actions)))
+ ;; :load-path "/usr/share/emacs/site-lisp/mu4e/"
+ ;;:defer 20 ; Wait until 20 seconds after startup
+ :config
+
+ ;; This is set to 't' to avoid mail syncing issues when using mbsync
+ (setq send-mail-function 'sendmail-send-it)
+ (setq mu4e-change-filenames-when-moving t)
+ (setq mu4e-mu-binary (executable-find "mu"))
+ (setq mu4e-hide-index-messages t)
+
+ (setq mu4e-update-interval 180)
+ (setq mu4e-get-mail-command "mbsync -a")
+ (setq mu4e-maildir "~/Mail")
+
+ ;; enable inline images
+ (setq mu4e-view-show-images t)
+ ;; use imagemagick, if available
+ (when (fboundp 'imagemagick-register-types)
+ (imagemagick-register-types))
+
+ (setq mu4e-drafts-folder "/Drafts")
+ (setq mu4e-sent-folder "/Sent Mail")
+ (setq mu4e-refile-folder "/All Mail")
+ (setq mu4e-trash-folder "/Trash")
+
+ (setq mu4e-maildir-shortcuts
+ '((:maildir "/leon/Inbox" :key ?1)
+ (:maildir "/nautilus/Inbox" :key ?2)
+ (:maildir "/mrswarsel/Inbox" :key ?3)
+ (:maildir "/Sent Mail" :key ?s)
+ (:maildir "/Trash" :key ?t)
+ (:maildir "/Drafts" :key ?d)
+ (:maildir "/All Mail" :key ?a)))
+
+ (setq user-mail-address "leon@swarsel.win"
+ user-full-name "Leon Schwarzäugl")
- (defalias 'start-lsp-server #'eglot)
+ (setq mu4e-user-mail-address-list '(leon.schwarzaeugl@gmail.com leon@swarsel.win nautilus.dw@gmail.com mrswarsel@gmail.com)))
+
+
+ (add-hook 'mu4e-compose-mode-hook #'swarsel/mu4e-send-from-correct-address)
+ (add-hook 'mu4e-compose-post-hook #'swarsel/mu4e-restore-default)
#+end_src
-*** Breadcrumb
+**** mu4e-alert
:PROPERTIES:
-:CUSTOM_ID: h:1de35f27-335d-4cbd-beb6-f85cf5496173
+:CUSTOM_ID: h:43209eeb-5d46-472e-b7c2-58a3fb465199
:END:
-This simple shows the path to the current file on the top of the buffer - I just think it looks kind of neat, even though it is not extremely useful :)
+This adds the simple utility of sending desktop notifications whenever a new mail is received. I am using =libnotify= because I want to use this with =notify-send=.
#+begin_src emacs-lisp
- (use-package breadcrumb
- :config (breadcrumb-mode))
+ (use-package mu4e-alert
+ :config
+ (setq mu4e-alert-set-default-style 'libnotify))
+ (add-hook 'after-init-hook #'mu4e-alert-enable-notifications)
+
+ (mu4e t)
#+end_src
-*** Prevent breaking of hardlinks
+*** Calendar
:PROPERTIES:
-:CUSTOM_ID: h:e9a30d0f-423f-4e85-af4b-f8560f1c1b53
+:CUSTOM_ID: h:c760f04e-622f-4b3e-8916-53ca8cce6edc
:END:
-This setting ensures that hard links are preserved during the backup process, which is useful for maintaining the integrity of files that are linked in multiple locations.
+This provides a beautiful calender to emacs.
+
+Yes, I am aware that I am exposing my university-calendar to the public here. I can imagine worse things ;) if you however know how to obscure this, let me know!
#+begin_src emacs-lisp
- (setq backup-by-copying-when-linked t)
+ (use-package org-caldav
+ :init
+ ;; set org-caldav-sync-initalization
+ (setq swarsel-caldav-synced 0)
+ (setq org-caldav-url "https://stash.swarsel.win/remote.php/dav/calendars/Swarsele")
+ (setq org-caldav-calendars
+ '((:calendar-id "personal"
+ :inbox "~/Calendars/leon_cal.org")))
+ ;; (setq org-caldav-backup-file "~/org-caldav/org-caldav-backup.org")
+ ;; (setq org-caldav-save-directory "~/org-caldav/")
+
+ :config
+ (setq org-icalendar-alarm-time 1)
+ ;; This makes sure to-do items as a category can show up on the calendar
+ (setq org-icalendar-include-todo t)
+ ;; This ensures all org "deadlines" show up, and show up as due dates
+ (setq org-icalendar-use-deadline '(event-if-todo event-if-not-todo todo-due))
+ ;; This ensures "scheduled" org items show up, and show up as start times
+ (setq org-icalendar-use-scheduled '(todo-start event-if-todo event-if-not-todo))
+ )
+
+ (use-package calfw
+ :ensure nil
+ :bind ("C-c A" . swarsel/open-calendar)
+ :init
+ (use-package calfw-cal
+ :ensure nil)
+ (use-package calfw-org
+ :ensure nil)
+ (use-package calfw-ical
+ :ensure nil)
+ :config
+ (bind-key "g" 'cfw:refresh-calendar-buffer cfw:calendar-mode-map)
+ (bind-key "q" 'evil-quit cfw:details-mode-map)
+ ;; (custom-set-faces
+ ;; '(cfw:face-title ((t (:foreground "#f0dfaf" :weight bold :height 65))))
+ ;; )
+ )
+
+ (defun swarsel/open-calendar ()
+ (interactive)
+ (unless (eq swarsel-caldav-synced 1) (org-caldav-sync) (setq swarsel-caldav-synced 1))
+ ;; (select-frame (make-frame '((name . "calendar")))) ; makes a new frame and selects it
+ ;; (set-face-attribute 'default (selected-frame) :height 65) ; reduces the font size of the new frame
+ (cfw:open-calendar-buffer
+ :contents-sources
+ (list
+ (cfw:org-create-source "Purple") ; orgmode source
+ (cfw:ical-create-source "TISS" "https://tiss.tuwien.ac.at/events/rest/calendar/personal?locale=de&token=4463bf7a-87a3-490a-b54c-99b4a65192f3" "Cyan"))))
#+end_src
-*** Dirvish
+*** Dashboard: emacs startup screen
:PROPERTIES:
-:CUSTOM_ID: h:0918557a-8463-430c-b8df-6546dea9abd0
+:CUSTOM_ID: h:48f5be2b-b3d2-4276-bd49-2630733f23d5
:END:
-Dirvish is an improvement upon the dired-framework and has more features like file preview etc. Sadly it has an incompatibility with =openwith= which is why I have disabled that package.
+This sets up the =dashboard=, which is really quite useless. But, it looks cool and makes me happy whenever I start an emacsclient without a file name as argument :)
#+begin_src emacs-lisp
- (use-package dirvish
- :init
- (dirvish-override-dired-mode)
+ (use-package dashboard
+ :ensure t
:config
- (dirvish-peek-mode)
- (dirvish-side-follow-mode)
- (setq dirvish-open-with-programs
- (append dirvish-open-with-programs '(
- (("xlsx" "docx" "doc" "odt" "ods") "libreoffice" "%f")
- (("jpg" "jpeg" "png") "imv" "%f")
- (("pdf") "sioyek" "%f")
- (("xopp") "xournalpp" "%f"))))
- :custom
- (delete-by-moving-to-trash t)
- (dired-listing-switches
- "-l --almost-all --human-readable --group-directories-first --no-group")
- (dirvish-attributes
- '(vc-state subtree-state nerd-icons collapse file-time file-size))
- (dirvish-quick-access-entries
- '(("h" "~/" "Home")
- ("c" "~/.dotfiles/" "Config")
- ("d" "~/Downloads/" "Downloads")
- ("D" "~/Documents/" "Documents")
- ("p" "~/Documents/GitHub/" "Projects")
- ("/" "/" "Root")))
- :bind
- ((" d" . 'dirvish)
- ("C-=" . 'dirvish-side)
- :map dirvish-mode-map
- ("h" . dired-up-directory)
- ("" . dired-up-directory)
- ("l" . dired-find-file)
- ("" . dired-find-file)
- ("j" . evil-next-visual-line)
- ("k" . evil-previous-visual-line)
- ("a" . dirvish-quick-access)
- ("f" . dirvish-file-info-menu)
- ("z" . dirvish-history-last)
- ("J" . dirvish-history-jump)
- ("y" . dirvish-yank-menu)
- ("/" . dirvish-narrow)
- ("TAB" . dirvish-subtree-toggle)
- ("M-f" . dirvish-history-go-forward)
- ("M-b" . dirvish-history-go-backward)
- ("M-l" . dirvish-ls-switches-menu)
- ("M-m" . dirvish-mark-menu)
- ("M-t" . dirvish-layout-toggle)
- ("M-s" . dirvish-setup-menu)
- ("M-e" . dirvish-emerge-menu)
- ("M-j" . dirvish-fd-jump)))
+ (dashboard-setup-startup-hook)
+ ;; (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*")))
+ (setq dashboard-display-icons-p t ;; display icons on both GUI and terminal
+ dashboard-icon-type 'nerd-icons ;; use `nerd-icons' package
+ dashboard-set-file-icons t
+ dashboard-items '((recents . 5)
+ (projects . 5)
+ (agenda . 5))
+ dashboard-set-footer nil
+ dashboard-banner-logo-title "Welcome to SwarsEmacs!"
+ dashboard-image-banner-max-height 300
+ dashboard-startup-banner "~/.dotfiles/wallpaper/swarsel.png"
+ dashboard-projects-backend 'projectile
+ dashboard-projects-switch-function 'magit-status
+ dashboard-set-navigator t
+ dashboard-startupify-list '(dashboard-insert-banner
+ dashboard-insert-newline
+ dashboard-insert-banner-title
+ dashboard-insert-newline
+ dashboard-insert-navigator
+ dashboard-insert-newline
+ dashboard-insert-init-info
+ dashboard-insert-items
+ )
+ dashboard-navigator-buttons
+ `(;; line1
+ ((,""
+ "SwarselSocial"
+ "Browse Swarsele"
+ (lambda (&rest _) (browse-url "instagram.com/Swarsele")))
+
+ (,""
+ "SwarselSound"
+ "Browse SwarselSound"
+ (lambda (&rest _) (browse-url "sound.swarsel.win")) )
+ (,""
+ "SwarselSwarsel"
+ "Browse Swarsel"
+ (lambda (&rest _) (browse-url "github.com/Swarsel")) )
+ (,""
+ "SwarselStash"
+ "Browse SwarselStash"
+ (lambda (&rest _) (browse-url "stash.swarsel.win")) )
+ (,""
+ "SwarselSport"
+ "Browse SwarselSports"
+ (lambda (&rest _) (browse-url "social.parkour.wien/@Lenno")))
+ )
+ (
+ (,""
+ "swarsel.win"
+ "Browse swarsel.win"
+ (lambda (&rest _) (browse-url "swarsel.win")))
+ )
+ )))
+
#+end_src
-*** pdf-tools: pdf-viewer and support for dirvish
+* Wiki
:PROPERTIES:
-:CUSTOM_ID: h:b108dd3e-f34d-4ed3-98df-0bf9de055889
+:CUSTOM_ID: h:c4c37b94-0760-4bff-9917-f1b0f023f6c3
:END:
-This enables pdf-previewing in dirvish and gives a much better pdf-viewer than is shipped normally by emacs.
+This houses a few configuration snippets that might be useful if you are new to the nix ecosystem. It will be infrequently updated as I come across things that I deem to be interesting to such a reader. Also, interesting configuration tricks will move here if I happen to obsolete them in my main configuration.
-#+begin_src emacs-lisp
+** Importing a NixOS module that is not in nixpkgs
+:PROPERTIES:
+:CUSTOM_ID: h:b917d84e-5549-4966-8817-f1d947083ab9
+:END:
- (use-package pdf-tools
- :init
- (if (not (boundp 'pdf-tools-directory))
- (pdf-tools-install))
- :mode ("\\.pdf" . pdf-view-mode))
+This requires changes in multiple locations. As an example we will use an early version of the mautrix-signal module by Niklas Korz.
-#+end_src
+1) Add the module source to =flake.nix=:
-*** Jupyter
+ #+begin_src nix
+ {
+ inputs = {
+ [...]
+ # provides expressions for mautrix-signal
+ nixpkgs-mautrix-signal ={
+ url = github:niklaskorz/nixpkgs/nixos-23.11-mautrix-signal;
+ };
+ [...]
+ };
+
+ outputs = inputs@{
+ self,
+ [...]
+ nixpkgs-mautrix-signal,
+ [...]
+ }: let
+ [...]
+ pkgsmautrix = import nixpkgs-mautrix-signal { inherit system;
+ config.allowUnfree = true;
+ };
+ [...]
+ in {
+ nixosConfigurations = {
+ matrix = nixpkgs.lib.nixosSystem {
+ pkgs = pkgsmautrix;
+ # this is to import a service module that is not on nixpkgs
+ # this way avoids infinite recursion errors
+ specialArgs.unstable = nixpkgs-mautrix-signal;
+ modules = [
+ [...]
+ ];
+ };
+ };
+ }
+ }
+
+ #+end_src
+
+2) Import the module in the configuration (=configuration.nix=)
+
+ #+begin_src nix
+
+ [...]
+ imports = [
+ [...]
+ (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix")
+ ];
+
+ [...]
+ #+end_src
+** Build a firefox addon
:PROPERTIES:
-:CUSTOM_ID: h:c15efae7-b884-4c97-8367-ccc7e7ed9ba8
+:CUSTOM_ID: h:0ea4318a-ef11-4d9a-bef4-e994c5020989
:END:
-This is a jupyter client. Using it is a bit cumbersome though, so I have not fully explored all features.
-
-#+begin_src emacs-lisp
+1) app id can be found in the manifest.json file of the .xpi (.xpi is just a normal archive)
+2) url can be found by copy url of the "add extension" button on the addon page
+3) the rest of the information is also found in the manifest.json, but might not be needed
- (use-package ein)
+ In =configuration.nix=:
+#+begin_src nix
+ programs.firefox = {
+ [...]
+ profiles.default = {
+ [...]
+ extensions = with pkgs.nur.repos.rycee.firefox-addons; [
+ [...]
+ (buildFirefoxXpiAddon {
+ pname = ":emoji:";
+ version = "0.1.3";
+ addonId = "gonelf@gmail.com";
+ url = "https://addons.mozilla.org/firefox/downloads/file/3365324/emojidots-0.1.3.xpi";
+ sha256 = "4f7cc25c478fe52eb82f37c9ff4978dcaa3f95020398c5b184e517f6efa2c201";
+ meta = with lib;
+ {
+ description = "emoji autocomplete anywhere on the internet";
+ mozPermissions = [ "https://gist.githubusercontent.com/gonelf/d8ae3ccb7902b501c4a5dd625d4089da/raw/5eeda197ba92f8c8139e846a1225d5640077e06f/emoji_pretty.json" "tabs" "storage"];
+ platforms = platforms.all;
+ };
+ })
+ [...]
#+end_src
-
-*** undo-tree
+** Define shell utility as package
:PROPERTIES:
-:CUSTOM_ID: h:1fc538d1-8c53-48b2-8652-66046f4bbbf8
+:CUSTOM_ID: h:ce7a2467-72e0-4a13-89c0-61e3b3dbb6e7
:END:
-Base emacs undo logic is very useful, but not easy to understand for me. I prefer undo-tree, which makes switching between branches easier and also allows quickly switching back to a much older state using the visualizer.
+In =configuration.nix= (or =home.nix=):
-Evil needs to be told to use this mode, see =(evil-set-undo-system 'undo-tree)= in [[#h:218376e8-086b-46bf-91b3-78295d5d440f][Evil/General.]]
+#+begin_src nix
-By default, I am not using undo-tree-mode in every buffer. This might change in the future, but for now this is fine. It can be enabled manually should the need arise.
+ home.packages = with pkgs; [ # or for NixOS environment.systemPackages = with pkgs; [
+ [...]
+ (pkgs.writeShellApplication {
+ name = "pass-fuzzel";
+ runtimeInputs = [ pkgs.pass pkgs.fuzzel ];
+ text = ''
+ shopt -s nullglob globstar
+
+ typeit=0
+ if [[ $# -ge 1 && $1 == "--type" ]]; then
+ typeit=1
+ shift
+ fi
+
+ export PASSWORD_STORE_DIR=~/.local/share/password-store
+ prefix=''${PASSWORD_STORE_DIR-~/.local/share/password-store}
+ password_files=( "$prefix"/**/*.gpg )
+ password_files=( "''${password_files[@]#"$prefix"/}" )
+ password_files=( "''${password_files[@]%.gpg}" )
+
+ password=$(printf '%s\n' "''${password_files[@]}" | fuzzel --dmenu "$@")
-While we are at it, we are also setting up a persistent undo-file for every file that we are working with.
+ [[ -n $password ]] || exit
-#+begin_src emacs-lisp
+ if [[ $typeit -eq 0 ]]; then
+ pass show -c "$password" &>/tmp/pass-fuzzel
+ else
+ pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | wtype -
+ fi
+ notify-send -u critical -a pass -t 1000 "Copied/Typed Password"
+ '';
+ })
- (use-package undo-tree
- ;; :init (global-undo-tree-mode)
- :bind (:map undo-tree-visualizer-mode-map
- ("h" . undo-tree-visualize-switch-branch-left)
- ("l" . undo-tree-visualize-switch-branch-left)
- ("j" . undo-tree-visualize-redo)
- ("k" . undo-tree-visualize-undo))
- :config
- (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))))
+ [...]
- (add-hook 'prog-mode-hook 'undo-tree-mode)
- (add-hook 'text-mode-hook 'undo-tree-mode)
- (add-hook 'org-mode-hook 'undo-tree-mode)
- (add-hook 'latex-mode-hook 'undo-tree-mode)
#+end_src
-*** Hydra
+** Add program with prebuild binaries to nix store
:PROPERTIES:
-:CUSTOM_ID: h:b6c18dd0-3377-47ea-80c3-ac1486454e18
+:CUSTOM_ID: h:f98faf13-1e3b-4ba4-9e76-cc4b98f1c308
:END:
-Hydra allows for the writing of macro-style functions. I have not yet looked into this all too much, but it seems to be a potent feature.
-
-#+begin_src emacs-lisp
-
- (use-package hydra)
+In =configuration.nix=:
-#+end_src
+#+begin_src nix
-**** Text scaling
-:PROPERTIES:
-:CUSTOM_ID: h:c5681884-7040-4b55-ab1b-5777631a0514
-:END:
+ home.packages = with pkgs; [ # or for NixOS environment.systemPackages = with pkgs; [
+ [...]
+ (stdenv.mkDerivation {
+ name = "oama";
-I only wrote this in order to try out hydra; rarely do I really need this. However, it can be useful for [[#h:4e11a845-a7bb-4eb5-b4ce-5b2f52e07425][Presentations]]. It simply scales the text size.
+ src = pkgs.fetchurl {
+ name = "oama";
+ url = "https://github.com/pdobsan/oama/releases/download/0.13.1/oama-0.13.1-Linux-x86_64-static.tgz";
+ sha256 = "sha256-OTdCObVfnMPhgZxVtZqehgUXtKT1iyqozdkPIV+i3Gc=";
+ };
-#+begin_src emacs-lisp
+ phases = [
+ "unpackPhase"
+ ];
+ unpackPhase = ''
+ mkdir -p $out/bin
+ tar xvf $src -C $out/
+ mv $out/oama-0.13.1-Linux-x86_64-static/oama $out/bin/
+ '';
- ;; change the text size of the current buffer
- (defhydra hydra-text-scale (:timeout 4)
- "scale text"
- ("j" text-scale-increase "in")
- ("k" text-scale-decrease "out")
- ("f" nil "finished" :exit t))
+ })
-#+end_src
-*** External Applications
+ [...]
+ #+end_src
+** Patch a utilty for nix paths:
:PROPERTIES:
-:CUSTOM_ID: h:fff816a0-6d70-4bda-abab-833345e51100
+:CUSTOM_ID: h:fceba848-f065-40e0-ad3f-d16e48c24db5
:END:
-**** Obsidian
+See https://drakerossman.com/blog/how-to-patch-a-package-source-on-nixos
+** let-block for overriding a package in nixpkgs (here: replacing airsonic with airsonic-advanced)
:PROPERTIES:
-:CUSTOM_ID: h:9335d32d-bf08-4601-820d-f3d1f33f876f
+:CUSTOM_ID: h:f87f511f-f2be-486d-8297-4361eee6a0d8
:END:
-This provides an interface to Obsidian for Emacs - as much as I want to like it, I actually enjoy using the official Obsidian app more - even though that cannot be used by Emacs directly.
-
-My workflow for Obsidian is now as follows:
-
-1) create notes either in Emacs or Obsidian
-2) look at them in the official client
+This can be useful if a module does not let you use your own package yourself.
- I hope that this package will improve, then I will come back to it one day.
+In =flake.nix=:
-#+begin_src emacs-lisp
+#+begin_src nix
- ;; (use-package obsidian
- ;; :ensure t
- ;; :demand t
- ;; :config
- ;; (obsidian-specify-path swarsel-obsidian-vault-directory)
- ;; (global-obsidian-mode t)
- ;; :custom
- ;; ;; This directory will be used for `obsidian-capture' if set.
- ;; (obsidian-inbox-directory "Inbox")
- ;; (bind-key (kbd "C-c M-o") 'obsidian-hydra/body 'obsidian-mode-map)
- ;; :bind (:map obsidian-mode-map
- ;; ;; Replace C-c C-o with Obsidian.el's implementation. It's ok to use another key binding.
- ;; ("C-c C-o" . obsidian-follow-link-at-point)
- ;; ;; Jump to backlinks
- ;; ("C-c C-b" . obsidian-backlink-jump)
- ;; ;; If you prefer you can use `obsidian-insert-link'
- ;; ("C-c C-l" . obsidian-insert-wikilink)))
+ pkgs = import nixpkgs { inherit system;
+ overlays = [ emacs-overlay.overlay
+ nur.overlay
+ nixgl.overlay
+ (self: super: {
+ airsonic = super.airsonic.overrideAttrs (_: rec {
+ version = "11.0.2-kagemomiji";
+ name = "airsonic-advanced-${version}";
+ src = super.fetchurl {
+ url = "https://github.com/kagemomiji/airsonic-advanced/releases/download/11.0.2/airsonic.war";
+ sha256 = "PgErtEizHraZgoWHs5jYJJ5NsliDd9VulQfS64ackFo=";
+ };
+ });
+ })
+ ];
+ config.allowUnfree = true;
+ };
#+end_src
-
-**** Anki
+** Reference configurations
:PROPERTIES:
-:CUSTOM_ID: h:5854c9a6-1319-4961-a112-75b1bf2e1f69
+:CUSTOM_ID: h:236b7d18-d97b-4714-805f-2ca4d8b1c3c2
:END:
-This section is here to make Anki usable from within Emacs - an endeavour that I have mostly given up on.
+Configurations that I have retired or are there for the general study.
-***** Basic Anki setup
+*** non-nixos
:PROPERTIES:
-:CUSTOM_ID: h:d20559ed-7ada-4fea-a964-33bfd64b4549
+:CUSTOM_ID: h:60bd347b-81c5-47b2-82f7-2e6a0c888d3e
:END:
+My Surface Pro 3, only used for on-the-go university work. Be careful when pushing large changes to this machine, as it easily runs out of memory on large switches. At the moment the only machine running non-NixOS, so special care must be taken not to break this one during updates.
-#+begin_src emacs-lisp
+***** Channel setup
+:PROPERTIES:
+:CUSTOM_ID: h:63e6e03a-8c1e-45f4-aec2-7ca351eccd35
+:END:
- ;; (use-package anki-editor
- ;; :after org
- ;; :bind (:map org-mode-map
- ;; ("" . anki-editor-cloze-region-auto-incr)
- ;; ("" . anki-editor-cloze-region-dont-incr)
- ;; ("" . anki-editor-reset-cloze-number)
- ;; ("" . anki-editor-push-tree))
- ;; :hook (org-capture-after-finalize . anki-editor-reset-cloze-number) ; Reset cloze-number after each capture.
- ;; :config
- ;; (setq anki-editor-create-decks t ;; Allow anki-editor to create a new deck if it doesn't exist
- ;; anki-editor-org-tags-as-anki-tags t)
+This installs nixGL, which is needed to run GL apps installed through home-manager, since this machine is not using NixOS.
- ;; (defun anki-editor-cloze-region-auto-incr (&optional arg)
- ;; "Cloze region without hint and increase card number."
- ;; (interactive)
- ;; (anki-editor-cloze-region swarsel-anki-editor-cloze-number "")
- ;; (setq swarsel-anki-editor-cloze-number (1+ swarsel-anki-editor-cloze-number))
- ;; (forward-sexp))
- ;; (defun anki-editor-cloze-region-dont-incr (&optional arg)
- ;; "Cloze region without hint using the previous card number."
- ;; (interactive)
- ;; (anki-editor-cloze-region (1- swarsel-anki-editor-cloze-number) "")
- ;; (forward-sexp))
- ;; (defun anki-editor-reset-cloze-number (&optional arg)
- ;; "Reset cloze number to ARG or 1"
- ;; (interactive)
- ;; (setq swarsel-anki-editor-cloze-number (or arg 1)))
- ;; (defun anki-editor-push-tree ()
- ;; "Push all notes under a tree."
- ;; (interactive)
- ;; (anki-editor-push-notes '(4))
- ;; (anki-editor-reset-cloze-number))
- ;; ;; Initialize
- ;; (anki-editor-reset-cloze-number)
- ;; )
+This is not super clean (because it is not fully replicative), but I do not really care.
- ;; (require 'anki-editor)
+1) Install nixGL:
+#+begin_src nix
+ nix-channel --add https://github.com/guibou/nixGL/archive/main.tar.gz nixgl && nix-channel --update
+ nix-env -iA nixgl.auto.nixGLDefault # or replace `nixGLDefault` with your desired wrapper
#+end_src
-***** Own Anki functions
+This is needed in order to use EGL. Prefix programs that use it with `nixGL`
+
+***** Home manager
:PROPERTIES:
-:CUSTOM_ID: h:64242e95-6454-4330-bcb9-15353083bade
+:CUSTOM_ID: h:483a26b5-5a40-4417-9ffb-67cc2cf07161
:END:
-- These functions enable you to quickly set the destination note type and deck
+Special things to note here: We are running xcape to allow =CAPS= to act as =CTRL= and =ESC=. Also we are using =nixGL= in most places.
-#+begin_src emacs-lisp
+#+begin_src nix
- ;; (defvar swarsel-anki-deck nil)
- ;; (defvar swarsel-anki-notetype nil)
- ;; (defvar swarsel-anki-fields nil)
+ { config, pkgs, lib, fetchFromGitHub, ... }:
- ;; (defun swarsel-anki-set-deck-and-notetype ()
- ;; (interactive)
- ;; (setq swarsel-anki-deck (completing-read "Choose a deck: "
- ;; (sort (anki-editor-deck-names) #'string-lessp)))
- ;; (setq swarsel-anki-notetype (completing-read "Choose a note type: "
- ;; (sort (anki-editor-note-types) #'string-lessp)))
- ;; (setq swarsel-anki-fields (progn
- ;; (anki-editor--anki-connect-invoke-result "modelFieldNames" `((modelName . ,swarsel-anki-notetype)))))
- ;; )
+ {
+ programs.home-manager.enable = true;
+ home.username = "leons";
+ home.homeDirectory = "/home/leons";
- ;; (defun swarsel-anki-make-template-string ()
- ;; (if (not swarsel-anki-deck)
- ;; (call-interactively 'swarsel-anki-set-deck-and-notetype))
- ;; (setq swarsel-temp swarsel-anki-fields)
- ;; (concat (concat "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: " swarsel-anki-notetype "\n:ANKI_DECK: " swarsel-anki-deck "\n:END:\n** ")(pop swarsel-temp) "\n%?\n** " (mapconcat 'identity swarsel-temp "\n\n** ") "\n\n"))
+ home.stateVersion = "23.05"; # Please read the comment before changing.
- ;; (defun swarsel-today()
- ;; (format-time-string "%Y-%m-%d"))
+ stylix.image = ../../wallpaper/surfacewp.png;
+ <>
- ;; (defun swarsel-obsidian-daily ()
- ;; (interactive)
- ;; (if (not (file-exists-p (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory)))
- ;; (write-region "" nil (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory))
- ;; )
- ;; (find-file (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory)))
+ nixpkgs = {
+ config = {
+ allowUnfree = true;
+ allowUnfreePredicate = (_: true);
+ };
+ };
+ services.xcape = {
+ enable = true;
+ mapExpression = {
+ Control_L = "Escape";
+ };
+ };
+ #keyboard config
+ home.keyboard.layout = "us";
-#+end_src
+ sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
-*** Email
-:PROPERTIES:
-:CUSTOM_ID: h:2f333330-b19d-4f64-85ea-146ff28667e8
-:END:
-**** make sure mu4e is found
-:PROPERTIES:
-:CUSTOM_ID: h:48fde614-7cd0-4764-a7ac-0dae60d8b65a
-:END:
+ # waybar config
+ programs.waybar.settings.mainBar.cpu.format = "{icon0} {icon1} {icon2} {icon3}";
+
+ programs.waybar.settings.mainBar.temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon3/temp3_input";
+ programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark" "mpris" "custom/left-arrow-light"
+ "network"
+ "custom/left-arrow-dark"
+ "pulseaudio"
+ "custom/left-arrow-light"
+ "battery"
+ "custom/left-arrow-dark"
+ "temperature"
+ "custom/left-arrow-light"
+ "disk"
+ "custom/left-arrow-dark"
+ "memory"
+ "custom/left-arrow-light"
+ "cpu"
+ "custom/left-arrow-dark"
+ "tray"
+ "custom/left-arrow-light"
+ "clock#2"
+ "custom/left-arrow-dark"
+ "clock#1" ];
+ services.blueman-applet.enable = true;
+ home.packages = with pkgs; [
+ # nixgl.auto.nixGLDefault
+ evince
+ # nodejs_20
-This seems not to be needed - I do not yet dare to delete it though.
+ # messaging
+ # we use gomuks for RAM preservation, but keep schildi around for files and images
+ ];
-#+begin_src emacs-lisp
+ programs.zsh.initExtra = "
+ export GPG_TTY=\"$(tty)\"
+ export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
+ gpgconf --launch gpg-agent
+ ";
- ;; (let ((mu4epath
- ;; (concat
- ;; (f-dirname
- ;; (file-truename
- ;; (executable-find "mu")))
- ;; "/../share/emacs/site-lisp/mu4e")))
- ;; (when (and
- ;; (string-prefix-p "/nix/store/" mu4epath)
- ;; (file-directory-p mu4epath))
- ;; (add-to-list 'load-path mu4epath)))
+ # sway config
+ wayland.windowManager.sway= {
+ config = rec {
+ input = {
+ "*" = {
+ xkb_layout = "us";
+ xkb_options = "ctrl:nocaps,grp:win_space_toggle";
+ xkb_variant = "altgr-intl";
+ };
+ "type:touchpad" = {
+ dwt = "enabled";
+ tap = "enabled";
+ natural_scroll = "enabled";
+ middle_emulation = "enabled";
+ };
+ };
-#+end_src
+ output = {
+ eDP-1 = {
+ mode = "2160x1440@59.955Hz";
+ scale = "1";
+ bg = "~/.dotfiles/wallpaper/surfacewp.png fill";
+ };
+ };
-**** mu4e
-:PROPERTIES:
-:CUSTOM_ID: h:b92a18cf-eec3-4605-a8c2-37133ade3574
-:END:
+ keybindings = let
+ modifier = config.wayland.windowManager.sway.config.modifier;
+ in {
+ "${modifier}+F2" = "exec brightnessctl set +5%";
+ "${modifier}+F1"= "exec brightnessctl set 5%-";
+ "${modifier}+n" = "exec sway output eDP-1 transform normal, splith";
+ "${modifier}+Ctrl+p" = "exec nixGL wl-mirror eDP-1";
+ "${modifier}+t" = "exec sway output eDP-1 transform 90, splitv";
+ "${modifier}+XF86AudioLowerVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
+ "${modifier}+XF86AudioRaiseVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
+ "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkgomuks.sh\"";
+ };
-In this section we are setting up mu4e, a mail client for emacs using mu with mbsync as backend. The mail accounts themselves are setup in the NixOS configuration, so we only need to add Emacs specific settings here.
+ startup = [
+ { command = "sleep 60 && nixGL nextcloud --background";}
+ # { command = "sleep 60 && nixGL spotify";}
+ { command = "sleep 60 && nixGL discord --start-minimized -enable-features=UseOzonePlatform -ozone-platform=wayland";}
+ # { command = "sleep 60 && nixGL schildichat-desktop --hidden";}
+ { command = "sleep 60 && nixGL syncthingtray --wait"; }
+ { command = "sleep 60 && ANKI_WAYLAND=1 nixGL anki";}
+ { command = "nm-applet --indicator";}
+ { command = "sleep 60 && OBSIDIAN_USE_WAYLAND=1 nixGL obsidian -enable-features=UseOzonePlatform -ozone-platform=wayland";}
+ ];
-The hook functions are defined here: [[#h:34506761-06b9-43b5-a818-506d9b3faf28][mu4e functions]]
+ keycodebindings = {
+ "124" = "exec systemctl suspend";
+ };
+ };
+
+ extraConfig = "
+ exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05 map_to_output eDP-1
+ exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05_Stylus map_to_output eDP-1
+ ";
+ };
+ }
+
+#+end_src
+*** nixos
+:PROPERTIES:
+:CUSTOM_ID: h:3f747cb3-bf83-4cb6-8fe4-6a4865472eeb
+:END:
+***** Onett (Lenovo Y510P)
+:PROPERTIES:
+:CUSTOM_ID: h:80753b6b-667e-4b04-a260-a3b5c73fb624
+:END:
-#+begin_src emacs-lisp
+My laptop, sadly soon to be replaced by a new one, since most basic functions are stopping to work lately.
- (use-package mu4e
- :ensure nil
- ;; :load-path "/usr/share/emacs/site-lisp/mu4e/"
- ;;:defer 20 ; Wait until 20 seconds after startup
- :config
+****** NixOS
+:PROPERTIES:
+:CUSTOM_ID: h:6f3fe0dc-a857-440a-b4bd-c32fd9024b8b
+:END:
- ;; This is set to 't' to avoid mail syncing issues when using mbsync
- (setq send-mail-function 'sendmail-send-it)
- (setq mu4e-change-filenames-when-moving t)
- (setq mu4e-mu-binary (executable-find "mu"))
- (setq mu4e-hide-index-messages t)
+#+begin_src nix
- (setq mu4e-update-interval 180)
- (setq mu4e-get-mail-command "mbsync -a")
- (setq mu4e-maildir "~/Mail")
+ { config, lib, pkgs, inputs, ... }:
- ;; enable inline images
- (setq mu4e-view-show-images t)
- ;; use imagemagick, if available
- (when (fboundp 'imagemagick-register-types)
- (imagemagick-register-types))
+ {
- (setq mu4e-drafts-folder "/Drafts")
- (setq mu4e-sent-folder "/Sent Mail")
- (setq mu4e-refile-folder "/All Mail")
- (setq mu4e-trash-folder "/Trash")
+ <>
- (setq mu4e-maildir-shortcuts
- '((:maildir "/leon/Inbox" :key ?1)
- (:maildir "/nautilus/Inbox" :key ?2)
- (:maildir "/mrswarsel/Inbox" :key ?3)
- (:maildir "/Sent Mail" :key ?s)
- (:maildir "/Trash" :key ?t)
- (:maildir "/Drafts" :key ?d)
- (:maildir "/All Mail" :key ?a)))
+ services = {
+ greetd.settings.initial_session.user ="swarsel";
+ xserver.videoDrivers = ["nvidia"];
+ };
- (setq user-mail-address "leon@swarsel.win"
- user-full-name "Leon Schwarzäugl")
+ hardware = {
+ nvidia = {
+ modesetting.enable = true;
+ powerManagement.enable = true;
+ prime = {
+ intelBusId = "PCI:0:2:0";
+ nvidiaBusId = "PCI:1:0:0";
+ sync.enable = true;
+ };
+ };
+ pulseaudio.configFile = pkgs.runCommand "default.pa" {} ''
+ sed 's/module-udev-detect$/module-udev-detect tsched=0/' \
+ ${pkgs.pulseaudio}/etc/pulse/default.pa > $out
+ '';
+ bluetooth.enable = true;
+ };
- (setq mu4e-user-mail-address-list '(leon.schwarzaeugl@gmail.com leon@swarsel.win nautilus.dw@gmail.com mrswarsel@gmail.com)))
+ stylix.image = ../../wallpaper/lenovowp.png;
+ <>
+ boot.loader.grub = {
+ enable = true;
+ device = "/dev/sda";
+ useOSProber = true;
+ };
- (add-hook 'mu4e-compose-mode-hook #'swarsel/mu4e-send-from-correct-address)
- (add-hook 'mu4e-compose-post-hook #'swarsel/mu4e-restore-default)
-#+end_src
+ networking.hostName = "onett"; # Define your hostname.
+ networking.enableIPv6 = false;
-**** mu4e-alert
-:PROPERTIES:
-:CUSTOM_ID: h:43209eeb-5d46-472e-b7c2-58a3fb465199
-:END:
+ users.users.swarsel = {
+ isNormalUser = true;
+ description = "Leon S";
+ extraGroups = [ "networkmanager" "wheel" "lp"];
+ packages = with pkgs; [];
+ };
-This adds the simple utility of sending desktop notifications whenever a new mail is received. I am using =libnotify= because I want to use this with =notify-send=.
+ system.stateVersion = "23.05"; # Did you read the comment?
-#+begin_src emacs-lisp
+ environment.systemPackages = with pkgs; [
+ ];
- (use-package mu4e-alert
- :config
- (setq mu4e-alert-set-default-style 'libnotify))
- (add-hook 'after-init-hook #'mu4e-alert-enable-notifications)
+ }
- (mu4e t)
#+end_src
-
-*** Calendar
+****** Home Manager
:PROPERTIES:
-:CUSTOM_ID: h:c760f04e-622f-4b3e-8916-53ca8cce6edc
+:CUSTOM_ID: h:7b76c914-c9b2-47b5-ba89-c501d6391110
:END:
-This provides a beautiful calender to emacs.
+#+begin_src nix
-Yes, I am aware that I am exposing my university-calendar to the public here. I can imagine worse things ;) if you however know how to obscure this, let me know!
+ { config, pkgs, lib, fetchFromGitHub, ... }:
-#+begin_src emacs-lisp
+ {
- (use-package org-caldav
- :init
- ;; set org-caldav-sync-initalization
- (setq swarsel-caldav-synced 0)
- (setq org-caldav-url "https://stash.swarsel.win/remote.php/dav/calendars/Swarsele")
- (setq org-caldav-calendars
- '((:calendar-id "personal"
- :inbox "~/Calendars/leon_cal.org")))
- ;; (setq org-caldav-backup-file "~/org-caldav/org-caldav-backup.org")
- ;; (setq org-caldav-save-directory "~/org-caldav/")
+ <>
- :config
- (setq org-icalendar-alarm-time 1)
- ;; This makes sure to-do items as a category can show up on the calendar
- (setq org-icalendar-include-todo t)
- ;; This ensures all org "deadlines" show up, and show up as due dates
- (setq org-icalendar-use-deadline '(event-if-todo event-if-not-todo todo-due))
- ;; This ensures "scheduled" org items show up, and show up as start times
- (setq org-icalendar-use-scheduled '(todo-start event-if-todo event-if-not-todo))
- )
+ home = {
+ username = "swarsel";
+ homeDirectory = "/home/swarsel";
+ stateVersion = "23.05"; # Please read the comment before changing.
+ keyboard.layout = "de";
+ packages = with pkgs; [
+ ];
+ };
- (use-package calfw
- :ensure nil
- :bind ("C-c A" . swarsel/open-calendar)
- :init
- (use-package calfw-cal
- :ensure nil)
- (use-package calfw-org
- :ensure nil)
- (use-package calfw-ical
- :ensure nil)
- :config
- (bind-key "g" 'cfw:refresh-calendar-buffer cfw:calendar-mode-map)
- (bind-key "q" 'evil-quit cfw:details-mode-map)
- ;; (custom-set-faces
- ;; '(cfw:face-title ((t (:foreground "#f0dfaf" :weight bold :height 65))))
- ;; )
- )
+ sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
- (defun swarsel/open-calendar ()
- (interactive)
- (unless (eq swarsel-caldav-synced 1) (org-caldav-sync) (setq swarsel-caldav-synced 1))
- ;; (select-frame (make-frame '((name . "calendar")))) ; makes a new frame and selects it
- ;; (set-face-attribute 'default (selected-frame) :height 65) ; reduces the font size of the new frame
- (cfw:open-calendar-buffer
- :contents-sources
- (list
- (cfw:org-create-source "Purple") ; orgmode source
- (cfw:ical-create-source "TISS" "https://tiss.tuwien.ac.at/events/rest/calendar/personal?locale=de&token=4463bf7a-87a3-490a-b54c-99b4a65192f3" "Cyan"))))
+ # # waybar config
+ programs.waybar.settings.mainBar = {
+ cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
+ temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon3/temp3_input";
+ };
+ <>
-#+end_src
+ services.blueman-applet.enable = true;
-*** Dashboard: emacs startup screen
-:PROPERTIES:
-:CUSTOM_ID: h:48f5be2b-b3d2-4276-bd49-2630733f23d5
-:END:
+ wayland.windowManager.sway= {
+ config = rec {
+ input = {
+ "1:1:AT_Translated_Set_2_keyboard" = {
+ xkb_layout = "us";
+ xkb_options = "grp:win_space_toggle";
+ # xkb_options = "ctrl:nocaps,grp:win_space_toggle";
+ xkb_variant = "altgr-intl";
+ };
+ "2362:33538:ipad_keyboard_Keyboard" = {
+ xkb_layout = "us";
+ xkb_options = "altwin:swap_lalt_lwin,ctrl:nocaps,grp:win_space_toggle";
+ xkb_variant = "colemak_dh";
+ };
+ "36125:53060:splitkb.com_Kyria_rev3" = {
+ xkb_layout = "us";
+ xkb_variant = "altgr-intl";
+ };
-This sets up the =dashboard=, which is really quite useless. But, it looks cool and makes me happy whenever I start an emacsclient without a file name as argument :)
+ "type:touchpad" = {
+ dwt = "enabled";
+ tap = "enabled";
+ natural_scroll = "enabled";
+ middle_emulation = "enabled";
+ };
+ };
-#+begin_src emacs-lisp
+ output = {
+ eDP-1 = {
+ mode = "1920x1080";
+ scale = "1";
+ bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ position = "1920,0";
+ };
+ VGA-1 = {
+ mode = "1920x1080";
+ scale = "1";
+ bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ position = "0,0";
+ };
+ };
- (use-package dashboard
- :ensure t
- :config
- (dashboard-setup-startup-hook)
- ;; (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*")))
- (setq dashboard-display-icons-p t ;; display icons on both GUI and terminal
- dashboard-icon-type 'nerd-icons ;; use `nerd-icons' package
- dashboard-set-file-icons t
- dashboard-items '((recents . 5)
- (projects . 5)
- (agenda . 5))
- dashboard-set-footer nil
- dashboard-banner-logo-title "Welcome to SwarsEmacs!"
- dashboard-image-banner-max-height 300
- dashboard-startup-banner "~/.dotfiles/wallpaper/swarsel.png"
- dashboard-projects-backend 'projectile
- dashboard-projects-switch-function 'magit-status
- dashboard-set-navigator t
- dashboard-startupify-list '(dashboard-insert-banner
- dashboard-insert-newline
- dashboard-insert-banner-title
- dashboard-insert-newline
- dashboard-insert-navigator
- dashboard-insert-newline
- dashboard-insert-init-info
- dashboard-insert-items
- )
- dashboard-navigator-buttons
- `(;; line1
- ((,""
- "SwarselSocial"
- "Browse Swarsele"
- (lambda (&rest _) (browse-url "instagram.com/Swarsele")))
+ keybindings = let
+ modifier = config.wayland.windowManager.sway.config.modifier;
+ in {
+ "${modifier}+F2" = "exec brightnessctl set +5%";
+ "${modifier}+F1"= "exec brightnessctl set 5%-";
+ "XF86MonBrightnessUp" = "exec brightnessctl set +5%";
+ "XF86MonBrightnessDown"= "exec brightnessctl set 5%-";
+ "${modifier}+Ctrl+p" = "exec wl-mirror eDP-1";
+ "XF86HomePage" = "exec wtype -P Escape -p Escape";
+ "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\"";
+ };
+ keycodebindings = {
+ "94" = "exec wtype c";
+ "Shift+94" = "exec wtype C";
+ "Ctrl+94" = "exec wtype -M ctrl c -m ctrl";
+ "Ctrl+Shift+94" = "exec wtype -M ctrl -M shift c -m ctrl -m shift";
+ };
- (,""
- "SwarselSound"
- "Browse SwarselSound"
- (lambda (&rest _) (browse-url "sound.swarsel.win")) )
- (,""
- "SwarselSwarsel"
- "Browse Swarsel"
- (lambda (&rest _) (browse-url "github.com/Swarsel")) )
- (,""
- "SwarselStash"
- "Browse SwarselStash"
- (lambda (&rest _) (browse-url "stash.swarsel.win")) )
- (,""
- "SwarselSport"
- "Browse SwarselSports"
- (lambda (&rest _) (browse-url "social.parkour.wien/@Lenno")))
- )
- (
- (,""
- "swarsel.win"
- "Browse swarsel.win"
- (lambda (&rest _) (browse-url "swarsel.win")))
- )
- )))
+ startup = [
+ <>
+ ];
+ };
+ extraConfig = "
+ ";
+ };
+ }
#+end_src
diff --git a/Wiki.org b/Wiki.org
deleted file mode 100644
index 9986140..0000000
--- a/Wiki.org
+++ /dev/null
@@ -1,536 +0,0 @@
-#+title: Useful Nix bits
-
-This pages houses a few configuration snippets that might be useful if you are new to the nix ecosystem. It will be infrequently updated as I come across things that I deem to be interesting to such a reader.
-
-* Importing a NixOS module that is not in nixpkgs
-
-This requires changes in multiple locations. As an example we will use an early version of the mautrix-signal module by Niklas Korz.
-
-1) Add the module source to flake.nix:
-
- #+begin_src nix flake.nix
- {
- inputs = {
- [...]
- # provides expressions for mautrix-signal
- nixpkgs-mautrix-signal ={
- url = github:niklaskorz/nixpkgs/nixos-23.11-mautrix-signal;
- };
- [...]
- };
-
- outputs = inputs@{
- self,
- [...]
- nixpkgs-mautrix-signal,
- [...]
- }: let
- [...]
- pkgsmautrix = import nixpkgs-mautrix-signal { inherit system;
- config.allowUnfree = true;
- };
- [...]
- in {
- nixosConfigurations = {
- matrix = nixpkgs.lib.nixosSystem {
- pkgs = pkgsmautrix;
- # this is to import a service module that is not on nixpkgs
- # this way avoids infinite recursion errors
- specialArgs.unstable = nixpkgs-mautrix-signal;
- modules = [
- [...]
- ];
- };
- };
- }
- }
-
- #+end_src
-
-2) Import the module in the configuration:
-
- #+begin_src nix configuration.nix
-
- [...]
- imports = [
- [...]
- (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix")
- ];
-
- [...]
- #+end_src
-
-* Build a firefox addon
-
-1) app id can be found in the manifest.json file of the .xpi (.xpi is just a normal archive)
-2) url can be found by copy url of the "add extension" button on the addon page
-3) the rest of the information is also found in the manifest.json, but might not be needed
-
-#+begin_src nix configuration.nix
- programs.firefox = {
- [...]
- profiles.default = {
- [...]
- extensions = with pkgs.nur.repos.rycee.firefox-addons; [
- [...]
- (buildFirefoxXpiAddon {
- pname = ":emoji:";
- version = "0.1.3";
- addonId = "gonelf@gmail.com";
- url = "https://addons.mozilla.org/firefox/downloads/file/3365324/emojidots-0.1.3.xpi";
- sha256 = "4f7cc25c478fe52eb82f37c9ff4978dcaa3f95020398c5b184e517f6efa2c201";
- meta = with lib;
- {
- description = "emoji autocomplete anywhere on the internet";
- mozPermissions = [ "https://gist.githubusercontent.com/gonelf/d8ae3ccb7902b501c4a5dd625d4089da/raw/5eeda197ba92f8c8139e846a1225d5640077e06f/emoji_pretty.json" "tabs" "storage"];
- platforms = platforms.all;
- };
- })
- [...]
-#+end_src
-
-* Define shell utility as package
-
-#+begin_src nix configuration.nix
-
- home.packages = with pkgs; [ # or for NixOS environment.systemPackages = with pkgs; [
- [...]
- (pkgs.writeShellApplication {
- name = "pass-fuzzel";
- runtimeInputs = [ pkgs.pass pkgs.fuzzel ];
- text = ''
- shopt -s nullglob globstar
-
- typeit=0
- if [[ $# -ge 1 && $1 == "--type" ]]; then
- typeit=1
- shift
- fi
-
- export PASSWORD_STORE_DIR=~/.local/share/password-store
- prefix=''${PASSWORD_STORE_DIR-~/.local/share/password-store}
- password_files=( "$prefix"/**/*.gpg )
- password_files=( "''${password_files[@]#"$prefix"/}" )
- password_files=( "''${password_files[@]%.gpg}" )
-
- password=$(printf '%s\n' "''${password_files[@]}" | fuzzel --dmenu "$@")
-
- [[ -n $password ]] || exit
-
- if [[ $typeit -eq 0 ]]; then
- pass show -c "$password" &>/tmp/pass-fuzzel
- else
- pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | wtype -
- fi
- notify-send -u critical -a pass -t 1000 "Copied/Typed Password"
- '';
- })
-
- [...]
-
-#+end_src
-
-* Add program with prebuild binaries to nix store
-
-#+begin_src nix configuration.nix
-
- home.packages = with pkgs; [ # or for NixOS environment.systemPackages = with pkgs; [
- [...]
- (stdenv.mkDerivation {
- name = "oama";
-
- src = pkgs.fetchurl {
- name = "oama";
- url = "https://github.com/pdobsan/oama/releases/download/0.13.1/oama-0.13.1-Linux-x86_64-static.tgz";
- sha256 = "sha256-OTdCObVfnMPhgZxVtZqehgUXtKT1iyqozdkPIV+i3Gc=";
- };
-
- phases = [
- "unpackPhase"
- ];
-
- unpackPhase = ''
- mkdir -p $out/bin
- tar xvf $src -C $out/
- mv $out/oama-0.13.1-Linux-x86_64-static/oama $out/bin/
- '';
-
- })
-
- [...]
- #+end_src
-
-* Patch a utilty for nix paths:
-See https://drakerossman.com/blog/how-to-patch-a-package-source-on-nixos
-* let-block for overriding a package in nixpkgs (here: replacing airsonic with airsonic-advanced)
-
-This can be useful if a module does not let you use your own package yourself.
-
-#+begin_src nix :tangle no
-
- pkgs = import nixpkgs { inherit system;
- overlays = [ emacs-overlay.overlay
- nur.overlay
- nixgl.overlay
- (self: super: {
- airsonic = super.airsonic.overrideAttrs (_: rec {
- version = "11.0.2-kagemomiji";
- name = "airsonic-advanced-${version}";
- src = super.fetchurl {
- url = "https://github.com/kagemomiji/airsonic-advanced/releases/download/11.0.2/airsonic.war";
- sha256 = "PgErtEizHraZgoWHs5jYJJ5NsliDd9VulQfS64ackFo=";
- };
- });
- })
- ];
- config.allowUnfree = true;
- };
-
-#+end_src
-
-* Reference configurations
-
-Configurations that I have retired or are there for the general study.
-
-** non-nixos
-:PROPERTIES:
-:CUSTOM_ID: h:42339b42-c64b-4d0c-a80c-5c44d3423fce
-:END:
-
-My Surface Pro 3, only used for on-the-go university work. Be careful when pushing large changes to this machine, as it easily runs out of memory on large switches. At the moment the only machine running non-NixOS, so special care must be taken not to break this one during updates.
-
-**** Channel setup
-:PROPERTIES:
-:CUSTOM_ID: h:42e45181-9d78-4266-a9a0-9621032f38b0
-:END:
-
-This installs nixGL, which is needed to run GL apps installed through home-manager, since this machine is not using NixOS.
-
-This is not super clean (because it is not fully replicative), but I do not really care.
-
-1) Install nixGL:
-
-#+begin_src nix :tangle no
- nix-channel --add https://github.com/guibou/nixGL/archive/main.tar.gz nixgl && nix-channel --update
- nix-env -iA nixgl.auto.nixGLDefault # or replace `nixGLDefault` with your desired wrapper
-#+end_src
-
-This is needed in order to use EGL. Prefix programs that use it with `nixGL`
-
-**** Home manager
-:PROPERTIES:
-:CUSTOM_ID: h:929d56f5-e16f-4341-901c-24e8a8450398
-:END:
-
-Special things to note here: We are running xcape to allow =CAPS= to act as =CTRL= and =ESC=. Also we are using =nixGL= in most places.
-
-#+begin_src nix :noweb yes :tangle profiles/surface/home.nix
-
- { config, pkgs, lib, fetchFromGitHub, ... }:
-
- {
- programs.home-manager.enable = true;
- home.username = "leons";
- home.homeDirectory = "/home/leons";
-
- home.stateVersion = "23.05"; # Please read the comment before changing.
-
- stylix.image = ../../wallpaper/surfacewp.png;
- <>
-
- nixpkgs = {
- config = {
- allowUnfree = true;
- allowUnfreePredicate = (_: true);
- };
- };
- services.xcape = {
- enable = true;
- mapExpression = {
- Control_L = "Escape";
- };
- };
- #keyboard config
- home.keyboard.layout = "us";
-
- sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
-
- # waybar config
- programs.waybar.settings.mainBar.cpu.format = "{icon0} {icon1} {icon2} {icon3}";
-
- programs.waybar.settings.mainBar.temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon3/temp3_input";
- programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark" "mpris" "custom/left-arrow-light"
- "network"
- "custom/left-arrow-dark"
- "pulseaudio"
- "custom/left-arrow-light"
- "battery"
- "custom/left-arrow-dark"
- "temperature"
- "custom/left-arrow-light"
- "disk"
- "custom/left-arrow-dark"
- "memory"
- "custom/left-arrow-light"
- "cpu"
- "custom/left-arrow-dark"
- "tray"
- "custom/left-arrow-light"
- "clock#2"
- "custom/left-arrow-dark"
- "clock#1" ];
- services.blueman-applet.enable = true;
- home.packages = with pkgs; [
- # nixgl.auto.nixGLDefault
- evince
- # nodejs_20
-
- # messaging
- # we use gomuks for RAM preservation, but keep schildi around for files and images
- ];
-
- programs.zsh.initExtra = "
- export GPG_TTY=\"$(tty)\"
- export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
- gpgconf --launch gpg-agent
- ";
-
- # sway config
- wayland.windowManager.sway= {
- config = rec {
- input = {
- "*" = {
- xkb_layout = "us";
- xkb_options = "ctrl:nocaps,grp:win_space_toggle";
- xkb_variant = "altgr-intl";
- };
- "type:touchpad" = {
- dwt = "enabled";
- tap = "enabled";
- natural_scroll = "enabled";
- middle_emulation = "enabled";
- };
- };
-
- output = {
- eDP-1 = {
- mode = "2160x1440@59.955Hz";
- scale = "1";
- bg = "~/.dotfiles/wallpaper/surfacewp.png fill";
- };
- };
-
- keybindings = let
- modifier = config.wayland.windowManager.sway.config.modifier;
- in {
- "${modifier}+F2" = "exec brightnessctl set +5%";
- "${modifier}+F1"= "exec brightnessctl set 5%-";
- "${modifier}+n" = "exec sway output eDP-1 transform normal, splith";
- "${modifier}+Ctrl+p" = "exec nixGL wl-mirror eDP-1";
- "${modifier}+t" = "exec sway output eDP-1 transform 90, splitv";
- "${modifier}+XF86AudioLowerVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
- "${modifier}+XF86AudioRaiseVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
- "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkgomuks.sh\"";
- };
-
- startup = [
- { command = "sleep 60 && nixGL nextcloud --background";}
- # { command = "sleep 60 && nixGL spotify";}
- { command = "sleep 60 && nixGL discord --start-minimized -enable-features=UseOzonePlatform -ozone-platform=wayland";}
- # { command = "sleep 60 && nixGL schildichat-desktop --hidden";}
- { command = "sleep 60 && nixGL syncthingtray --wait"; }
- { command = "sleep 60 && ANKI_WAYLAND=1 nixGL anki";}
- { command = "nm-applet --indicator";}
- { command = "sleep 60 && OBSIDIAN_USE_WAYLAND=1 nixGL obsidian -enable-features=UseOzonePlatform -ozone-platform=wayland";}
- ];
-
- keycodebindings = {
- "124" = "exec systemctl suspend";
- };
- };
-
- extraConfig = "
- exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05 map_to_output eDP-1
- exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05_Stylus map_to_output eDP-1
- ";
- };
- }
-
-#+end_src
-** nixos
-**** Onett (Lenovo Y510P)
-:PROPERTIES:
-:CUSTOM_ID: h:6bc7b9c7-ccfd-42d7-982a-97907aa28b80
-:END:
-
-My laptop, sadly soon to be replaced by a new one, since most basic functions are stopping to work lately.
-
-***** NixOS
-:PROPERTIES:
-:CUSTOM_ID: h:20fc100c-045d-468a-9bf2-824037e6785b
-:END:
-
-#+begin_src nix :noweb yes :tangle profiles/onett/nixos.nix
-
- { config, lib, pkgs, inputs, ... }:
-
- {
-
- <>
-
- services = {
- greetd.settings.initial_session.user ="swarsel";
- xserver.videoDrivers = ["nvidia"];
- };
-
-
- hardware = {
- nvidia = {
- modesetting.enable = true;
- powerManagement.enable = true;
- prime = {
- intelBusId = "PCI:0:2:0";
- nvidiaBusId = "PCI:1:0:0";
- sync.enable = true;
- };
- };
- pulseaudio.configFile = pkgs.runCommand "default.pa" {} ''
- sed 's/module-udev-detect$/module-udev-detect tsched=0/' \
- ${pkgs.pulseaudio}/etc/pulse/default.pa > $out
- '';
- bluetooth.enable = true;
- };
-
- stylix.image = ../../wallpaper/lenovowp.png;
- <>
-
- boot.loader.grub = {
- enable = true;
- device = "/dev/sda";
- useOSProber = true;
- };
-
- networking.hostName = "onett"; # Define your hostname.
- networking.enableIPv6 = false;
-
- users.users.swarsel = {
- isNormalUser = true;
- description = "Leon S";
- extraGroups = [ "networkmanager" "wheel" "lp"];
- packages = with pkgs; [];
- };
-
- system.stateVersion = "23.05"; # Did you read the comment?
-
- environment.systemPackages = with pkgs; [
- ];
-
-
- }
-
-#+end_src
-
-***** Home Manager
-:PROPERTIES:
-:CUSTOM_ID: h:d35847ae-2207-4417-9858-b0ea7e2b1a0b
-:END:
-
-#+begin_src nix :noweb yes :tangle profiles/onett/home.nix
-
- { config, pkgs, lib, fetchFromGitHub, ... }:
-
- {
-
- <>
-
- home = {
- username = "swarsel";
- homeDirectory = "/home/swarsel";
- stateVersion = "23.05"; # Please read the comment before changing.
- keyboard.layout = "de";
- packages = with pkgs; [
- ];
- };
-
- sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
-
- # # waybar config
- programs.waybar.settings.mainBar = {
- cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
- temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon3/temp3_input";
- };
- <>
-
- services.blueman-applet.enable = true;
-
- wayland.windowManager.sway= {
- config = rec {
- input = {
- "1:1:AT_Translated_Set_2_keyboard" = {
- xkb_layout = "us";
- xkb_options = "grp:win_space_toggle";
- # xkb_options = "ctrl:nocaps,grp:win_space_toggle";
- xkb_variant = "altgr-intl";
- };
- "2362:33538:ipad_keyboard_Keyboard" = {
- xkb_layout = "us";
- xkb_options = "altwin:swap_lalt_lwin,ctrl:nocaps,grp:win_space_toggle";
- xkb_variant = "colemak_dh";
- };
- "36125:53060:splitkb.com_Kyria_rev3" = {
- xkb_layout = "us";
- xkb_variant = "altgr-intl";
- };
-
- "type:touchpad" = {
- dwt = "enabled";
- tap = "enabled";
- natural_scroll = "enabled";
- middle_emulation = "enabled";
- };
- };
-
- output = {
- eDP-1 = {
- mode = "1920x1080";
- scale = "1";
- bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- position = "1920,0";
- };
- VGA-1 = {
- mode = "1920x1080";
- scale = "1";
- bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- position = "0,0";
- };
- };
-
- keybindings = let
- modifier = config.wayland.windowManager.sway.config.modifier;
- in {
- "${modifier}+F2" = "exec brightnessctl set +5%";
- "${modifier}+F1"= "exec brightnessctl set 5%-";
- "XF86MonBrightnessUp" = "exec brightnessctl set +5%";
- "XF86MonBrightnessDown"= "exec brightnessctl set 5%-";
- "${modifier}+Ctrl+p" = "exec wl-mirror eDP-1";
- "XF86HomePage" = "exec wtype -P Escape -p Escape";
- "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\"";
- };
- keycodebindings = {
- "94" = "exec wtype c";
- "Shift+94" = "exec wtype C";
- "Ctrl+94" = "exec wtype -M ctrl c -m ctrl";
- "Ctrl+Shift+94" = "exec wtype -M ctrl -M shift c -m ctrl -m shift";
- };
-
- startup = [
- <>
- ];
- };
-
- extraConfig = "
- ";
- };
- }
-
-#+end_src
diff --git a/index.html b/index.html
index 20cddee..3eb998d 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
+
SwarselSystems: NixOS + Emacs Configuration
@@ -339,37 +339,46 @@ Table of Contents
4.4.11. devdocs
4.4.12. Projectile
4.4.13. Magit
+4.4.14. Yubikey support
+4.4.15. Forge
+4.4.16. git-timemachine
+4.4.17. Delimiters (brackets): rainbow-delimiters, highlight-parentheses
+4.4.18. rainbow-mode
+4.4.19. Corfu
+4.4.20. cape
+4.4.21. rust
+4.4.22. Tramp
+4.4.23. diff-hl
+4.4.24. Commenting
+4.4.25. yasnippet
+4.4.26. eglot
+4.4.27. Breadcrumb
+4.4.28. Prevent breaking of hardlinks
+4.4.29. Dirvish
+4.4.30. pdf-tools: pdf-viewer and support for dirvish
+4.4.31. Jupyter
+4.4.32. undo-tree
+4.4.33. Hydra
+4.4.34. External Applications
+4.4.35. Email
+4.4.36. Calendar
+4.4.37. Dashboard: emacs startup screen
-5. Yubikey support
+5. Wiki
@@ -378,7 +387,7 @@ Table of Contents
-This file has 40289 words spanning 10434 lines and was last revised on 2024-07-17 02:28:18 +0200.
+This file has 42235 words spanning 11010 lines and was last revised on 2024-07-17 04:32:19 +0200.
@@ -428,7 +437,7 @@
1
-My emacs is built using the emacs-overlay nix flake, which builds a bleeding edge emacs on wayland (pgtk) with utilities like treesitter support. By executing the below source block, the current build setting can be updated at any time, and you can see my most up-to-date build options (last updated: 2024-07-17 02:28:18 +0200)
+My emacs is built using the emacs-overlay nix flake, which builds a bleeding edge emacs on wayland (pgtk) with utilities like treesitter support. By executing the below source block, the current build setting can be updated at any time, and you can see my most up-to-date build options (last updated: 2024-07-17 04:32:19 +0200)
@@ -1601,565 +1610,884 @@ 3
-- Threed (Surface Pro 3)
-
+
- Sandbox (Lenovo Y510P)
+
-New setup for the SP3, this time using NixOS - another machine will take over the HM-only config for compatibility in the future.
+My old laptop, replaced by a new one, since most basic functions have stopped to work lately. However, it is still good as a dummy server for testing things out before having them go live.
-- NixOS
-
+
- NixOS
+
-{ config, lib, pkgs, inputs, ... }:
-
-{
+ { config, pkgs, modulesPath, unstable, sops, ... }: let
+ matrixDomain = "swatrix.swarsel.win";
+ in {
- imports =
- [
+ imports = [
./hardware-configuration.nix
+ # we import here a service that is not available yet on normal nixpkgs
+ # this module is hence not in the modules list, we add it ourselves
+ (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix")
];
-
- services = {
- getty.autologinUser = "swarsel";
- greetd.settings.initial_session.user="swarsel";
- };
-
- hardware.bluetooth.enable = true;
-
- # Bootloader
- boot = {
- loader.systemd-boot.enable = lib.mkForce false;
- lanzaboote = {
- enable = true;
- pkiBundle = "/etc/secureboot";
- };
- loader.efi.canTouchEfiVariables = true;
- # use bootspec instead of lzbt for secure boot. This is not a generally needed setting
- bootspec.enable = true;
- # kernelPackages = pkgs.linuxPackages_latest;
- };
-
- networking = {
- hostName = "threed";
- enableIPv6 = false;
- firewall.enable = false;
- };
-
- stylix.image = ../../wallpaper/surfacewp.png;
-
- stylix = {
- enable = true;
- base16Scheme = ../../wallpaper/swarsel.yaml;
- # base16Scheme = "${pkgs.base16-schemes}/share/themes/shapeshifter.yaml";
- polarity = "dark";
- opacity.popups = 0.5;
- cursor = {
- package = pkgs.capitaine-cursors;
- name = "capitaine-cursors";
- size = 16;
- };
- fonts = {
- sizes = {
- terminal = 10;
- applications = 11;
- };
- serif = {
- # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; });
- package = pkgs.cantarell-fonts;
- # package = pkgs.montserrat;
- name = "Cantarell";
- # name = "FiraCode Nerd Font Propo";
- # name = "Montserrat";
+ boot.loader.grub = {
+ enable = true;
+ device = "/dev/sda";
+ useOSProber = true;
};
- sansSerif = {
- # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; });
- package = pkgs.cantarell-fonts;
- # package = pkgs.montserrat;
- name = "Cantarell";
- # name = "FiraCode Nerd Font Propo";
- # name = "Montserrat";
+ users.users.swarsel = {
+ isNormalUser = true;
+ description = "Leon S";
+ extraGroups = [ "networkmanager" "wheel" "lp"];
+ packages = with pkgs; [];
};
- monospace = {
- package = (pkgs.nerdfonts.override { fonts = [ "FiraCode"]; });
- name = "FiraCode Nerd Font Mono";
- };
+ # actual config starts here
- emoji = {
- package = pkgs.noto-fonts-emoji;
- name = "Noto Color Emoji";
- };
+ fileSystems."/mnt/Eternor" = {
+ device = "//192.168.1.3/Eternor";
+ fsType = "cifs";
+ options = let
+ # this line prevents hanging on network split
+ automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s";
+ in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=1000,gid=100"];
};
- };
-
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ lego
+ nginx
+ calibre
+ openvpn
+ jq
+ iptables
+ busybox
+ wireguard-tools
+ matrix-synapse
+ lottieconverter
+ ffmpeg
+ pciutils
+ alsa-utils
+ mpv
+ zfs
+ ];
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
- users.users.swarsel = {
- isNormalUser = true;
- description = "Leon S";
- extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" ];
- packages = with pkgs; [];
- };
+ nix.settings.experimental-features = ["nix-command" "flakes"];
- environment.systemPackages = with pkgs; [
- ];
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ listenAddresses = [{
+ port = 22;
+ addr = "0.0.0.0";
+ }];
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../secrets/keys/authorized_keys
+ ];
- system.stateVersion = "23.05";
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
-}
+ environment.shellAliases = {
+ nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
-
-
-
-
-
- Home Manager
-
-
-
-{ config, pkgs, lib, fetchFromGitHub, ... }:
+boot.supportedFilesystems = [ "zfs" ];
+boot.zfs.forceImportRoot = false;
+networking.hostId = "8a8ad84a";
-{
+ networking.hostName = "sandbox"; # Define your hostname.
+ networking.enableIPv6 = true;
+ networking.firewall.enable = false;
+ documentation = {
+ enable = false;
+ };
- services.gpg-agent = {
- enable = true;
- enableSshSupport = true;
- enableExtraSocket = true;
- pinentryPackage = pkgs.pinentry.gtk2;
- defaultCacheTtl = 600;
- maxCacheTtl = 7200;
- extraConfig = ''
- allow-loopback-pinentry
- allow-emacs-pinentry
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/root/.dotfiles/secrets/sandbox/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.dnstokenfull = {owner="acme";};
+ sops.templates."certs.secret".content = ''
+ CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
'';
+
+ security.acme = {
+ acceptTerms = true;
+ preliminarySelfsigned = false;
+ defaults.email = "mrswarsel@gmail.com";
+ defaults.dnsProvider = "cloudflare";
+ defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
};
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ virtualHosts = {
- home = {
- username = "swarsel";
- homeDirectory = "/home/swarsel";
- stateVersion = "23.05"; # Please read the comment before changing.
- keyboard.layout = "us";
- packages = with pkgs; [
- ];
- };
+ "stash.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "https://192.168.1.5";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ # "/push/" = {
+ # proxyPass = "http://192.168.2.5:7867";
+ # };
+ "/.well-known/carddav" = {
+ return = "301 $scheme://$host/remote.php/dav";
+ };
+ "/.well-known/caldav" = {
+ return = "301 $scheme://$host/remote.php/dav";
+ };
+ };
+ };
- sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
+ "swatrix.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "~ ^(/_matrix|/_synapse/client)" = {
+ proxyPass = "http://127.0.0.1:8008";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- programs.waybar.settings.mainBar = {
- cpu.format = "{icon0} {icon1} {icon2} {icon3}";
- temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp3_input";
- };
- programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark"
- "mpris"
- "custom/left-arrow-light"
- "network"
- "custom/left-arrow-dark"
- "pulseaudio"
- "custom/left-arrow-light"
- "custom/pseudobat"
- "battery"
- "custom/left-arrow-dark"
- "group/hardware"
- "custom/left-arrow-light"
- "clock#2"
- "custom/left-arrow-dark"
- "clock#1"
- ];
-
-
- wayland.windowManager.sway= {
- config = rec {
- input = {
- "*" = {
- xkb_layout = "us";
- xkb_options = "grp:win_space_toggle";
- xkb_variant = "altgr-intl";
- };
- "type:touchpad" = {
- dwt = "enabled";
- tap = "enabled";
- natural_scroll = "enabled";
- middle_emulation = "enabled";
- };
- };
-
- output = {
- eDP-1 = {
- mode = "2160x1440@59.955Hz";
- scale = "1";
- bg = "~/.dotfiles/wallpaper/surfacewp.png fill";
- };
- };
+ "sound.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:4040";
+ proxyWebsockets = true;
+ extraConfig = ''
+ proxy_redirect http:// https://;
+ proxy_read_timeout 600s;
+ proxy_send_timeout 600s;
+ proxy_buffering off;
+ proxy_request_buffering off;
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- keybindings = let
- modifier = config.wayland.windowManager.sway.config.modifier;
- in {
- "${modifier}+F2" = "exec brightnessctl set +5%";
- "${modifier}+F1"= "exec brightnessctl set 5%-";
- "${modifier}+n" = "exec sway output eDP-1 transform normal, splith";
- "${modifier}+Ctrl+p" = "exec wl-mirror eDP-1";
- "${modifier}+t" = "exec sway output eDP-1 transform 90, splitv";
- "${modifier}+XF86AudioLowerVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
- "${modifier}+XF86AudioRaiseVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
- "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\"";
- };
+ "scan.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:28981";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- startup = [
+ "screen.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:8096";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- { command = "nextcloud --background";}
- { command = "discord --start-minimized";}
- { command = "element-desktop --hidden -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds";}
- { command = "ANKI_WAYLAND=1 anki";}
- { command = "OBSIDIAN_USE_WAYLAND=1 obsidian";}
- { command = "nm-applet";}
+ "scroll.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://127.0.0.1:8080";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
- ];
- keycodebindings = {
- "124" = "exec systemctl suspend";
+ };
};
- };
-
- extraConfig = "
- exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05 map_to_output eDP-1
- exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05_Stylus map_to_output eDP-1
- ";
- };
-}
-
-
-
-
-
-
-
- Fourside (Lenovo Thinkpad P14s Gen2)
-
-
-My new main machine.
-
-
-
-- NixOS
-
-
-Mostly just sets some opened ports for several games, enables virtualbox (which I do not want everywhere because of resource considerations) and enables thinkfan, which allows for better fan control on Lenovo Thinkpad machines.
-
-
-
-{ config, lib, pkgs, inputs, ... }:
-{
+ sops.secrets.kavita = { owner = "kavita";};
- #
- # imports =
- # [
- # ./hardware-configuration.nix
- # ];
- #
- imports =
- [
- ./hardware-configuration.nix
- ];
+ services.kavita = {
+ enable = true;
+ user = "kavita";
+ port = 8080;
+ tokenKeyFile = config.sops.secrets.kavita.path;
+ };
- services = {
- getty.autologinUser = "swarsel";
- greetd.settings.initial_session.user="swarsel";
- };
+ users.users.jellyfin = {
+ extraGroups = [ "video" "render" ];
+ };
- boot = {
- loader.systemd-boot.enable = true;
- loader.efi.canTouchEfiVariables = true;
- # kernelPackages = pkgs.linuxPackages_latest;
- };
+ # nixpkgs.config.packageOverrides = pkgs: {
+ # vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
+ # };
- sops.age.sshKeyPaths = [ "${config.users.users.swarsel.home}/.ssh/sops" ];
+ hardware.graphics = {
+ enable = true;
+ extraPackages = with pkgs; [
+ intel-media-driver # LIBVA_DRIVER_NAME=iHD
+ vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
+ vaapiVdpau
+ libvdpau-va-gl
+ ];
+ };
- networking = {
- hostName = "fourside"; # Define your hostname.
- nftables.enable = true;
- enableIPv6 = false;
- firewall.checkReversePath = false;
- firewall = {
+ services.jellyfin = {
enable = true;
- allowedUDPPorts = [ 4380 27036 14242 34197 51820 ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard
- allowedTCPPorts = [ ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard
- allowedTCPPortRanges = [
- {from = 27015; to = 27030;} # barotrauma
- {from = 27036; to = 27037;} # barotrauma
- ];
- allowedUDPPortRanges = [
- {from = 27000; to = 27031;} # barotrauma
- {from = 58962; to = 58964;} # barotrauma
- ];
+ user = "jellyfin";
+ # openFirewall = true; # this works only for the default ports
};
- };
- virtualisation.virtualbox = {
- host = {
- enable = true;
- enableExtensionPack = true;
- };
- # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch
- guest = {
- enable = false;
- };
- };
+ users.groups.vpn = {};
- stylix.image = ../../wallpaper/lenovowp.png;
+ users.users.vpn = {
+ isNormalUser = true;
+ group = "vpn";
+ home = "/home/vpn";
+ };
- stylix = {
- enable = true;
- base16Scheme = ../../wallpaper/swarsel.yaml;
- # base16Scheme = "${pkgs.base16-schemes}/share/themes/shapeshifter.yaml";
- polarity = "dark";
- opacity.popups = 0.5;
- cursor = {
- package = pkgs.capitaine-cursors;
- name = "capitaine-cursors";
- size = 16;
- };
- fonts = {
- sizes = {
- terminal = 10;
- applications = 11;
- };
- serif = {
- # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; });
- package = pkgs.cantarell-fonts;
- # package = pkgs.montserrat;
- name = "Cantarell";
- # name = "FiraCode Nerd Font Propo";
- # name = "Montserrat";
- };
+ boot.kernelModules = [ "tun" ];
- sansSerif = {
- # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; });
- package = pkgs.cantarell-fonts;
- # package = pkgs.montserrat;
- name = "Cantarell";
- # name = "FiraCode Nerd Font Propo";
- # name = "Montserrat";
- };
+ services.radarr = {
+ enable = true;
+ };
- monospace = {
- package = (pkgs.nerdfonts.override { fonts = [ "FiraCode"]; });
- name = "FiraCode Nerd Font Mono";
- };
+ services.readarr = {
+ enable = true;
+ };
+ services.sonarr = {
+ enable = true;
+ };
+ services.lidarr = {
+ enable = true;
+ };
+ services.prowlarr = {
+ enable = true;
+ };
- emoji = {
- package = pkgs.noto-fonts-emoji;
- name = "Noto Color Emoji";
- };
- };
- };
+ networking.firewall.extraCommands = ''
+ sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP
+ '';
+ networking.iproute2 = {
+ enable = true;
+ rttablesExtraConfig = ''
+ 200 vpn
+ '';
+ };
+ boot.kernel.sysctl = {
+ "net.ipv4.conf.all.rp_filter" = 2;
+ "net.ipv4.conf.default.rp_filter" = 2;
+ "net.ipv4.conf.enp7s0.rp_filter" = 2;
+ };
+ environment.etc = {
+ "openvpn/iptables.sh" =
+ { source = ../../scripts/server1/iptables.sh;
+ mode = "0755";
+ };
+ "openvpn/update-resolv-conf" =
+ { source = ../../scripts/server1/update-resolv-conf;
+ mode = "0755";
+ };
+ "openvpn/routing.sh" =
+ { source = ../../scripts/server1/routing.sh;
+ mode = "0755";
+ };
+ "openvpn/ca.rsa.2048.crt" =
+ { source = ../../secrets/certs/ca.rsa.2048.crt;
+ mode = "0644";
+ };
+ "openvpn/crl.rsa.2048.pem" =
+ { source = ../../secrets/certs/crl.rsa.2048.pem;
+ mode = "0644";
+ };
+ };
+ sops.secrets.vpnuser = {};
+ sops.secrets.rpcuser = {owner="vpn";};
+ sops.secrets.vpnpass = {};
+ sops.secrets.rpcpass = {owner="vpn";};
+ sops.secrets.vpnprot = {};
+ sops.secrets.vpnloc = {};
+ # sops.secrets.crlpem = {};
+ # sops.secrets.capem = {};
+ sops.templates."transmission-rpc".owner = "vpn";
+ sops.templates."transmission-rpc".content = builtins.toJSON {
+ rpc-username = config.sops.placeholder.rpcuser;
+ rpc-password = config.sops.placeholder.rpcpass;
+ };
+ sops.templates.pia.content = ''
+ ${config.sops.placeholder.vpnuser}
+ ${config.sops.placeholder.vpnpass}
+ '';
+ sops.templates.vpn.content = ''
+ client
+ dev tun
+ proto ${config.sops.placeholder.vpnprot}
+ remote ${config.sops.placeholder.vpnloc}
+ resolv-retry infinite
+ nobind
+ persist-key
+ persist-tun
+ cipher aes-128-cbc
+ auth sha1
+ tls-client
+ remote-cert-tls server
- hardware = {
- graphics = {
- enable = true;
- enable32Bit = true;
- extraPackages = with pkgs; [
- vulkan-loader
- vulkan-validation-layers
- vulkan-extension-layer
- ];
- };
- bluetooth.enable = true;
- trackpoint = {
- enable = true;
- device = "TPPS/2 Elan TrackPoint";
- };
- };
+ auth-user-pass ${config.sops.templates.pia.path}
+ compress
+ verb 1
+ reneg-sec 0
- programs.steam = {
- enable = true;
- extraCompatPackages = [
- pkgs.proton-ge-bin
- ];
- };
+ crl-verify /etc/openvpn/crl.rsa.2048.pem
+ ca /etc/openvpn/ca.rsa.2048.crt
- # Configure keymap in X11 (only used for login)
+ disable-occ
+ '';
- services.thinkfan = {
- enable = false;
- };
- services.power-profiles-daemon.enable = true;
- services.fprintd.enable = true;
+ services.openvpn.servers = {
+ pia = {
+ autoStart = true;
+ updateResolvConf = false;
+ config = "config ${config.sops.templates.vpn.path}";
+ };
+ };
- users.users.swarsel = {
- isNormalUser = true;
- description = "Leon S";
- hashedPasswordFile = config.sops.secrets.swarseluser.path;
- extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ];
- packages = with pkgs; [];
- };
+ services.transmission = {
+ enable = true;
+ credentialsFile = config.sops.templates."transmission-rpc".path;
+ user = "vpn";
+ settings = {
- environment.systemPackages = with pkgs; [
- # gog games installing
- heroic
- # minecraft
- temurin-bin-17
- (prismlauncher.override {
- glfw = pkgs.glfw-wayland-minecraft;
- })
- ];
+ alt-speed-down= 8000;
+ alt-speed-enabled= false;
+ alt-speed-time-begin= 0;
+ alt-speed-time-day= 127;
+ alt-speed-time-enabled= true;
+ alt-speed-time-end= 360;
+ alt-speed-up= 2000;
+ bind-address-ipv4= "0.0.0.0";
+ bind-address-ipv6= "::";
+ blocklist-enabled= false;
+ blocklist-url= "http://www.example.com/blocklist";
+ cache-size-mb= 256;
+ dht-enabled= false;
+ download-dir= "/test";
+ download-limit= 100;
+ download-limit-enabled= 0;
+ download-queue-enabled= true;
+ download-queue-size= 5;
+ encryption= 2;
+ idle-seeding-limit= 30;
+ idle-seeding-limit-enabled= false;
+ incomplete-dir= "/var/lib/transmission-daemon/Downloads";
+ incomplete-dir-enabled= false;
+ lpd-enabled= false;
+ max-peers-global= 200;
+ message-level= 1;
+ peer-congestion-algorithm= "";
+ peer-id-ttl-hours= 6;
+ peer-limit-global= 100;
+ peer-limit-per-torrent= 40;
+ peer-port= 22371;
+ peer-port-random-high= 65535;
+ peer-port-random-low= 49152;
+ peer-port-random-on-start= false;
+ peer-socket-tos= "default";
+ pex-enabled= false;
+ port-forwarding-enabled= false;
+ preallocation= 1;
+ prefetch-enabled= true;
+ queue-stalled-enabled= true;
+ queue-stalled-minutes= 30;
+ ratio-limit= 2;
+ ratio-limit-enabled= false;
+ rename-partial-files= true;
+ rpc-authentication-required= true;
+ rpc-bind-address= "0.0.0.0";
+ rpc-enabled= true;
+ rpc-host-whitelist= "";
+ rpc-host-whitelist-enabled= true;
+ rpc-port= 9091;
+ rpc-url= "/transmission/";
+ rpc-whitelist= "127.0.0.1,192.168.3.2";
+ rpc-whitelist-enabled= true;
+ scrape-paused-torrents-enabled= true;
+ script-torrent-done-enabled= false;
+ seed-queue-enabled= false;
+ seed-queue-size= 10;
+ speed-limit-down= 6000;
+ speed-limit-down-enabled= true;
+ speed-limit-up= 500;
+ speed-limit-up-enabled= true;
+ start-added-torrents= true;
+ trash-original-torrent-files= false;
+ umask= 2;
+ upload-limit= 100;
+ upload-limit-enabled= 0;
+ upload-slots-per-torrent= 14;
+ utp-enabled= false;
+ };
+ };
- system.stateVersion = "23.05";
+ # services.nginx = {
+ # enable = true;
+ # virtualHosts = {
+ # "192.168.1.192" = {
+ # locations = {
+ # "/transmission" = {
+ # proxyPass = "http://127.0.0.1:9091";
+ # extraConfig = ''
+ # proxy_set_header Host $host;
+ # proxy_set_header X-Real-IP $remote_addr;
+ # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ # '';
+ # };
+ # };
+ # };
+ # };
+ # };
-}
-
-
-
-
-
-- Home Manager
-
-
-This is basically just adjusted to the core count, path to the hwmon
(this was very bothersome on this machine due to changing address), as well as making use of the top-row function keys.
-
-
-
-
-{ config, pkgs, lib, fetchFromGitHub, ... }:
-
-{
+ # sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
+ # sops.templates."matrix_user_register.sh".content = ''
+ # register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
+ # '';
+ # sops.templates.matrixshared.owner = "matrix-synapse";
+ # sops.templates.matrixshared.content = ''
+ # registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
+ # '';
+ # sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
+ # sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
+ # sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
+ # sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
+ # sops.templates.mautrixtelegram.owner = "matrix-synapse";
+ # sops.templates.mautrixtelegram.content = ''
+ # MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
+ # MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
+ # MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
+ # MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
+ # '';
- services.gpg-agent = {
- enable = true;
- enableSshSupport = true;
- enableExtraSocket = true;
- pinentryPackage = pkgs.pinentry.gtk2;
- defaultCacheTtl = 600;
- maxCacheTtl = 7200;
- extraConfig = ''
- allow-loopback-pinentry
- allow-emacs-pinentry
- '';
- };
- home = {
- username = "swarsel";
- homeDirectory = "/home/swarsel";
- stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing.
- keyboard.layout = "us"; # TEMPLATE
- packages = with pkgs; [
- ];
- };
- sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
- # waybar config - TEMPLATE - update for cores and temp
- programs.waybar.settings.mainBar = {
- cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
- # temperature.hwmon-path = "/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon4/temp1_input";
- temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/";
- temperature.input-filename = "temp1_input";
- };
+ # ----------------
+ # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
+ # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
+ # sops.templates.mautrixwhatsapp.content = ''
+ # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
+ # '';
- programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark"
- "mpris"
- "custom/left-arrow-light"
- "network"
- "custom/left-arrow-dark"
- "pulseaudio"
- "custom/left-arrow-light"
- "custom/pseudobat"
- "battery"
- "custom/left-arrow-dark"
- "group/hardware"
- "custom/left-arrow-light"
- "clock#2"
- "custom/left-arrow-dark"
- "clock#1"
- ];
+ services.postgresql.enable = true;
+ services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
+ CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
+ CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
+ CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
+ CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
+ CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ '';
+ services.matrix-synapse = {
+ settings.app_service_config_files = [
+ "/var/lib/matrix-synapse/telegram-registration.yaml"
+ "/var/lib/matrix-synapse/whatsapp-registration.yaml"
+ "/var/lib/matrix-synapse/signal-registration.yaml"
+ "/var/lib/matrix-synapse/doublepuppet.yaml"
+ ];
+ enable = false;
+ settings.server_name = matrixDomain;
+ settings.public_baseurl = "https://${matrixDomain}";
+ extraConfigFiles = [
+ config.sops.templates.matrixshared.path
+ ];
+ settings.listeners = [
+ { port = 8008;
+ bind_addresses = [ "0.0.0.0" ];
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [
+ {
+ names = [ "client" "federation" ];
+ compress = true;
+ }
+ ];
+ }
+ ];
+ };
- wayland.windowManager.sway= {
- config = rec {
- # update for actual inputs here,
- input = {
- "36125:53060:splitkb.com_Kyria_rev3" = {
- xkb_layout = "us";
- xkb_variant = "altgr-intl";
+ services.mautrix-telegram = {
+ enable = false;
+ environmentFile = config.sops.templates.mautrixtelegram.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
};
- "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE
- xkb_layout = "us";
- xkb_options = "grp:win_space_toggle";
- xkb_variant = "altgr-intl";
+ appservice = {
+ address= "http://localhost:29317";
+ hostname = "0.0.0.0";
+ port = "29317";
+ provisioning.enabled = true;
+ id = "telegram";
+ # ephemeral_events = true; # not needed due to double puppeting
+ public = {
+ enabled = false;
+ };
+ database = "postgresql:///mautrix-telegram?host=/run/postgresql";
};
- "type:touchpad" = {
- dwt = "enabled";
- tap = "enabled";
- natural_scroll = "enabled";
- middle_emulation = "enabled";
+ bridge = {
+ # login_shared_secret_map = {
+ # matrixDomain = "as_token:doublepuppet";
+ # };
+ relaybot.authless_portals = true;
+ allow_avatar_remove = true;
+ allow_contact_info = true;
+ sync_channel_members = true;
+ startup_sync = true;
+ sync_create_limit = 0;
+ sync_direct_chats = true;
+ telegram_link_preview = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
+ # Animated stickers conversion requires additional packages in the
+ # service's path.
+ # If this isn't a fresh installation, clearing the bridge's uploaded
+ # file cache might be necessary (make a database backup first!):
+ # delete from telegram_file where \
+ # mime_type in ('application/gzip', 'application/octet-stream')
+ animated_sticker = {
+ target = "gif";
+ args = {
+ width = 256;
+ height = 256;
+ fps = 30; # only for webm
+ background = "020202"; # only for gif, transparency not supported
+ };
+ };
};
-
};
+ };
+ # systemd.services.mautrix-telegram.path = with pkgs; [
+ # lottieconverter # for animated stickers conversion, unfree package
+ # ffmpeg # if converting animated stickers to webm (very slow!)
+ # ];
- output = {
- eDP-1 = {
- mode = "1920x1080"; # TEMPLATE
- scale = "1";
- position = "1920,0";
- # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ services.mautrix-whatsapp = {
+ enable = false;
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
};
- HDMI-A-1 = {
- mode = "2560x1440";
- scale = "1";
- # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- position = "0,0";
+ appservice = {
+ address= "http://localhost:29318";
+ hostname = "0.0.0.0";
+ port = 29318;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
+ };
+ };
+ bridge = {
+ displayname_template = "{{or .FullName .PushName .JID}} (WA)";
+ history_sync = {
+ backfill = true;
+ max_initial_conversations = -1;
+ message_count = -1;
+ request_full_sync = true;
+ full_sync_config = {
+ days_limit = 900;
+ size_mb_limit = 5000;
+ storage_quota_mb = 5000;
+ };
+ };
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ sync_manual_marked_unread = true;
+ send_presence_on_typing = true;
+ parallel_member_sync = true;
+ url_previews = true;
+ caption_in_message = true;
+ extev_polls = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
};
};
+ };
- workspaceOutputAssign = [
- { output = "eDP-1"; workspace = "1:一";}
- { output = "HDMI-A-1"; workspace = "2:二";}
- ];
+ services.mautrix-signal = {
+ enable = false;
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
+
+ address= "http://localhost:29328";
+ hostname = "0.0.0.0";
+ port = 29328;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-signal?host=/run/postgresql";
+ };
+ };
+ bridge = {
+ displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ caption_in_message = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
+ };
+ };
+ };
+ # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
+ # messages out after a while.
- keybindings = let
- modifier = config.wayland.windowManager.sway.config.modifier;
- in {
- "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkelement.sh\"";
- "XF86MonBrightnessUp" = "exec brightnessctl set +5%";
- "XF86MonBrightnessDown"= "exec brightnessctl set 5%-";
- "XF86Display" = "exec wl-mirror eDP-1";
- # these are left open to use
- # "XF86WLAN" = "exec wl-mirror eDP-1";
- # "XF86Messenger" = "exec wl-mirror eDP-1";
- # "XF86Go" = "exec wl-mirror eDP-1";
- # "XF86Favorites" = "exec wl-mirror eDP-1";
- # "XF86HomePage" = "exec wtype -P Escape -p Escape";
- # "XF86AudioLowerVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink -5%";
- # "XF86AudioRaiseVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink +5% ";
- "XF86AudioMute" = "pactl set-sink-mute alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink toggle";
+ systemd.timers."restart-bridges" = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnBootSec = "1d";
+ OnUnitActiveSec = "1d";
+ Unit = "restart-bridges.service";
};
+ };
- startup = [
+ systemd.services."restart-bridges" = {
+ script = ''
+ systemctl restart mautrix-whatsapp.service
+ systemctl restart mautrix-signal.service
+ systemctl restart mautrix-telegram.service
+ '';
+ serviceConfig = {
+ Type = "oneshot";
+ User = "root";
+ };
+ };
- { command = "nextcloud --background";}
- { command = "discord --start-minimized";}
- { command = "element-desktop --hidden -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds";}
- { command = "ANKI_WAYLAND=1 anki";}
- { command = "OBSIDIAN_USE_WAYLAND=1 obsidian";}
- { command = "nm-applet";}
+ users.groups.navidrome = {
+ gid = 61593;
+ };
+
+ users.groups.mpd = {};
+
+ users.users.navidrome = {
+ isSystemUser = true;
+ uid = 61593;
+ group = "navidrome";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ users.users.mpd = {
+ isSystemUser = true;
+ group = "mpd";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ sound = {
+ enable = true;
+ };
+
+ hardware.enableAllFirmware = true;
+
+ sops.secrets.mpdpass = { owner = "mpd";};
+
+ services.navidrome = {
+ enable = true;
+ settings = {
+ Address = "0.0.0.0";
+ Port = 4040;
+ MusicFolder = "/mnt/";
+ EnableSharing = true;
+ EnableTranscodingConfig = true;
+ Scanner.GroupAlbumReleases = true;
+ ScanSchedule = "@every 24h";
+ # Insert these values locally as sops-nix does not work for them
+ # LastFM.ApiKey = TEMPLATE;
+ # LastFM.Secret = TEMPLATE;
+ # Spotify.ID = TEMPLATE;
+ # Spotify.Secret = TEMPLATE;
+ UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png";
+ UIWelcomeMessage = "~SwarselSound~";
+ };
+ };
+ services.mpd = {
+ enable = true;
+ musicDirectory = "/mnt/Eternor/Musik";
+ user = "mpd";
+ group = "mpd";
+ network = {
+ port = 3254;
+ listenAddress = "any";
+ };
+ credentials = [
+ {
+ passwordFile = config.sops.secrets.mpdpass.path;
+ permissions = [
+ "read"
+ "add"
+ "control"
+ "admin"
+ ];
+ }
];
};
- };
-}
+
+
+ users.groups.spotifyd = {
+ gid = 65136;
+ };
+
+ users.users.spotifyd = {
+ isSystemUser = true;
+ uid = 65136;
+ group = "spotifyd";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ services.spotifyd = {
+ enable = true;
+ settings = {
+ global = {
+ dbus_type = "session";
+ use_mpris = false;
+ device = "default:CARD=PCH";
+ device_name = "SwarselSpot";
+ mixer = "alsa";
+ zeroconf_port = 1025;
+ };
+ };
+ };
+
+ # Network shares
+ # add a user with sudo smbpasswd -a <user>
+ services.samba = {
+ package = pkgs.samba4Full;
+ extraConfig = ''
+ workgroup = WORKGROUP
+ server role = standalone server
+ dns proxy = no
+
+ pam password change = yes
+ map to guest = bad user
+ create mask = 0664
+ force create mode = 0664
+ directory mask = 0775
+ force directory mode = 0775
+ follow symlinks = yes
+ '';
+
+ # ^^ `samba4Full` is compiled with avahi, ldap, AD etc support compared to the default package, `samba`
+ # Required for samba to register mDNS records for auto discovery
+ # See https://github.com/NixOS/nixpkgs/blob/592047fc9e4f7b74a4dc85d1b9f5243dfe4899e3/pkgs/top-level/all-packages.nix#L27268
+ enable = true;
+ # openFirewall = true;
+ shares.test = {
+ browseable = "yes";
+ "read only" = "no";
+ "guest ok" = "no";
+ path = "/test2";
+ writable = "true";
+ comment = "Eternor";
+ "valid users" = "@smbtest2";
+ };
+ };
+
+
+ services.avahi = {
+ publish.enable = true;
+ publish.userServices = true;
+ # ^^ Needed to allow samba to automatically register mDNS records without the need for an `extraServiceFile`
+ nssmdns = true;
+ # ^^ Not one hundred percent sure if this is needed- if it aint broke, don't fix it
+ enable = true;
+ };
+
+ services.samba-wsdd = {
+ # This enables autodiscovery on windows since SMB1 (and thus netbios) support was discontinued
+ enable = true;
+ };
+
+
+
+
+
+
+
+
+
+
+ }
@@ -2167,75 +2495,54 @@
3
-- Winters (Framwork Laptop 16)
-
+
- Threed (Surface Pro 3)
+
-My work machine.
+New setup for the SP3, this time using NixOS - another machine will take over the HM-only config for compatibility in the future.
-- NixOS
-
-
-Mostly just sets some opened ports for several games, enables virtualbox (which I do not want everywhere because of resource considerations) and enables thinkfan, which allows for better fan control on Lenovo Thinkpad machines.
-
-
+
- NixOS
+
{ config, lib, pkgs, inputs, ... }:
{
- #
- # imports =
- # [
- # ./hardware-configuration.nix
- # ];
- #
imports =
[
./hardware-configuration.nix
];
+
services = {
getty.autologinUser = "swarsel";
greetd.settings.initial_session.user="swarsel";
};
+ hardware.bluetooth.enable = true;
+
+ # Bootloader
boot = {
- loader.systemd-boot.enable = true;
- loader.efi.canTouchEfiVariables = true;
- kernelPackages = pkgs.linuxPackages_latest;
- };
-
- networking = {
- hostName = "winters"; # Define your hostname.
- nftables.enable = true;
- enableIPv6 = true;
- firewall.checkReversePath = "strict";
- firewall = {
+ loader.systemd-boot.enable = lib.mkForce false;
+ lanzaboote = {
enable = true;
- allowedUDPPorts = [ ];
- allowedTCPPorts = [ ];
- allowedTCPPortRanges = [
- ];
- allowedUDPPortRanges = [
- ];
+ pkiBundle = "/etc/secureboot";
};
+ loader.efi.canTouchEfiVariables = true;
+ # use bootspec instead of lzbt for secure boot. This is not a generally needed setting
+ bootspec.enable = true;
+ # kernelPackages = pkgs.linuxPackages_latest;
};
- virtualisation.virtualbox = {
- host = {
- enable = true;
- enableExtensionPack = true;
- };
- # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch
- guest = {
- enable = false;
- };
- };
+ networking = {
+ hostName = "threed";
+ enableIPv6 = false;
+ firewall.enable = false;
+ };
- stylix.image = ../../wallpaper/lenovowp.png;
+ stylix.image = ../../wallpaper/surfacewp.png;
stylix = {
enable = true;
@@ -2286,58 +2593,26 @@ 3
- hardware = {
- graphics = {
- enable = true;
- enable32Bit = true;
- extraPackages = with pkgs; [
- ];
- };
- bluetooth.enable = true;
- };
-
- programs.steam = {
- enable = true;
- extraCompatPackages = [
- pkgs.proton-ge-bin
- ];
- };
-
- services.power-profiles-daemon.enable = true;
-
users.users.swarsel = {
isNormalUser = true;
description = "Leon S";
- extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ];
+ extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" ];
packages = with pkgs; [];
};
environment.systemPackages = with pkgs; [
- sbctl
- # gog games installing
- heroic
- # minecraft
- temurin-bin-17
- (prismlauncher.override {
- glfw = pkgs.glfw-wayland-minecraft;
- })
];
system.stateVersion = "23.05";
-
}
-
- TODO Home Manager
-
-
-TODO: Adjust hwmon
path, I/O modules and XF86 keys once laptop arrives.
-
-
+
- Home Manager
+
{ config, pkgs, lib, fetchFromGitHub, ... }:
@@ -2358,25 +2633,23 @@ 3
'';
};
+
home = {
username = "swarsel";
homeDirectory = "/home/swarsel";
- stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing.
- keyboard.layout = "us"; # TEMPLATE
+ stateVersion = "23.05"; # Please read the comment before changing.
+ keyboard.layout = "us";
packages = with pkgs; [
];
};
+
sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
- # waybar config - TEMPLATE - update for cores and temp
programs.waybar.settings.mainBar = {
- cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
-
- temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/";
- temperature.input-filename = "temp1_input";
+ cpu.format = "{icon0} {icon1} {icon2} {icon3}";
+ temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp3_input";
};
-
programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark"
"mpris"
"custom/left-arrow-light"
@@ -2397,13 +2670,8 @@ 3
wayland.windowManager.sway= {
config = rec {
- # update for actual inputs here,
input = {
- "36125:53060:splitkb.com_Kyria_rev3" = {
- xkb_layout = "us";
- xkb_variant = "altgr-intl";
- };
- "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE
+ "*" = {
xkb_layout = "us";
xkb_options = "grp:win_space_toggle";
xkb_variant = "altgr-intl";
@@ -2414,35 +2682,27 @@ 3
natural_scroll = "enabled";
middle_emulation = "enabled";
};
-
};
output = {
eDP-1 = {
- mode = "1920x1080"; # TEMPLATE
- scale = "1";
- position = "1920,0";
- # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- };
- # external monitor
- HDMI-A-1 = {
- mode = "2560x1440";
+ mode = "2160x1440@59.955Hz";
scale = "1";
- # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
- position = "0,0";
+ bg = "~/.dotfiles/wallpaper/surfacewp.png fill";
};
};
- workspaceOutputAssign = [
- { output = "eDP-1"; workspace = "1:一";}
- { output = "HDMI-A-1"; workspace = "2:二";}
- ];
-
-
keybindings = let
modifier = config.wayland.windowManager.sway.config.modifier;
in {
-
+ "${modifier}+F2" = "exec brightnessctl set +5%";
+ "${modifier}+F1"= "exec brightnessctl set 5%-";
+ "${modifier}+n" = "exec sway output eDP-1 transform normal, splith";
+ "${modifier}+Ctrl+p" = "exec wl-mirror eDP-1";
+ "${modifier}+t" = "exec sway output eDP-1 transform 90, splitv";
+ "${modifier}+XF86AudioLowerVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
+ "${modifier}+XF86AudioRaiseVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png";
+ "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\"";
};
startup = [
@@ -2455,434 +2715,344 @@ 3
{ command = "nm-applet";}
];
+
+ keycodebindings = {
+ "124" = "exec systemctl suspend";
+ };
};
+
+ extraConfig = "
+ exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05 map_to_output eDP-1
+ exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05_Stylus map_to_output eDP-1
+ ";
};
}
-
-
-
-
-
3.1.3. Virtual hosts
-
-
-My server setup is built on Proxmox VE; back when I started, I created all kinds of wild Debian/Ubuntu/etc. KVMs and LXCs on there. However, the root disk has suffered a weird failure where it has become unable to be cloned, but it is still functional for now. I am currently rewriting all machines on there to use NixOS instead; this is a ongoing process.
-
-
+
- Fourside (Lenovo Thinkpad P14s Gen2)
+
-In the long run, I am thinking about a transition to kubernetes or using just a server running NixOS and using the built-in container functionality. For now however, I like the network management provided by Proxmox, as I am a bit intimidated by doing that from scratch.
+My new main machine.
-- TEMPLATE
-
-
-
-- NixOS
-
+
- NixOS
+
+
+Mostly just sets some opened ports for several games, enables virtualbox (which I do not want everywhere because of resource considerations) and enables thinkfan, which allows for better fan control on Lenovo Thinkpad machines.
+
+
-{ pkgs, modulesPath, ... }:
+{ config, lib, pkgs, inputs, ... }:
{
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ];
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- ];
+ #
+ # imports =
+ # [
+ # ./hardware-configuration.nix
+ # ];
+ #
+ imports =
+ [
+ ./hardware-configuration.nix
+ ];
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
+ services = {
+ getty.autologinUser = "swarsel";
+ greetd.settings.initial_session.user="swarsel";
};
- nix.settings.experimental-features = ["nix-command" "flakes"];
-
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "TEMPLATE"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
+ boot = {
+ loader.systemd-boot.enable = true;
+ loader.efi.canTouchEfiVariables = true;
+ # kernelPackages = pkgs.linuxPackages_latest;
};
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
- # users.users.root.password = "TEMPLATE";
-
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
-}
-
-
-
-
-
-
-
- NGINX
-
-
-
-- NixOS
-
-
-
-{ config, pkgs, modulesPath, ... }:
-{
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- ];
+ sops.age.sshKeyPaths = [ "${config.users.users.swarsel.home}/.ssh/sops" ];
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- lego
- nginx
- ];
+ networking = {
+ hostName = "fourside"; # Define your hostname.
+ nftables.enable = true;
+ enableIPv6 = false;
+ firewall.checkReversePath = false;
+ firewall = {
+ enable = true;
+ allowedUDPPorts = [ 4380 27036 14242 34197 51820 ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard
+ allowedTCPPorts = [ ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard
+ allowedTCPPortRanges = [
+ {from = 27015; to = 27030;} # barotrauma
+ {from = 27036; to = 27037;} # barotrauma
+ ];
+ allowedUDPPortRanges = [
+ {from = 27000; to = 27031;} # barotrauma
+ {from = 58962; to = 58964;} # barotrauma
+ ];
+ };
+ };
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
-
- nix.settings.experimental-features = ["nix-command" "flakes"];
-
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/nginx/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.dnstokenfull = {owner="acme";};
- sops.templates."certs.secret".content = ''
- CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
- '';
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "nginx"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
- services.openssh = {
+ virtualisation.virtualbox = {
+ host = {
enable = true;
- settings.PermitRootLogin = "yes";
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
- # users.users.root.password = "TEMPLATE";
-
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
-
- security.acme = {
- acceptTerms = true;
- preliminarySelfsigned = false;
- defaults.email = "mrswarsel@gmail.com";
- defaults.dnsProvider = "cloudflare";
- defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
- };
+ enableExtensionPack = true;
+ };
+ # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch
+ guest = {
+ enable = false;
+ };
+ };
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
+ stylix.image = ../../wallpaper/lenovowp.png;
- services.nginx = {
+ stylix = {
enable = true;
- recommendedProxySettings = true;
- recommendedTlsSettings = true;
- recommendedOptimisation = true;
- recommendedGzipSettings = true;
- virtualHosts = {
-
- "stash.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "https://192.168.1.5";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- # "/push/" = {
- # proxyPass = "http://192.168.2.5:7867";
- # };
- "/.well-known/carddav" = {
- return = "301 $scheme://$host/remote.php/dav";
- };
- "/.well-known/caldav" = {
- return = "301 $scheme://$host/remote.php/dav";
- };
- };
+ base16Scheme = ../../wallpaper/swarsel.yaml;
+ # base16Scheme = "${pkgs.base16-schemes}/share/themes/shapeshifter.yaml";
+ polarity = "dark";
+ opacity.popups = 0.5;
+ cursor = {
+ package = pkgs.capitaine-cursors;
+ name = "capitaine-cursors";
+ size = 16;
+ };
+ fonts = {
+ sizes = {
+ terminal = 10;
+ applications = 11;
};
-
- "matrix2.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "~ ^(/_matrix|/_synapse/client)" = {
- proxyPass = "http://192.168.1.23:8008";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
+ serif = {
+ # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; });
+ package = pkgs.cantarell-fonts;
+ # package = pkgs.montserrat;
+ name = "Cantarell";
+ # name = "FiraCode Nerd Font Propo";
+ # name = "Montserrat";
};
+ sansSerif = {
+ # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; });
+ package = pkgs.cantarell-fonts;
+ # package = pkgs.montserrat;
+ name = "Cantarell";
+ # name = "FiraCode Nerd Font Propo";
+ # name = "Montserrat";
+ };
- "sound.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://192.168.1.13:4040";
- proxyWebsockets = true;
- extraConfig = ''
- proxy_redirect http:// https://;
- proxy_read_timeout 600s;
- proxy_send_timeout 600s;
- proxy_buffering off;
- proxy_request_buffering off;
- client_max_body_size 0;
- '';
- };
- };
- };
-
- "scan.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://192.168.1.24:28981";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ monospace = {
+ package = (pkgs.nerdfonts.override { fonts = [ "FiraCode"]; });
+ name = "FiraCode Nerd Font Mono";
+ };
- "screen.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://192.168.1.16:8096";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ emoji = {
+ package = pkgs.noto-fonts-emoji;
+ name = "Noto Color Emoji";
+ };
+ };
+ };
- "matrix.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "~ ^(/_matrix|/_synapse/client)" = {
- proxyPass = "http://192.168.1.20:8008";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
- "scroll.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://192.168.1.22:8080";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
- "blog.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "https://192.168.1.7";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ hardware = {
+ graphics = {
+ enable = true;
+ enable32Bit = true;
+ extraPackages = with pkgs; [
+ vulkan-loader
+ vulkan-validation-layers
+ vulkan-extension-layer
+ ];
+ };
+ bluetooth.enable = true;
+ trackpoint = {
+ enable = true;
+ device = "TPPS/2 Elan TrackPoint";
};
};
+ programs.steam = {
+ enable = true;
+ extraCompatPackages = [
+ pkgs.proton-ge-bin
+ ];
+ };
+ # Configure keymap in X11 (only used for login)
+ services.thinkfan = {
+ enable = false;
+ };
+ services.power-profiles-daemon.enable = true;
+ services.fprintd.enable = true;
+ users.users.swarsel = {
+ isNormalUser = true;
+ description = "Leon S";
+ hashedPasswordFile = config.sops.secrets.swarseluser.path;
+ extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ];
+ packages = with pkgs; [];
+ };
-}
-
-
-
-
-
-
-
-
- [Manual steps required] Calibre
-
-
-This machine requires manual setup:
-
-
-- (obsolete for now) Set up calibre-web:
-
-- Create metadata.db with 664 permissions, make sure parent directory is writeable
-- Login @ books.swarsel.win using initial creds:
-
-- user: admin
-- pw: admin123
-
-- point to metadata.db file, make sure you can upload
-- Change pw, create normal user
-
-- Setup kavita:
-
-- Login @ scrolls.swarsel.win
-- Create admin user
-- Import Libraries
-- Create normal user
-
-
+ environment.systemPackages = with pkgs; [
+ # gog games installing
+ heroic
+ # minecraft
+ temurin-bin-17
+ (prismlauncher.override {
+ glfw = pkgs.glfw-wayland-minecraft;
+ })
+ ];
+
+ system.stateVersion = "23.05";
+
+}
+
+
+
+
+
+- Home Manager
+
-In general, I am not amazed by this setup; Kavita is the reader of choice, calibre-web mostly is there to have a convenient way to fullfill the opinionated folder structure when uploading ebooks (calibre-web does not work on its own since it forces sqlite which does not work nicely with my NFS book store). I hope that in the future Kavita will implement ebook upload, or that calibre-web will ditch the sqlite constraints.
+This is basically just adjusted to the core count, path to the hwmon
(this was very bothersome on this machine due to changing address), as well as making use of the top-row function keys.
-
-
-- NixOS
-
+
-{ config, pkgs, modulesPath, ... }:
+{ config, pkgs, lib, fetchFromGitHub, ... }:
{
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- ];
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- calibre
- ];
- users.groups.lxc_shares = {
- gid = 10000;
- members = [
- "kavita"
- "calibre-web"
- "root"
- ];
+ services.gpg-agent = {
+ enable = true;
+ enableSshSupport = true;
+ enableExtraSocket = true;
+ pinentryPackage = pkgs.pinentry.gtk2;
+ defaultCacheTtl = 600;
+ maxCacheTtl = 7200;
+ extraConfig = ''
+ allow-loopback-pinentry
+ allow-emacs-pinentry
+ '';
+ };
+
+ home = {
+ username = "swarsel";
+ homeDirectory = "/home/swarsel";
+ stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing.
+ keyboard.layout = "us"; # TEMPLATE
+ packages = with pkgs; [
+ ];
};
+ sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
+ # waybar config - TEMPLATE - update for cores and temp
+ programs.waybar.settings.mainBar = {
+ cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
+ # temperature.hwmon-path = "/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon4/temp1_input";
+ temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/";
+ temperature.input-filename = "temp1_input";
};
- nix.settings.experimental-features = ["nix-command" "flakes"];
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/calibre/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.kavita = { owner = "kavita";};
- # sops.secrets.smbuser = { };
- # sops.secrets.smbpassword = { };
- # sops.secrets.smbdomain = { };
- # sops.templates."smb.cred".content = ''
- # user=${config.sops.placeholder.smbuser}
- # password=${config.sops.placeholder.smbpassword}
- # domain=${config.sops.placeholder.smbdomain}
- # '';
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "calibre"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
+ programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark"
+ "mpris"
+ "custom/left-arrow-light"
+ "network"
+ "custom/left-arrow-dark"
+ "pulseaudio"
+ "custom/left-arrow-light"
+ "custom/pseudobat"
+ "battery"
+ "custom/left-arrow-dark"
+ "group/hardware"
+ "custom/left-arrow-light"
+ "clock#2"
+ "custom/left-arrow-dark"
+ "clock#1"
+ ];
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
+ wayland.windowManager.sway= {
+ config = rec {
+ # update for actual inputs here,
+ input = {
+ "36125:53060:splitkb.com_Kyria_rev3" = {
+ xkb_layout = "us";
+ xkb_variant = "altgr-intl";
+ };
+ "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE
+ xkb_layout = "us";
+ xkb_options = "grp:win_space_toggle";
+ xkb_variant = "altgr-intl";
+ };
+ "type:touchpad" = {
+ dwt = "enabled";
+ tap = "enabled";
+ natural_scroll = "enabled";
+ middle_emulation = "enabled";
+ };
+ };
- # services.calibre-server = {
- # enable = true;
- # user = "calibre-server";
- # auth.enable = true;
- # auth.userDb = "/srv/calibre/users.sqlite";
- # libraries = [
- # /media/Books/main
- # /media/Books/diverse
- # /media/Books/language
- # /media/Books/science
- # /media/Books/sport
- # /media/Books/novels
- # ];
- # };
+ output = {
+ eDP-1 = {
+ mode = "1920x1080"; # TEMPLATE
+ scale = "1";
+ position = "1920,0";
+ # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ };
+ HDMI-A-1 = {
+ mode = "2560x1440";
+ scale = "1";
+ # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ position = "0,0";
+ };
+ };
- # services.calibre-web = {
- # enable = true;
- # user = "calibre-web";
- # group = "calibre-web";
- # listen.port = 8083;
- # listen.ip = "0.0.0.0";
- # options = {
- # enableBookUploading = true;
- # enableKepubify = true;
- # enableBookConversion = true;
- # };
- # };
+ workspaceOutputAssign = [
+ { output = "eDP-1"; workspace = "1:一";}
+ { output = "HDMI-A-1"; workspace = "2:二";}
+ ];
- services.kavita = {
- enable = true;
- user = "kavita";
- port = 8080;
- tokenKeyFile = config.sops.secrets.kavita.path;
- };
+ keybindings = let
+ modifier = config.wayland.windowManager.sway.config.modifier;
+ in {
+ "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkelement.sh\"";
+ "XF86MonBrightnessUp" = "exec brightnessctl set +5%";
+ "XF86MonBrightnessDown"= "exec brightnessctl set 5%-";
+ "XF86Display" = "exec wl-mirror eDP-1";
+ # these are left open to use
+ # "XF86WLAN" = "exec wl-mirror eDP-1";
+ # "XF86Messenger" = "exec wl-mirror eDP-1";
+ # "XF86Go" = "exec wl-mirror eDP-1";
+ # "XF86Favorites" = "exec wl-mirror eDP-1";
+ # "XF86HomePage" = "exec wtype -P Escape -p Escape";
+ # "XF86AudioLowerVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink -5%";
+ # "XF86AudioRaiseVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink +5% ";
+ "XF86AudioMute" = "pactl set-sink-mute alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink toggle";
+ };
+
+ startup = [
+
+ { command = "nextcloud --background";}
+ { command = "discord --start-minimized";}
+ { command = "element-desktop --hidden -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds";}
+ { command = "ANKI_WAYLAND=1 anki";}
+ { command = "OBSIDIAN_USE_WAYLAND=1 obsidian";}
+ { command = "nm-applet";}
+ ];
+ };
+ };
}
@@ -2891,467 +3061,363 @@
3
-- Jellyfin
-
+
- Winters (Framwork Laptop 16)
+
-- NixOS
-
-
+
- NixOS
+
+
+Mostly just sets some opened ports for several games, enables virtualbox (which I do not want everywhere because of resource considerations) and enables thinkfan, which allows for better fan control on Lenovo Thinkpad machines.
+
+
+
-{ config, pkgs, modulesPath, ... }:
+{ config, lib, pkgs, inputs, ... }:
{
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- ];
-
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- ];
- users.groups.lxc_shares = {
- gid = 10000;
- members = [
- "jellyfin"
- "root"
+ #
+ # imports =
+ # [
+ # ./hardware-configuration.nix
+ # ];
+ #
+ imports =
+ [
+ ./hardware-configuration.nix
];
+
+ services = {
+ getty.autologinUser = "swarsel";
+ greetd.settings.initial_session.user="swarsel";
};
- users.users.jellyfin = {
- extraGroups = [ "video" "render" ];
+ boot = {
+ loader.systemd-boot.enable = true;
+ loader.efi.canTouchEfiVariables = true;
+ kernelPackages = pkgs.linuxPackages_latest;
};
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
+ networking = {
+ hostName = "winters"; # Define your hostname.
+ nftables.enable = true;
+ enableIPv6 = true;
+ firewall.checkReversePath = "strict";
+ firewall = {
+ enable = true;
+ allowedUDPPorts = [ ];
+ allowedTCPPorts = [ ];
+ allowedTCPPortRanges = [
+ ];
+ allowedUDPPortRanges = [
+ ];
+ };
};
- nix.settings.experimental-features = ["nix-command" "flakes"];
+ virtualisation.virtualbox = {
+ host = {
+ enable = true;
+ enableExtensionPack = true;
+ };
+ # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch
+ guest = {
+ enable = false;
+ };
+ };
- # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- # sops.defaultSopsFile = "/.dotfiles/secrets/jellyfin/secrets.yaml";
- # sops.validateSopsFiles = false;
+ stylix.image = ../../wallpaper/lenovowp.png;
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "jellyfin"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
- services.openssh = {
+ stylix = {
enable = true;
- settings.PermitRootLogin = "yes";
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
+ base16Scheme = ../../wallpaper/swarsel.yaml;
+ # base16Scheme = "${pkgs.base16-schemes}/share/themes/shapeshifter.yaml";
+ polarity = "dark";
+ opacity.popups = 0.5;
+ cursor = {
+ package = pkgs.capitaine-cursors;
+ name = "capitaine-cursors";
+ size = 16;
+ };
+ fonts = {
+ sizes = {
+ terminal = 10;
+ applications = 11;
+ };
+ serif = {
+ # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; });
+ package = pkgs.cantarell-fonts;
+ # package = pkgs.montserrat;
+ name = "Cantarell";
+ # name = "FiraCode Nerd Font Propo";
+ # name = "Montserrat";
+ };
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ sansSerif = {
+ # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; });
+ package = pkgs.cantarell-fonts;
+ # package = pkgs.montserrat;
+ name = "Cantarell";
+ # name = "FiraCode Nerd Font Propo";
+ # name = "Montserrat";
+ };
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ monospace = {
+ package = (pkgs.nerdfonts.override { fonts = [ "FiraCode"]; });
+ name = "FiraCode Nerd Font Mono";
+ };
+
+ emoji = {
+ package = pkgs.noto-fonts-emoji;
+ name = "Noto Color Emoji";
+ };
+ };
};
- nixpkgs.config.packageOverrides = pkgs: {
- vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
- };
- hardware.graphics = {
- enable = true;
- extraPackages = with pkgs; [
- intel-media-driver # LIBVA_DRIVER_NAME=iHD
- vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
- vaapiVdpau
- libvdpau-va-gl
- ];
- };
- services.jellyfin = {
+
+
+ hardware = {
+ graphics = {
+ enable = true;
+ enable32Bit = true;
+ extraPackages = with pkgs; [
+ ];
+ };
+ bluetooth.enable = true;
+ };
+
+ programs.steam = {
enable = true;
- user = "jellyfin";
- # openFirewall = true; # this works only for the default ports
+ extraCompatPackages = [
+ pkgs.proton-ge-bin
+ ];
+ };
+
+ services.power-profiles-daemon.enable = true;
+
+ users.users.swarsel = {
+ isNormalUser = true;
+ description = "Leon S";
+ extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ];
+ packages = with pkgs; [];
};
+ environment.systemPackages = with pkgs; [
+ sbctl
+ # gog games installing
+ heroic
+ # minecraft
+ temurin-bin-17
+ (prismlauncher.override {
+ glfw = pkgs.glfw-wayland-minecraft;
+ })
+ ];
+
+ system.stateVersion = "23.05";
+
+
}
-
-
-
- [WIP/Incomplete/Untested] Transmission
-
+
- TODO Home Manager
+
-This stuff just does not work, I seem to be unable to create a working VPN Split Tunneling on NixOS. Maybe this is introduced by the wonky Proxmox-NixOS container interaction, I am not sure. For now, this machine does not work at all and I am stuck with my Debian Container that does this for me …
+TODO: Adjust hwmon
path, I/O modules and XF86 keys once laptop arrives.
-
-
-- NixOS
-
+
- { config, pkgs, modulesPath, ... }:
+{ config, pkgs, lib, fetchFromGitHub, ... }:
- {
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- # ./openvpn.nix #this file holds the vpn login data
- ];
+{
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- openvpn
- jq
- iptables
- busybox
- wireguard-tools
- ];
- users.groups.lxc_shares = {
- gid = 10000;
- members = [
- "vpn"
- "radarr"
- "sonarr"
- "lidarr"
- "readarr"
- "root"
- ];
- };
- users.groups.vpn = {};
+ services.gpg-agent = {
+ enable = true;
+ enableSshSupport = true;
+ enableExtraSocket = true;
+ pinentryPackage = pkgs.pinentry.gtk2;
+ defaultCacheTtl = 600;
+ maxCacheTtl = 7200;
+ extraConfig = ''
+ allow-loopback-pinentry
+ allow-emacs-pinentry
+ '';
+ };
- users.users.vpn = {
- isNormalUser = true;
- group = "vpn";
- home = "/home/vpn";
- };
+ home = {
+ username = "swarsel";
+ homeDirectory = "/home/swarsel";
+ stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing.
+ keyboard.layout = "us"; # TEMPLATE
+ packages = with pkgs; [
+ ];
+ };
+ sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ];
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
+ # waybar config - TEMPLATE - update for cores and temp
+ programs.waybar.settings.mainBar = {
+ cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}";
- nix.settings.experimental-features = ["nix-command" "flakes"];
+ temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/";
+ temperature.input-filename = "temp1_input";
+ };
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/transmission/secrets.yaml";
- sops.validateSopsFiles = false;
- boot.kernelModules = [ "tun" ];
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.hostName = "transmission"; # Define your hostname.
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- networking.firewall.enable = false;
+ programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark"
+ "mpris"
+ "custom/left-arrow-light"
+ "network"
+ "custom/left-arrow-dark"
+ "pulseaudio"
+ "custom/left-arrow-light"
+ "custom/pseudobat"
+ "battery"
+ "custom/left-arrow-dark"
+ "group/hardware"
+ "custom/left-arrow-light"
+ "clock#2"
+ "custom/left-arrow-dark"
+ "clock#1"
+ ];
- services.radarr = {
- enable = true;
- };
- services.readarr = {
- enable = true;
- };
- services.sonarr = {
- enable = true;
- };
- services.lidarr = {
- enable = true;
- };
- services.prowlarr = {
- enable = true;
- };
+ wayland.windowManager.sway= {
+ config = rec {
+ # update for actual inputs here,
+ input = {
+ "36125:53060:splitkb.com_Kyria_rev3" = {
+ xkb_layout = "us";
+ xkb_variant = "altgr-intl";
+ };
+ "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE
+ xkb_layout = "us";
+ xkb_options = "grp:win_space_toggle";
+ xkb_variant = "altgr-intl";
+ };
+ "type:touchpad" = {
+ dwt = "enabled";
+ tap = "enabled";
+ natural_scroll = "enabled";
+ middle_emulation = "enabled";
+ };
- # networking.interfaces = {
- # lo = {
- # useDHCP = false;
- # ipv4.addresses = [
- # { address = "127.0.0.1"; prefixLength = 8; }
- # ];
- # };
- #
- # eth0 = {
- # useDHCP = true;
- # };
- # };
+ };
- # networking.firewall.extraCommands = ''
- # sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP
- # '';
- networking.iproute2 = {
- enable = true;
- rttablesExtraConfig = ''
- 200 vpn
- '';
- };
- # boot.kernel.sysctl = {
- # "net.ipv4.conf.all.rp_filter" = 2;
- # "net.ipv4.conf.default.rp_filter" = 2;
- # "net.ipv4.conf.eth0.rp_filter" = 2;
- # };
- environment.etc = {
- "openvpn/iptables.sh" =
- { source = ../../../scripts/server1/iptables.sh;
- mode = "0755";
- };
- "openvpn/update-resolv-conf" =
- { source = ../../../scripts/server1/update-resolv-conf;
- mode = "0755";
- };
- "openvpn/routing.sh" =
- { source = ../../../scripts/server1/routing.sh;
- mode = "0755";
- };
- "openvpn/ca.rsa.2048.crt" =
- { source = ../../../secrets/certs/ca.rsa.2048.crt;
- mode = "0644";
- };
- "openvpn/crl.rsa.2048.pem" =
- { source = ../../../secrets/certs/crl.rsa.2048.pem;
- mode = "0644";
- };
- };
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
- listenAddresses = [{
- port = 22;
- addr = "0.0.0.0";
- }];
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
+ output = {
+ eDP-1 = {
+ mode = "1920x1080"; # TEMPLATE
+ scale = "1";
+ position = "1920,0";
+ # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ };
+ # external monitor
+ HDMI-A-1 = {
+ mode = "2560x1440";
+ scale = "1";
+ # bg = "~/.dotfiles/wallpaper/lenovowp.png fill";
+ position = "0,0";
+ };
+ };
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
- # users.users.root.password = "TEMPLATE";
+ workspaceOutputAssign = [
+ { output = "eDP-1"; workspace = "1:一";}
+ { output = "HDMI-A-1"; workspace = "2:二";}
+ ];
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
- sops.secrets.vpnuser = {};
- sops.secrets.rpcuser = {owner="vpn";};
- sops.secrets.vpnpass = {};
- sops.secrets.rpcpass = {owner="vpn";};
- sops.secrets.vpnprot = {};
- sops.secrets.vpnloc = {};
- # sops.secrets.crlpem = {};
- # sops.secrets.capem = {};
- sops.templates."transmission-rpc".owner = "vpn";
- sops.templates."transmission-rpc".content = builtins.toJSON {
- rpc-username = config.sops.placeholder.rpcuser;
- rpc-password = config.sops.placeholder.rpcpass;
- };
+ keybindings = let
+ modifier = config.wayland.windowManager.sway.config.modifier;
+ in {
- sops.templates.pia.content = ''
- ${config.sops.placeholder.vpnuser}
- ${config.sops.placeholder.vpnpass}
- '';
+ };
- sops.templates.vpn.content = ''
- client
- dev tun
- proto ${config.sops.placeholder.vpnprot}
- remote ${config.sops.placeholder.vpnloc}
- resolv-retry infinite
- nobind
- persist-key
- persist-tun
- cipher aes-128-cbc
- auth sha1
- tls-client
- remote-cert-tls server
+ startup = [
- auth-user-pass ${config.sops.templates.pia.path}
- compress
- verb 1
- reneg-sec 0
+ { command = "nextcloud --background";}
+ { command = "discord --start-minimized";}
+ { command = "element-desktop --hidden -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds";}
+ { command = "ANKI_WAYLAND=1 anki";}
+ { command = "OBSIDIAN_USE_WAYLAND=1 obsidian";}
+ { command = "nm-applet";}
- crl-verify /etc/openvpn/crl.rsa.2048.pem
- ca /etc/openvpn/ca.rsa.2048.crt
+ ];
+ };
+ };
+}
- disable-occ
- dhcp-option DNS 209.222.18.222
- dhcp-option DNS 209.222.18.218
- dhcp-option DNS 8.8.8.8
- route-noexec
- '';
+
+
+
+
+
+
+
+
+
+
3.1.3. Virtual hosts
+
+
+My server setup is built on Proxmox VE; back when I started, I created all kinds of wild Debian/Ubuntu/etc. KVMs and LXCs on there. However, the root disk has suffered a weird failure where it has become unable to be cloned, but it is still functional for now. I am currently rewriting all machines on there to use NixOS instead; this is a ongoing process.
+
- # services.pia.enable = true;
- # services.pia.authUserPass.username = "na";
- # services.pia.authUserPass.password = "na";
+
+In the long run, I am thinking about a transition to kubernetes or using just a server running NixOS and using the built-in container functionality. For now however, I like the network management provided by Proxmox, as I am a bit intimidated by doing that from scratch.
+
+
+
+- TEMPLATE
+
+
+
+- NixOS
+
+
+
+{ pkgs, modulesPath, ... }:
+{
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ];
- # systemd.services.openvpn-vpn = {
- # wantedBy = [ "multi-user.target" ];
- # after = [ "network.target" ];
- # description = "OpenVPN connection to pia";
- # serviceConfig = {
- # Type = "forking";
- # RuntimeDirectory="openvpn";
- # PrivateTmp=true;
- # KillMode="mixed";
- # ExecStart = ''@${pkgs.openvpn}/sbin/openvpn openvpn --daemon ovpn-pia --status /run/openvpn/pia.status 10 --cd /etc/openvpn --script-security 2 --config ${config.sops.templates.vpn.path} --writepid /run/openvpn/pia.pid'';
- # PIDFile=''/run/openvpn/pia.pid'';
- # ExecReload=''/run/current-system/sw/bin/kill -HUP $MAINPID'';
- # WorkingDirectory="/etc/openvpn";
- # Restart="on-failure";
- # RestartSec=30;
- # ProtectSystem="yes";
- # DeviceAllow=["/dev/null rw" "/dev/net/tun rw"];
- # };
- # };
- services.openvpn.servers = {
- pia = {
- autoStart = false;
- updateResolvConf = true;
-# up = ''
-# export INTERFACE="tun0"
-# export VPNUSER="vpn"
-# export LOCALIP="192.168.1.191"
-# export NETIF="eth0"
-# export VPNIF="tun0"
-# export GATEWAYIP=$(ifconfig $VPNIF | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}' | egrep -v '255|(127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})' | tail -n1)
-# iptables -F -t nat
-# iptables -F -t mangle
-# iptables -F -t filter
-# iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
-# iptables -t mangle -A OUTPUT ! --dest $LOCALIP -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
-# iptables -t mangle -A OUTPUT --dest $LOCALIP -p udp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
-# iptables -t mangle -A OUTPUT --dest $LOCALIP -p tcp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
-# iptables -t mangle -A OUTPUT ! --src $LOCALIP -j MARK --set-mark 0x1
-# iptables -t mangle -A OUTPUT -j CONNMARK --save-mark
-# iptables -A INPUT -i $INTERFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-# iptables -A INPUT -i $INTERFACE -j REJECT
-# iptables -A OUTPUT -o lo -m owner --uid-owner $VPNUSER -j ACCEPT
-# iptables -A OUTPUT -o $INTERFACE -m owner --uid-owner $VPNUSER -j ACCEPT
-# iptables -t nat -A POSTROUTING -o $INTERFACE -j MASQUERADE
-# iptables -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-# iptables -A OUTPUT ! --src $LOCALIP -o $NETIF -j REJECT
-# if [[ `ip rule list | grep -c 0x1` == 0 ]]; then
-# ip rule add from all fwmark 0x1 lookup $VPNUSER
-# fi
-# ip route replace default via $GATEWAYIP table $VPNUSER
-# ip route append default via 127.0.0.1 dev lo table $VPNUSER
-# ip route flush cache
- # '';
- # down = "bash /etc/openvpn/update-resolv-conf";
- # these are outsourced to a local file, I am not sure if it can be done with sops-nix
- # authUserPass = {
- # username = "TODO:secrets";
- # password = "TODO:secrets";
- # };
- config = "config ${config.sops.templates.vpn.path}";
- };
- };
-
- services.transmission = {
- enable = true;
- credentialsFile = config.sops.templates."transmission-rpc".path;
- user = "vpn";
- group = "lxc_shares";
- settings = {
-
- alt-speed-down= 8000;
- alt-speed-enabled= false;
- alt-speed-time-begin= 0;
- alt-speed-time-day= 127;
- alt-speed-time-enabled= true;
- alt-speed-time-end= 360;
- alt-speed-up= 2000;
- bind-address-ipv4= "0.0.0.0";
- bind-address-ipv6= "::";
- blocklist-enabled= false;
- blocklist-url= "http://www.example.com/blocklist";
- cache-size-mb= 4;
- dht-enabled= false;
- download-dir= "/media/Eternor/New";
- download-limit= 100;
- download-limit-enabled= 0;
- download-queue-enabled= true;
- download-queue-size= 5;
- encryption= 2;
- idle-seeding-limit= 30;
- idle-seeding-limit-enabled= false;
- incomplete-dir= "/var/lib/transmission-daemon/Downloads";
- incomplete-dir-enabled= false;
- lpd-enabled= false;
- max-peers-global= 200;
- message-level= 1;
- peer-congestion-algorithm= "";
- peer-id-ttl-hours= 6;
- peer-limit-global= 100;
- peer-limit-per-torrent= 40;
- peer-port= 22371;
- peer-port-random-high= 65535;
- peer-port-random-low= 49152;
- peer-port-random-on-start= false;
- peer-socket-tos= "default";
- pex-enabled= false;
- port-forwarding-enabled= false;
- preallocation= 1;
- prefetch-enabled= true;
- queue-stalled-enabled= true;
- queue-stalled-minutes= 30;
- ratio-limit= 2;
- ratio-limit-enabled= false;
- rename-partial-files= true;
- rpc-authentication-required= true;
- rpc-bind-address= "0.0.0.0";
- rpc-enabled= true;
- rpc-host-whitelist= "";
- rpc-host-whitelist-enabled= true;
- rpc-port= 9091;
- rpc-url= "/transmission/";
- rpc-whitelist= "127.0.0.1,192.168.3.2";
- rpc-whitelist-enabled= true;
- scrape-paused-torrents-enabled= true;
- script-torrent-done-enabled= false;
- seed-queue-enabled= false;
- seed-queue-size= 10;
- speed-limit-down= 6000;
- speed-limit-down-enabled= true;
- speed-limit-up= 500;
- speed-limit-up-enabled= true;
- start-added-torrents= true;
- trash-original-torrent-files= false;
- umask= 2;
- upload-limit= 100;
- upload-limit-enabled= 0;
- upload-slots-per-torrent= 14;
- utp-enabled= false;
- };
- };
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ ];
- # services.nginx = {
- # enable = true;
- # virtualHosts = {
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
- # "192.168.1.192" = {
- # locations = {
- # "/transmission" = {
- # proxyPass = "http://127.0.0.1:9091";
- # extraConfig = ''
- # proxy_set_header Host $host;
- # proxy_set_header X-Real-IP $remote_addr;
- # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- # '';
- # };
- # };
- # };
- # };
- # };
+ nix.settings.experimental-features = ["nix-command" "flakes"];
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "TEMPLATE"; # Define your hostname.
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ networking.firewall.enable = false;
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
+ # users.users.root.password = "TEMPLATE";
- }
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+}
@@ -3359,329 +3425,357 @@
3
-- [Manual steps needed] Matrix
-
-
-- After the initial setup, run the
-
-- /run/secrets-generated/matrixuserregister.sh
-
-
-
-command to register a new admin user.
-
-
-- All bridges will fail on first start, copy the registration files using:
-
-- cp var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse
-- chown matrix-synapse:matrix-synapse var/lib/matrix-synapse/telegram-registration.yaml
-
-
-
-Make sure to also do this for doublepuppet.yaml
-
-
-- Restart postgresql.service, matrix-synapse.service, mautrix-whatsapp.service, mautrix-telegram.service
-
+
- NGINX
+
-- NixOS
-
+
- NixOS
+
-{ config, pkgs, modulesPath, unstable, sops, ... }: let
- matrixDomain = "matrix2.swarsel.win";
-in {
+{ config, pkgs, modulesPath, ... }:
+{
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
+ ];
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ lego
+ nginx
+ ];
services.xserver = {
layout = "us";
xkbVariant = "altgr-intl";
};
+
nix.settings.experimental-features = ["nix-command" "flakes"];
+
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/.dotfiles/secrets/nginx/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.dnstokenfull = {owner="acme";};
+ sops.templates."certs.secret".content = ''
+ CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
+ '';
proxmoxLXC.manageNetwork = true; # manage network myself
proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "nginx"; # Define your hostname.
networking.useDHCP = true;
networking.enableIPv6 = false;
+ networking.firewall.enable = false;
services.openssh = {
enable = true;
settings.PermitRootLogin = "yes";
- listenAddresses = [{
- port = 22;
- addr = "0.0.0.0";
- }];
};
users.users.root.openssh.authorizedKeys.keyFiles = [
../../../secrets/keys/authorized_keys
];
+ # users.users.root.password = "TEMPLATE";
system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ security.acme = {
+ acceptTerms = true;
+ preliminarySelfsigned = false;
+ defaults.email = "mrswarsel@gmail.com";
+ defaults.dnsProvider = "cloudflare";
+ defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
+ };
+
environment.shellAliases = {
nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
};
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ virtualHosts = {
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- # we import here a service that is not available yet on normal nixpkgs
- # this module is hence not in the modules list, we add it ourselves
+ "stash.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "https://192.168.1.5";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ # "/push/" = {
+ # proxyPass = "http://192.168.2.5:7867";
+ # };
+ "/.well-known/carddav" = {
+ return = "301 $scheme://$host/remote.php/dav";
+ };
+ "/.well-known/caldav" = {
+ return = "301 $scheme://$host/remote.php/dav";
+ };
+ };
+ };
+
+ "matrix2.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "~ ^(/_matrix|/_synapse/client)" = {
+ proxyPass = "http://192.168.1.23:8008";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+
+
+ "sound.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.13:4040";
+ proxyWebsockets = true;
+ extraConfig = ''
+ proxy_redirect http:// https://;
+ proxy_read_timeout 600s;
+ proxy_send_timeout 600s;
+ proxy_buffering off;
+ proxy_request_buffering off;
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+
+ "scan.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.24:28981";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+
+ "screen.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.16:8096";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+
+ "matrix.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "~ ^(/_matrix|/_synapse/client)" = {
+ proxyPass = "http://192.168.1.20:8008";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+
+ "scroll.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.22:8080";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+
+ "blog.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "https://192.168.1.7";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+
+ };
+ };
+
+
+
+
+
+}
+
+
+
+
+
+
+
+
- [Manual steps required] Calibre
+
+
+This machine requires manual setup:
+
+
+- (obsolete for now) Set up calibre-web:
+
+- Create metadata.db with 664 permissions, make sure parent directory is writeable
+- Login @ books.swarsel.win using initial creds:
+
+- user: admin
+- pw: admin123
+
+- point to metadata.db file, make sure you can upload
+- Change pw, create normal user
+
+- Setup kavita:
+
+- Login @ scrolls.swarsel.win
+- Create admin user
+- Import Libraries
+- Create normal user
+
+
+
+
+In general, I am not amazed by this setup; Kavita is the reader of choice, calibre-web mostly is there to have a convenient way to fullfill the opinionated folder structure when uploading ebooks (calibre-web does not work on its own since it forces sqlite which does not work nicely with my NFS book store). I hope that in the future Kavita will implement ebook upload, or that calibre-web will ditch the sqlite constraints.
+
+
+
+- NixOS
+
+
+
+{ config, pkgs, modulesPath, ... }:
+
+{
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
];
- networking.hostName = "matrix"; # Define your hostname.
- networking.firewall.enable = false;
environment.systemPackages = with pkgs; [
git
gnupg
ssh-to-age
- matrix-synapse
- lottieconverter
- ffmpeg
+ calibre
];
+ users.groups.lxc_shares = {
+ gid = 10000;
+ members = [
+ "kavita"
+ "calibre-web"
+ "root"
+ ];
+ };
+
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
+
+ nix.settings.experimental-features = ["nix-command" "flakes"];
+
sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/matrix/secrets.yaml";
+ sops.defaultSopsFile = "/.dotfiles/secrets/calibre/secrets.yaml";
sops.validateSopsFiles = false;
- sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
- sops.templates."matrix_user_register.sh".content = ''
- register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
- '';
- sops.templates.matrixshared.owner = "matrix-synapse";
- sops.templates.matrixshared.content = ''
- registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
- '';
- sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
- sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
- sops.templates.mautrixtelegram.owner = "matrix-synapse";
- sops.templates.mautrixtelegram.content = ''
- MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
- MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
- MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
- MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
- '';
- # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
- # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
- # sops.templates.mautrixwhatsapp.content = ''
- # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
+ sops.secrets.kavita = { owner = "kavita";};
+ # sops.secrets.smbuser = { };
+ # sops.secrets.smbpassword = { };
+ # sops.secrets.smbdomain = { };
+ # sops.templates."smb.cred".content = ''
+ # user=${config.sops.placeholder.smbuser}
+ # password=${config.sops.placeholder.smbpassword}
+ # domain=${config.sops.placeholder.smbdomain}
# '';
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "calibre"; # Define your hostname.
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ networking.firewall.enable = false;
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
- services.postgresql.enable = true;
- services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
- CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
- CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
- CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
- CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
- CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- '';
-
- services.matrix-synapse = {
- settings.app_service_config_files = [
- "/var/lib/matrix-synapse/telegram-registration.yaml"
- "/var/lib/matrix-synapse/whatsapp-registration.yaml"
- "/var/lib/matrix-synapse/signal-registration.yaml"
- "/var/lib/matrix-synapse/doublepuppet.yaml"
- ];
- enable = true;
- settings.server_name = matrixDomain;
- settings.public_baseurl = "https://${matrixDomain}";
- extraConfigFiles = [
- config.sops.templates.matrixshared.path
- ];
- settings.listeners = [
- { port = 8008;
- bind_addresses = [ "0.0.0.0" ];
- type = "http";
- tls = false;
- x_forwarded = true;
- resources = [
- {
- names = [ "client" "federation" ];
- compress = true;
- }
- ];
- }
- ];
- };
-
- services.mautrix-telegram = {
- enable = true;
- environmentFile = config.sops.templates.mautrixtelegram.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29317";
- hostname = "0.0.0.0";
- port = "29317";
- provisioning.enabled = true;
- id = "telegram";
- # ephemeral_events = true; # not needed due to double puppeting
- public = {
- enabled = false;
- };
- database = "postgresql:///mautrix-telegram?host=/run/postgresql";
- };
- bridge = {
- # login_shared_secret_map = {
- # matrixDomain = "as_token:doublepuppet";
- # };
- relaybot.authless_portals = true;
- allow_avatar_remove = true;
- allow_contact_info = true;
- sync_channel_members = true;
- startup_sync = true;
- sync_create_limit = 0;
- sync_direct_chats = true;
- telegram_link_preview = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- # Animated stickers conversion requires additional packages in the
- # service's path.
- # If this isn't a fresh installation, clearing the bridge's uploaded
- # file cache might be necessary (make a database backup first!):
- # delete from telegram_file where \
- # mime_type in ('application/gzip', 'application/octet-stream')
- animated_sticker = {
- target = "gif";
- args = {
- width = 256;
- height = 256;
- fps = 30; # only for webm
- background = "020202"; # only for gif, transparency not supported
- };
- };
- };
- };
- };
- systemd.services.mautrix-telegram.path = with pkgs; [
- lottieconverter # for animated stickers conversion, unfree package
- ffmpeg # if converting animated stickers to webm (very slow!)
- ];
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
- services.mautrix-whatsapp = {
- enable = true;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29318";
- hostname = "0.0.0.0";
- port = 29318;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
- };
- };
- bridge = {
- displayname_template = "{{or .FullName .PushName .JID}} (WA)";
- history_sync = {
- backfill = true;
- max_initial_conversations = -1;
- message_count = -1;
- request_full_sync = true;
- full_sync_config = {
- days_limit = 900;
- size_mb_limit = 5000;
- storage_quota_mb = 5000;
- };
- };
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- sync_manual_marked_unread = true;
- send_presence_on_typing = true;
- parallel_member_sync = true;
- url_previews = true;
- caption_in_message = true;
- extev_polls = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- };
- };
+ environment.shellAliases = {
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
};
- services.mautrix-signal = {
- enable = true;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29328";
- hostname = "0.0.0.0";
- port = 29328;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-signal?host=/run/postgresql";
- };
- };
- bridge = {
- displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- caption_in_message = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- };
- };
- };
+ # services.calibre-server = {
+ # enable = true;
+ # user = "calibre-server";
+ # auth.enable = true;
+ # auth.userDb = "/srv/calibre/users.sqlite";
+ # libraries = [
+ # /media/Books/main
+ # /media/Books/diverse
+ # /media/Books/language
+ # /media/Books/science
+ # /media/Books/sport
+ # /media/Books/novels
+ # ];
+ # };
- # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
- # messages out after a while.
+ # services.calibre-web = {
+ # enable = true;
+ # user = "calibre-web";
+ # group = "calibre-web";
+ # listen.port = 8083;
+ # listen.ip = "0.0.0.0";
+ # options = {
+ # enableBookUploading = true;
+ # enableKepubify = true;
+ # enableBookConversion = true;
+ # };
+ # };
- systemd.timers."restart-bridges" = {
- wantedBy = [ "timers.target" ];
- timerConfig = {
- OnBootSec = "1d";
- OnUnitActiveSec = "1d";
- Unit = "restart-bridges.service";
- };
+ services.kavita = {
+ enable = true;
+ user = "kavita";
+ port = 8080;
+ tokenKeyFile = config.sops.secrets.kavita.path;
};
- systemd.services."restart-bridges" = {
- script = ''
- systemctl restart mautrix-whatsapp.service
- systemctl restart mautrix-signal.service
- systemctl restart mautrix-telegram.service
- '';
- serviceConfig = {
- Type = "oneshot";
- User = "root";
- };
- };
}
@@ -3691,187 +3785,60 @@ 3
-- Sound
-
+
- Jellyfin
+
-- NixOS
-
+
- NixOS
+
{ config, pkgs, modulesPath, ... }:
{
-
imports = [
(modulesPath + "/virtualisation/proxmox-lxc.nix")
./hardware-configuration.nix
];
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ ];
-
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
- nix.settings.experimental-features = ["nix-command" "flakes"];
- proxmoxLXC.manageNetwork = true; # manage network myself
- proxmoxLXC.manageHostName = false; # manage hostname myself
- networking.useDHCP = true;
- networking.enableIPv6 = false;
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
- listenAddresses = [{
- port = 22;
- addr = "0.0.0.0";
- }];
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../secrets/keys/authorized_keys
- ];
-
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
-
- environment.shellAliases = {
- nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
-
-
-
- proxmoxLXC.privileged = true; # manage hostname myself
-
- users.groups.lxc_pshares = {
- gid = 110000;
+ users.groups.lxc_shares = {
+ gid = 10000;
members = [
- "navidrome"
- "mpd"
+ "jellyfin"
"root"
];
};
- users.groups.navidrome = {
- gid = 61593;
- };
-
- users.groups.mpd = {};
-
- users.users.navidrome = {
- isSystemUser = true;
- uid = 61593;
- group = "navidrome";
- extraGroups = [ "audio" "utmp" ];
- };
-
- users.users.mpd = {
- isSystemUser = true;
- group = "mpd";
- extraGroups = [ "audio" "utmp" ];
- };
-
- sound = {
- enable = true;
- };
-
- hardware.enableAllFirmware = true;
- networking.hostName = "sound"; # Define your hostname.
- networking.firewall.enable = false;
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- pciutils
- alsa-utils
- mpv
- ];
-
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/.dotfiles/secrets/sound/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.mpdpass = { owner = "mpd";};
-
- services.navidrome = {
- enable = true;
- settings = {
- Address = "0.0.0.0";
- Port = 4040;
- MusicFolder = "/media";
- EnableSharing = true;
- EnableTranscodingConfig = true;
- Scanner.GroupAlbumReleases = true;
- ScanSchedule = "@every 1d";
- # Insert these values locally as sops-nix does not work for them
- LastFM.ApiKey = TEMPLATE;
- LastFM.Secret = TEMPLATE;
- Spotify.ID = TEMPLATE;
- Spotify.Secret = TEMPLATE;
- UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png";
- UIWelcomeMessage = "~SwarselSound~";
- };
- };
- services.mpd = {
- enable = true;
- musicDirectory = "/media";
- user = "mpd";
- group = "mpd";
- network = {
- port = 3254;
- listenAddress = "any";
- };
- credentials = [
- {
- passwordFile = config.sops.secrets.mpdpass.path;
- permissions = [
- "read"
- "add"
- "control"
- "admin"
- ];
- }
- ];
+ users.users.jellyfin = {
+ extraGroups = [ "video" "render" ];
};
-}
-
-
-
-
-
-
-
- Spotifyd
-
-
-
-- NixOS
-
-
-
-{ config, pkgs, modulesPath, ... }:
-
-{
-
- imports = [
- (modulesPath + "/virtualisation/proxmox-lxc.nix")
- ./hardware-configuration.nix
- ];
-
-
services.xserver = {
layout = "us";
xkbVariant = "altgr-intl";
};
+
nix.settings.experimental-features = ["nix-command" "flakes"];
+
+ # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ # sops.defaultSopsFile = "/.dotfiles/secrets/jellyfin/secrets.yaml";
+ # sops.validateSopsFiles = false;
+
proxmoxLXC.manageNetwork = true; # manage network myself
proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "jellyfin"; # Define your hostname.
networking.useDHCP = true;
networking.enableIPv6 = false;
+ networking.firewall.enable = false;
services.openssh = {
enable = true;
settings.PermitRootLogin = "yes";
- listenAddresses = [{
- port = 22;
- addr = "0.0.0.0";
- }];
};
users.users.root.openssh.authorizedKeys.keyFiles = [
../../../secrets/keys/authorized_keys
@@ -3883,50 +3850,23 @@ 3
nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
};
+ nixpkgs.config.packageOverrides = pkgs: {
+ vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
+ };
+ hardware.graphics = {
+ enable = true;
+ extraPackages = with pkgs; [
+ intel-media-driver # LIBVA_DRIVER_NAME=iHD
+ vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
+ vaapiVdpau
+ libvdpau-va-gl
+ ];
+ };
-
- proxmoxLXC.privileged = true; # manage hostname myself
-
- users.groups.spotifyd = {
- gid = 65136;
- };
-
- users.users.spotifyd = {
- isSystemUser = true;
- uid = 65136;
- group = "spotifyd";
- extraGroups = [ "audio" "utmp" ];
- };
-
- sound = {
- enable = true;
- };
-
- hardware.enableAllFirmware = true;
- networking.hostName = "spotifyd"; # Define your hostname.
- networking.firewall.enable = false;
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- ];
-
- # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- # sops.defaultSopsFile = "/.dotfiles/secrets/spotifyd/secrets.yaml";
- # sops.validateSopsFiles = false;
-
- services.spotifyd = {
+ services.jellyfin = {
enable = true;
- settings = {
- global = {
- dbus_type = "session";
- use_mpris = false;
- device = "default:CARD=PCH";
- device_name = "SwarselSpot";
- mixer = "alsa";
- zeroconf_port = 1025;
- };
- };
+ user = "jellyfin";
+ # openFirewall = true; # this works only for the default ports
};
}
@@ -3937,342 +3877,466 @@ 3
-- Sync
-
+
- [WIP/Incomplete/Untested] Transmission
+
+
+This stuff just does not work, I seem to be unable to create a working VPN Split Tunneling on NixOS. Maybe this is introduced by the wonky Proxmox-NixOS container interaction, I am not sure. For now, this machine does not work at all and I am stuck with my Debian Container that does this for me …
+
-- NixOS
-
+
- NixOS
+
-{ config, pkgs, modulesPath, ... }:
-
-{
- imports = [
- ./hardware-configuration.nix
- ];
-
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- ];
+ { config, pkgs, modulesPath, ... }:
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
+ {
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
+ # ./openvpn.nix #this file holds the vpn login data
+ ];
- nix.settings.experimental-features = ["nix-command" "flakes"];
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ openvpn
+ jq
+ iptables
+ busybox
+ wireguard-tools
+ ];
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/root/.dotfiles/secrets/sync/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.swarsel = { owner = "root";};
- sops.secrets.dnstokenfull = {owner="acme";};
- sops.templates."certs.secret".content = ''
- CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
- '';
+ users.groups.lxc_shares = {
+ gid = 10000;
+ members = [
+ "vpn"
+ "radarr"
+ "sonarr"
+ "lidarr"
+ "readarr"
+ "root"
+ ];
+ };
+ users.groups.vpn = {};
- security.acme = {
- acceptTerms = true;
- preliminarySelfsigned = false;
- defaults.email = "mrswarsel@gmail.com";
- defaults.dnsProvider = "cloudflare";
- defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
- };
+ users.users.vpn = {
+ isNormalUser = true;
+ group = "vpn";
+ home = "/home/vpn";
+ };
- services.nginx = {
- enable = true;
- recommendedProxySettings = true;
- recommendedTlsSettings = true;
- recommendedOptimisation = true;
- recommendedGzipSettings = true;
- virtualHosts = {
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
- "synki.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://localhost:27701";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ nix.settings.experimental-features = ["nix-command" "flakes"];
- "sync.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://localhost:8384/";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/.dotfiles/secrets/transmission/secrets.yaml";
+ sops.validateSopsFiles = false;
- "swagit.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://localhost:3000";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
- };
- };
+ boot.kernelModules = [ "tun" ];
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.hostName = "transmission"; # Define your hostname.
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ networking.firewall.enable = false;
- boot.tmp.cleanOnBoot = true;
- zramSwap.enable = false;
- networking.hostName = "sync";
- networking.enableIPv6 = false;
- networking.domain = "subnet03112148.vcn03112148.oraclevcn.com";
- networking.firewall.extraCommands = ''
- iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 27701 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 8384 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 3000 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 22000 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p udp --dport 22000 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p udp --dport 21027 -j ACCEPT
- '';
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../../secrets/keys/authorized_keys
- ];
+ services.radarr = {
+ enable = true;
+ };
- system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change
+ services.readarr = {
+ enable = true;
+ };
+ services.sonarr = {
+ enable = true;
+ };
+ services.lidarr = {
+ enable = true;
+ };
+ services.prowlarr = {
+ enable = true;
+ };
- environment.shellAliases = {
- nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
+ # networking.interfaces = {
+ # lo = {
+ # useDHCP = false;
+ # ipv4.addresses = [
+ # { address = "127.0.0.1"; prefixLength = 8; }
+ # ];
+ # };
+ #
+ # eth0 = {
+ # useDHCP = true;
+ # };
+ # };
- boot.loader.grub.device = "nodev";
+ # networking.firewall.extraCommands = ''
+ # sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP
+ # '';
+ networking.iproute2 = {
+ enable = true;
+ rttablesExtraConfig = ''
+ 200 vpn
+ '';
+ };
+ # boot.kernel.sysctl = {
+ # "net.ipv4.conf.all.rp_filter" = 2;
+ # "net.ipv4.conf.default.rp_filter" = 2;
+ # "net.ipv4.conf.eth0.rp_filter" = 2;
+ # };
+ environment.etc = {
+ "openvpn/iptables.sh" =
+ { source = ../../../scripts/server1/iptables.sh;
+ mode = "0755";
+ };
+ "openvpn/update-resolv-conf" =
+ { source = ../../../scripts/server1/update-resolv-conf;
+ mode = "0755";
+ };
+ "openvpn/routing.sh" =
+ { source = ../../../scripts/server1/routing.sh;
+ mode = "0755";
+ };
+ "openvpn/ca.rsa.2048.crt" =
+ { source = ../../../secrets/certs/ca.rsa.2048.crt;
+ mode = "0644";
+ };
+ "openvpn/crl.rsa.2048.pem" =
+ { source = ../../../secrets/certs/crl.rsa.2048.pem;
+ mode = "0644";
+ };
+ };
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ listenAddresses = [{
+ port = 22;
+ addr = "0.0.0.0";
+ }];
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
- services.anki-sync-server = {
- enable = true;
- port = 27701;
- address = "0.0.0.0";
- openFirewall = true;
- users = [
- {
- username = "Swarsel";
- passwordFile = config.sops.secrets.swarsel.path;
- }
- ];
- };
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ # users.users.root.password = "TEMPLATE";
- services.syncthing = {
- enable = true;
- guiAddress = "0.0.0.0:8384";
- openDefaultPorts = true;
- };
+ environment.shellAliases = {
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
- services.forgejo = {
- enable = true;
- settings = {
- DEFAULT = {
- APP_NAME = "~SwaGit~";
- };
- server = {
- PROTOCOL = "http";
- HTTP_PORT = 3000;
- HTTP_ADDR = "0.0.0.0";
- DOMAIN = "swagit.swarsel.win";
- ROOT_URL = "https://swagit.swarsel.win";
- };
- service = {
- DISABLE_REGISTRATION = true;
- SHOW_REGISTRATION_BUTTON = false;
- };
- };
- };
+ sops.secrets.vpnuser = {};
+ sops.secrets.rpcuser = {owner="vpn";};
+ sops.secrets.vpnpass = {};
+ sops.secrets.rpcpass = {owner="vpn";};
+ sops.secrets.vpnprot = {};
+ sops.secrets.vpnloc = {};
+ # sops.secrets.crlpem = {};
+ # sops.secrets.capem = {};
+ sops.templates."transmission-rpc".owner = "vpn";
+ sops.templates."transmission-rpc".content = builtins.toJSON {
+ rpc-username = config.sops.placeholder.rpcuser;
+ rpc-password = config.sops.placeholder.rpcpass;
+ };
-}
+ sops.templates.pia.content = ''
+ ${config.sops.placeholder.vpnuser}
+ ${config.sops.placeholder.vpnpass}
+ '';
-
-
-
-
-
-
-
- [Manual steps required] Swatrix
-
-
-
-- NixOS
-
-
-The files mentioned by
-
+ sops.templates.vpn.content = ''
+ client
+ dev tun
+ proto ${config.sops.placeholder.vpnprot}
+ remote ${config.sops.placeholder.vpnloc}
+ resolv-retry infinite
+ nobind
+ persist-key
+ persist-tun
+ cipher aes-128-cbc
+ auth sha1
+ tls-client
+ remote-cert-tls server
-
-
-settings.app_service_config_files = [
- "/var/lib/matrix-synapse/telegram-registration.yaml"
- "/var/lib/matrix-synapse/whatsapp-registration.yaml"
- "/var/lib/matrix-synapse/signal-registration.yaml"
- "/var/lib/matrix-synapse/doublepuppet.yaml"
- ]
+ auth-user-pass ${config.sops.templates.pia.path}
+ compress
+ verb 1
+ reneg-sec 0
-
-
+ crl-verify /etc/openvpn/crl.rsa.2048.pem
+ ca /etc/openvpn/ca.rsa.2048.crt
-
-need to be moved to the corresponding location. The below files are created as soon as the appservice is run once. This means that matrix will crash on the first startup; afterwards run these commands and restart the service.
-
+ disable-occ
+ dhcp-option DNS 209.222.18.222
+ dhcp-option DNS 209.222.18.218
+ dhcp-option DNS 8.8.8.8
+ route-noexec
+ '';
-
-
-cp /var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse/
-chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/telegram-registration.yaml
-cp /var/lib/mautrix-signal/signal-registration.yaml /var/lib/matrix-synapse/
-chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/signal-registration.yaml
-cp /var/lib/mautrix-whatsapp/whatsapp-registration.yaml /var/lib/matrix-synapse/
-chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/whatsapp-registration.yaml
+ # services.pia.enable = true;
+ # services.pia.authUserPass.username = "na";
+ # services.pia.authUserPass.password = "na";
-
-
-
-as for the contents of doublepuppet.yaml:
-
+ # systemd.services.openvpn-vpn = {
+ # wantedBy = [ "multi-user.target" ];
+ # after = [ "network.target" ];
+ # description = "OpenVPN connection to pia";
+ # serviceConfig = {
+ # Type = "forking";
+ # RuntimeDirectory="openvpn";
+ # PrivateTmp=true;
+ # KillMode="mixed";
+ # ExecStart = ''@${pkgs.openvpn}/sbin/openvpn openvpn --daemon ovpn-pia --status /run/openvpn/pia.status 10 --cd /etc/openvpn --script-security 2 --config ${config.sops.templates.vpn.path} --writepid /run/openvpn/pia.pid'';
+ # PIDFile=''/run/openvpn/pia.pid'';
+ # ExecReload=''/run/current-system/sw/bin/kill -HUP $MAINPID'';
+ # WorkingDirectory="/etc/openvpn";
+ # Restart="on-failure";
+ # RestartSec=30;
+ # ProtectSystem="yes";
+ # DeviceAllow=["/dev/null rw" "/dev/net/tun rw"];
+ # };
+ # };
+ services.openvpn.servers = {
+ pia = {
+ autoStart = false;
+ updateResolvConf = true;
+# up = ''
+# export INTERFACE="tun0"
+# export VPNUSER="vpn"
+# export LOCALIP="192.168.1.191"
+# export NETIF="eth0"
+# export VPNIF="tun0"
+# export GATEWAYIP=$(ifconfig $VPNIF | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}' | egrep -v '255|(127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})' | tail -n1)
+# iptables -F -t nat
+# iptables -F -t mangle
+# iptables -F -t filter
+# iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
+# iptables -t mangle -A OUTPUT ! --dest $LOCALIP -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
+# iptables -t mangle -A OUTPUT --dest $LOCALIP -p udp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
+# iptables -t mangle -A OUTPUT --dest $LOCALIP -p tcp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1
+# iptables -t mangle -A OUTPUT ! --src $LOCALIP -j MARK --set-mark 0x1
+# iptables -t mangle -A OUTPUT -j CONNMARK --save-mark
+# iptables -A INPUT -i $INTERFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+# iptables -A INPUT -i $INTERFACE -j REJECT
+# iptables -A OUTPUT -o lo -m owner --uid-owner $VPNUSER -j ACCEPT
+# iptables -A OUTPUT -o $INTERFACE -m owner --uid-owner $VPNUSER -j ACCEPT
+# iptables -t nat -A POSTROUTING -o $INTERFACE -j MASQUERADE
+# iptables -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+# iptables -A OUTPUT ! --src $LOCALIP -o $NETIF -j REJECT
+# if [[ `ip rule list | grep -c 0x1` == 0 ]]; then
+# ip rule add from all fwmark 0x1 lookup $VPNUSER
+# fi
+# ip route replace default via $GATEWAYIP table $VPNUSER
+# ip route append default via 127.0.0.1 dev lo table $VPNUSER
+# ip route flush cache
+ # '';
+ # down = "bash /etc/openvpn/update-resolv-conf";
+ # these are outsourced to a local file, I am not sure if it can be done with sops-nix
+ # authUserPass = {
+ # username = "TODO:secrets";
+ # password = "TODO:secrets";
+ # };
+ config = "config ${config.sops.templates.vpn.path}";
+ };
+ };
-
-
id: doublepuppet
-url:
-as_token: doublepuppet
-hs_token: notused
-sender_localpart: notused
-rate_limited: false
-namespaces:
- users:
- - regex: '@.*:matrix2\.swarsel\.win'
- exclusive: false
-
-
+ services.transmission = {
+ enable = true;
+ credentialsFile = config.sops.templates."transmission-rpc".path;
+ user = "vpn";
+ group = "lxc_shares";
+ settings = {
-
-Lastly, the machine that runs matrix needs to regularly update, as otherwise you will lose connectivity to the bridges.
-
+ alt-speed-down= 8000;
+ alt-speed-enabled= false;
+ alt-speed-time-begin= 0;
+ alt-speed-time-day= 127;
+ alt-speed-time-enabled= true;
+ alt-speed-time-end= 360;
+ alt-speed-up= 2000;
+ bind-address-ipv4= "0.0.0.0";
+ bind-address-ipv6= "::";
+ blocklist-enabled= false;
+ blocklist-url= "http://www.example.com/blocklist";
+ cache-size-mb= 4;
+ dht-enabled= false;
+ download-dir= "/media/Eternor/New";
+ download-limit= 100;
+ download-limit-enabled= 0;
+ download-queue-enabled= true;
+ download-queue-size= 5;
+ encryption= 2;
+ idle-seeding-limit= 30;
+ idle-seeding-limit-enabled= false;
+ incomplete-dir= "/var/lib/transmission-daemon/Downloads";
+ incomplete-dir-enabled= false;
+ lpd-enabled= false;
+ max-peers-global= 200;
+ message-level= 1;
+ peer-congestion-algorithm= "";
+ peer-id-ttl-hours= 6;
+ peer-limit-global= 100;
+ peer-limit-per-torrent= 40;
+ peer-port= 22371;
+ peer-port-random-high= 65535;
+ peer-port-random-low= 49152;
+ peer-port-random-on-start= false;
+ peer-socket-tos= "default";
+ pex-enabled= false;
+ port-forwarding-enabled= false;
+ preallocation= 1;
+ prefetch-enabled= true;
+ queue-stalled-enabled= true;
+ queue-stalled-minutes= 30;
+ ratio-limit= 2;
+ ratio-limit-enabled= false;
+ rename-partial-files= true;
+ rpc-authentication-required= true;
+ rpc-bind-address= "0.0.0.0";
+ rpc-enabled= true;
+ rpc-host-whitelist= "";
+ rpc-host-whitelist-enabled= true;
+ rpc-port= 9091;
+ rpc-url= "/transmission/";
+ rpc-whitelist= "127.0.0.1,192.168.3.2";
+ rpc-whitelist-enabled= true;
+ scrape-paused-torrents-enabled= true;
+ script-torrent-done-enabled= false;
+ seed-queue-enabled= false;
+ seed-queue-size= 10;
+ speed-limit-down= 6000;
+ speed-limit-down-enabled= true;
+ speed-limit-up= 500;
+ speed-limit-up-enabled= true;
+ start-added-torrents= true;
+ trash-original-torrent-files= false;
+ umask= 2;
+ upload-limit= 100;
+ upload-limit-enabled= 0;
+ upload-slots-per-torrent= 14;
+ utp-enabled= false;
+ };
+ };
-
-
-{ config, pkgs, modulesPath, unstable, sops, ... }: let
- matrixDomain = "swatrix.swarsel.win";
-in {
+ # services.nginx = {
+ # enable = true;
+ # virtualHosts = {
- imports = [
- ./hardware-configuration.nix
- # (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix") # no longer needed; mautrix-signal was added to nixpkgs
- ];
+ # "192.168.1.192" = {
+ # locations = {
+ # "/transmission" = {
+ # proxyPass = "http://127.0.0.1:9091";
+ # extraConfig = ''
+ # proxy_set_header Host $host;
+ # proxy_set_header X-Real-IP $remote_addr;
+ # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ # '';
+ # };
+ # };
+ # };
+ # };
+ # };
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- matrix-synapse
- lottieconverter
- ffmpeg
- ];
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
-
- nix.settings.experimental-features = ["nix-command" "flakes"];
-
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/root/.dotfiles/secrets/omatrix/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.dnstokenfull = {owner="acme";};
- sops.templates."certs.secret".content = ''
- CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
- '';
-
- documentation = {
- enable = false;
- };
+ }
- security.acme = {
- acceptTerms = true;
- preliminarySelfsigned = false;
- defaults.email = "mrswarsel@gmail.com";
- defaults.dnsProvider = "cloudflare";
- defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
- };
+
+
+
+
+
+
+
- [Manual steps needed] Matrix
+
+
+- After the initial setup, run the
+
+- /run/secrets-generated/matrixuserregister.sh
+
+
+
+command to register a new admin user.
+
+
+- All bridges will fail on first start, copy the registration files using:
+
+- cp var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse
+- chown matrix-synapse:matrix-synapse var/lib/matrix-synapse/telegram-registration.yaml
+
+
+
+Make sure to also do this for doublepuppet.yaml
+
+
+- Restart postgresql.service, matrix-synapse.service, mautrix-whatsapp.service, mautrix-telegram.service
+
+
+
+- NixOS
+
+
+
+{ config, pkgs, modulesPath, unstable, sops, ... }: let
+ matrixDomain = "matrix2.swarsel.win";
+in {
- services.nginx = {
- enable = true;
- recommendedProxySettings = true;
- recommendedTlsSettings = true;
- recommendedOptimisation = true;
- recommendedGzipSettings = true;
- virtualHosts = {
- "swatrix.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "~ ^(/_matrix|/_synapse/client)" = {
- proxyPass = "http://localhost:8008";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
- };
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
};
-
- boot.tmp.cleanOnBoot = true;
- zramSwap.enable = false;
- networking.hostName = "swatrix";
+ nix.settings.experimental-features = ["nix-command" "flakes"];
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.useDHCP = true;
networking.enableIPv6 = false;
- # networking.domain = "subnet03112148.vcn03112148.oraclevcn.com";
- networking.domain = "swarsel.win";
- networking.firewall.extraCommands = ''
- iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 8008 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 29317 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 29318 -j ACCEPT
- iptables -I INPUT -m state --state NEW -p tcp --dport 29328 -j ACCEPT
- '';
services.openssh = {
enable = true;
settings.PermitRootLogin = "yes";
+ listenAddresses = [{
+ port = 22;
+ addr = "0.0.0.0";
+ }];
};
users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../../../secrets/keys/authorized_keys
+ ../../../secrets/keys/authorized_keys
];
- system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
environment.shellAliases = {
- nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
};
- boot.loader.grub.device = "nodev";
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
+ # we import here a service that is not available yet on normal nixpkgs
+ # this module is hence not in the modules list, we add it ourselves
+ ];
+
+ networking.hostName = "matrix"; # Define your hostname.
+ networking.firewall.enable = false;
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ matrix-synapse
+ lottieconverter
+ ffmpeg
+ ];
+
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/.dotfiles/secrets/matrix/secrets.yaml";
+ sops.validateSopsFiles = false;
sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
sops.templates."matrix_user_register.sh".content = ''
register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
@@ -4459,7 +4523,6 @@ 3
services.mautrix-signal = {
enable = true;
- registerToSynapse = false; # this has the same effect as registering to app_service_config_file above
# environmentFile = config.sops.templates.mautrixwhatsapp.path;
settings = {
homeserver = {
@@ -4522,12 +4585,12 @@ 3
-- Paperless
-
+
- Sound
+
-- NixOS
-
+
- NixOS
+
{ config, pkgs, modulesPath, ... }:
@@ -4570,931 +4633,877 @@ 3
- users.groups.lxc_shares = {
- gid = 10000;
+ proxmoxLXC.privileged = true; # manage hostname myself
+
+ users.groups.lxc_pshares = {
+ gid = 110000;
members = [
- "paperless"
+ "navidrome"
+ "mpd"
"root"
];
};
+ users.groups.navidrome = {
+ gid = 61593;
+ };
+
+ users.groups.mpd = {};
+
+ users.users.navidrome = {
+ isSystemUser = true;
+ uid = 61593;
+ group = "navidrome";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ users.users.mpd = {
+ isSystemUser = true;
+ group = "mpd";
+ extraGroups = [ "audio" "utmp" ];
+ };
+
+ sound = {
+ enable = true;
+ };
+
+ hardware.enableAllFirmware = true;
+ networking.hostName = "sound"; # Define your hostname.
+ networking.firewall.enable = false;
environment.systemPackages = with pkgs; [
git
gnupg
ssh-to-age
+ pciutils
+ alsa-utils
+ mpv
];
- networking.hostName = "paperless"; # Define your hostname.
- networking.firewall.enable = false;
-
sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/root/.dotfiles/secrets/paperless/secrets.yaml";
+ sops.defaultSopsFile = "/.dotfiles/secrets/sound/secrets.yaml";
sops.validateSopsFiles = false;
- sops.secrets.admin = { owner = "paperless";};
+ sops.secrets.mpdpass = { owner = "mpd";};
- services.paperless = {
+ services.navidrome = {
enable = true;
- mediaDir = "/media";
- user = "paperless";
- port = 28981;
- passwordFile = config.sops.secrets.admin.path;
- address = "0.0.0.0";
- extraConfig = {
- PAPERLESS_OCR_LANGUAGE = "deu+eng";
- PAPERLESS_URL = "scan.swarsel.win";
- PAPERLESS_OCR_USER_ARGS = builtins.toJSON {
- optimize = 1;
- pdfa_image_compression = "lossless";
- };
+ settings = {
+ Address = "0.0.0.0";
+ Port = 4040;
+ MusicFolder = "/media";
+ EnableSharing = true;
+ EnableTranscodingConfig = true;
+ Scanner.GroupAlbumReleases = true;
+ ScanSchedule = "@every 1d";
+ # Insert these values locally as sops-nix does not work for them
+ LastFM.ApiKey = TEMPLATE;
+ LastFM.Secret = TEMPLATE;
+ Spotify.ID = TEMPLATE;
+ Spotify.Secret = TEMPLATE;
+ UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png";
+ UIWelcomeMessage = "~SwarselSound~";
};
};
-
+ services.mpd = {
+ enable = true;
+ musicDirectory = "/media";
+ user = "mpd";
+ group = "mpd";
+ network = {
+ port = 3254;
+ listenAddress = "any";
+ };
+ credentials = [
+ {
+ passwordFile = config.sops.secrets.mpdpass.path;
+ permissions = [
+ "read"
+ "add"
+ "control"
+ "admin"
+ ];
+ }
+ ];
+ };
}
-
-
- Sandbox (Lenovo Y510P)
-
-
-My laptop, sadly soon to be replaced by a new one, since most basic functions are stopping to work lately.
-
+
- Spotifyd
+
-- NixOS
-
+
- NixOS
+
- { config, pkgs, modulesPath, unstable, sops, ... }: let
- matrixDomain = "swatrix.swarsel.win";
- in {
+{ config, pkgs, modulesPath, ... }:
- imports = [
- ./hardware-configuration.nix
- # we import here a service that is not available yet on normal nixpkgs
- # this module is hence not in the modules list, we add it ourselves
- (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix")
- ];
+{
- boot.loader.grub = {
- enable = true;
- device = "/dev/sda";
- useOSProber = true;
- };
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
+ ];
- users.users.swarsel = {
- isNormalUser = true;
- description = "Leon S";
- extraGroups = [ "networkmanager" "wheel" "lp"];
- packages = with pkgs; [];
- };
- # actual config starts here
- fileSystems."/mnt/Eternor" = {
- device = "//192.168.1.3/Eternor";
- fsType = "cifs";
- options = let
- # this line prevents hanging on network split
- automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s";
- in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=1000,gid=100"];
- };
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
+ nix.settings.experimental-features = ["nix-command" "flakes"];
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ listenAddresses = [{
+ port = 22;
+ addr = "0.0.0.0";
+ }];
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
- environment.systemPackages = with pkgs; [
- git
- gnupg
- ssh-to-age
- lego
- nginx
- calibre
- openvpn
- jq
- iptables
- busybox
- wireguard-tools
- matrix-synapse
- lottieconverter
- ffmpeg
- pciutils
- alsa-utils
- mpv
- zfs
- ];
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
- services.xserver = {
- layout = "us";
- xkbVariant = "altgr-intl";
- };
+ environment.shellAliases = {
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
- nix.settings.experimental-features = ["nix-command" "flakes"];
- services.openssh = {
- enable = true;
- settings.PermitRootLogin = "yes";
- listenAddresses = [{
- port = 22;
- addr = "0.0.0.0";
- }];
- };
- users.users.root.openssh.authorizedKeys.keyFiles = [
- ../../secrets/keys/authorized_keys
- ];
- system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ proxmoxLXC.privileged = true; # manage hostname myself
- environment.shellAliases = {
- nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
- };
+ users.groups.spotifyd = {
+ gid = 65136;
+ };
-boot.supportedFilesystems = [ "zfs" ];
-boot.zfs.forceImportRoot = false;
-networking.hostId = "8a8ad84a";
+ users.users.spotifyd = {
+ isSystemUser = true;
+ uid = 65136;
+ group = "spotifyd";
+ extraGroups = [ "audio" "utmp" ];
+ };
- networking.hostName = "sandbox"; # Define your hostname.
- networking.enableIPv6 = true;
- networking.firewall.enable = false;
+ sound = {
+ enable = true;
+ };
- documentation = {
- enable = false;
- };
+ hardware.enableAllFirmware = true;
+ networking.hostName = "spotifyd"; # Define your hostname.
+ networking.firewall.enable = false;
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ ];
- sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
- sops.defaultSopsFile = "/root/.dotfiles/secrets/sandbox/secrets.yaml";
- sops.validateSopsFiles = false;
- sops.secrets.dnstokenfull = {owner="acme";};
- sops.templates."certs.secret".content = ''
- CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
- '';
+ # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ # sops.defaultSopsFile = "/.dotfiles/secrets/spotifyd/secrets.yaml";
+ # sops.validateSopsFiles = false;
- security.acme = {
- acceptTerms = true;
- preliminarySelfsigned = false;
- defaults.email = "mrswarsel@gmail.com";
- defaults.dnsProvider = "cloudflare";
- defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
+ services.spotifyd = {
+ enable = true;
+ settings = {
+ global = {
+ dbus_type = "session";
+ use_mpris = false;
+ device = "default:CARD=PCH";
+ device_name = "SwarselSpot";
+ mixer = "alsa";
+ zeroconf_port = 1025;
+ };
};
+ };
- services.nginx = {
- enable = true;
- recommendedProxySettings = true;
- recommendedTlsSettings = true;
- recommendedOptimisation = true;
- recommendedGzipSettings = true;
- virtualHosts = {
+}
- "stash.swarsel.win" = {
+
+
+
+
+
+
+
- Sync
+
+
+
+- NixOS
+
+
+
+{ config, pkgs, modulesPath, ... }:
+
+{
+ imports = [
+ ./hardware-configuration.nix
+ ];
+
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ ];
+
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
+
+ nix.settings.experimental-features = ["nix-command" "flakes"];
+
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/root/.dotfiles/secrets/sync/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.swarsel = { owner = "root";};
+ sops.secrets.dnstokenfull = {owner="acme";};
+ sops.templates."certs.secret".content = ''
+ CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
+ '';
+
+ security.acme = {
+ acceptTerms = true;
+ preliminarySelfsigned = false;
+ defaults.email = "mrswarsel@gmail.com";
+ defaults.dnsProvider = "cloudflare";
+ defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
+ };
+
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ virtualHosts = {
+
+ "synki.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "/" = {
+ proxyPass = "http://localhost:27701";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
+ };
+ };
+ };
+
+ "sync.swarsel.win" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
- proxyPass = "https://192.168.1.5";
+ proxyPass = "http://localhost:8384/";
extraConfig = ''
- client_max_body_size 0;
+ client_max_body_size 0;
'';
};
- # "/push/" = {
- # proxyPass = "http://192.168.2.5:7867";
- # };
- "/.well-known/carddav" = {
- return = "301 $scheme://$host/remote.php/dav";
- };
- "/.well-known/caldav" = {
- return = "301 $scheme://$host/remote.php/dav";
- };
};
};
- "swatrix.swarsel.win" = {
+ "swagit.swarsel.win" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
locations = {
- "~ ^(/_matrix|/_synapse/client)" = {
- proxyPass = "http://127.0.0.1:8008";
+ "/" = {
+ proxyPass = "http://localhost:3000";
extraConfig = ''
- client_max_body_size 0;
- '';
+ client_max_body_size 0;
+ '';
};
};
};
+ };
+ };
+ boot.tmp.cleanOnBoot = true;
+ zramSwap.enable = false;
+ networking.hostName = "sync";
+ networking.enableIPv6 = false;
+ networking.domain = "subnet03112148.vcn03112148.oraclevcn.com";
+ networking.firewall.extraCommands = ''
+ iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 27701 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 8384 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 3000 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 22000 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p udp --dport 22000 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p udp --dport 21027 -j ACCEPT
+ '';
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../../secrets/keys/authorized_keys
+ ];
- "sound.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://127.0.0.1:4040";
- proxyWebsockets = true;
- extraConfig = ''
- proxy_redirect http:// https://;
- proxy_read_timeout 600s;
- proxy_send_timeout 600s;
- proxy_buffering off;
- proxy_request_buffering off;
- client_max_body_size 0;
- '';
- };
- };
- };
+ system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change
- "scan.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://127.0.0.1:28981";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ environment.shellAliases = {
+ nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
- "screen.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://127.0.0.1:8096";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ boot.loader.grub.device = "nodev";
- "scroll.swarsel.win" = {
- enableACME = true;
- forceSSL = true;
- acmeRoot = null;
- locations = {
- "/" = {
- proxyPass = "http://127.0.0.1:8080";
- extraConfig = ''
- client_max_body_size 0;
- '';
- };
- };
- };
+ services.anki-sync-server = {
+ enable = true;
+ port = 27701;
+ address = "0.0.0.0";
+ openFirewall = true;
+ users = [
+ {
+ username = "Swarsel";
+ passwordFile = config.sops.secrets.swarsel.path;
+ }
+ ];
+ };
+ services.syncthing = {
+ enable = true;
+ guiAddress = "0.0.0.0:8384";
+ openDefaultPorts = true;
+ };
- };
+ services.forgejo = {
+ enable = true;
+ settings = {
+ DEFAULT = {
+ APP_NAME = "~SwaGit~";
+ };
+ server = {
+ PROTOCOL = "http";
+ HTTP_PORT = 3000;
+ HTTP_ADDR = "0.0.0.0";
+ DOMAIN = "swagit.swarsel.win";
+ ROOT_URL = "https://swagit.swarsel.win";
+ };
+ service = {
+ DISABLE_REGISTRATION = true;
+ SHOW_REGISTRATION_BUTTON = false;
};
+ };
+ };
+}
- sops.secrets.kavita = { owner = "kavita";};
+
+
+
+
+
+
+
- [Manual steps required] Swatrix
+
+
+
+- NixOS
+
+
+The files mentioned by
+
- services.kavita = {
- enable = true;
- user = "kavita";
- port = 8080;
- tokenKeyFile = config.sops.secrets.kavita.path;
- };
+
+
+settings.app_service_config_files = [
+ "/var/lib/matrix-synapse/telegram-registration.yaml"
+ "/var/lib/matrix-synapse/whatsapp-registration.yaml"
+ "/var/lib/matrix-synapse/signal-registration.yaml"
+ "/var/lib/matrix-synapse/doublepuppet.yaml"
+ ]
- users.users.jellyfin = {
- extraGroups = [ "video" "render" ];
- };
+
+
- # nixpkgs.config.packageOverrides = pkgs: {
- # vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
- # };
+
+need to be moved to the corresponding location. The below files are created as soon as the appservice is run once. This means that matrix will crash on the first startup; afterwards run these commands and restart the service.
+
- hardware.graphics = {
- enable = true;
- extraPackages = with pkgs; [
- intel-media-driver # LIBVA_DRIVER_NAME=iHD
- vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
- vaapiVdpau
- libvdpau-va-gl
- ];
- };
+
+
+cp /var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse/
+chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/telegram-registration.yaml
+cp /var/lib/mautrix-signal/signal-registration.yaml /var/lib/matrix-synapse/
+chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/signal-registration.yaml
+cp /var/lib/mautrix-whatsapp/whatsapp-registration.yaml /var/lib/matrix-synapse/
+chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/whatsapp-registration.yaml
- services.jellyfin = {
- enable = true;
- user = "jellyfin";
- # openFirewall = true; # this works only for the default ports
- };
+
+
- users.groups.vpn = {};
+
+as for the contents of doublepuppet.yaml:
+
- users.users.vpn = {
- isNormalUser = true;
- group = "vpn";
- home = "/home/vpn";
- };
+
+
id: doublepuppet
+url:
+as_token: doublepuppet
+hs_token: notused
+sender_localpart: notused
+rate_limited: false
+namespaces:
+ users:
+ - regex: '@.*:matrix2\.swarsel\.win'
+ exclusive: false
+
+
- boot.kernelModules = [ "tun" ];
+
+Lastly, the machine that runs matrix needs to regularly update, as otherwise you will lose connectivity to the bridges.
+
- services.radarr = {
- enable = true;
- };
+
+
+{ config, pkgs, modulesPath, unstable, sops, ... }: let
+ matrixDomain = "swatrix.swarsel.win";
+in {
- services.readarr = {
- enable = true;
- };
- services.sonarr = {
- enable = true;
- };
- services.lidarr = {
- enable = true;
- };
- services.prowlarr = {
- enable = true;
- };
+ imports = [
+ ./hardware-configuration.nix
+ # (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix") # no longer needed; mautrix-signal was added to nixpkgs
+ ];
- networking.firewall.extraCommands = ''
- sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP
- '';
- networking.iproute2 = {
- enable = true;
- rttablesExtraConfig = ''
- 200 vpn
- '';
- };
- boot.kernel.sysctl = {
- "net.ipv4.conf.all.rp_filter" = 2;
- "net.ipv4.conf.default.rp_filter" = 2;
- "net.ipv4.conf.enp7s0.rp_filter" = 2;
- };
- environment.etc = {
- "openvpn/iptables.sh" =
- { source = ../../scripts/server1/iptables.sh;
- mode = "0755";
- };
- "openvpn/update-resolv-conf" =
- { source = ../../scripts/server1/update-resolv-conf;
- mode = "0755";
- };
- "openvpn/routing.sh" =
- { source = ../../scripts/server1/routing.sh;
- mode = "0755";
- };
- "openvpn/ca.rsa.2048.crt" =
- { source = ../../secrets/certs/ca.rsa.2048.crt;
- mode = "0644";
- };
- "openvpn/crl.rsa.2048.pem" =
- { source = ../../secrets/certs/crl.rsa.2048.pem;
- mode = "0644";
- };
- };
-
- sops.secrets.vpnuser = {};
- sops.secrets.rpcuser = {owner="vpn";};
- sops.secrets.vpnpass = {};
- sops.secrets.rpcpass = {owner="vpn";};
- sops.secrets.vpnprot = {};
- sops.secrets.vpnloc = {};
- # sops.secrets.crlpem = {};
- # sops.secrets.capem = {};
- sops.templates."transmission-rpc".owner = "vpn";
- sops.templates."transmission-rpc".content = builtins.toJSON {
- rpc-username = config.sops.placeholder.rpcuser;
- rpc-password = config.sops.placeholder.rpcpass;
- };
-
- sops.templates.pia.content = ''
- ${config.sops.placeholder.vpnuser}
- ${config.sops.placeholder.vpnpass}
- '';
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ matrix-synapse
+ lottieconverter
+ ffmpeg
+ ];
- sops.templates.vpn.content = ''
- client
- dev tun
- proto ${config.sops.placeholder.vpnprot}
- remote ${config.sops.placeholder.vpnloc}
- resolv-retry infinite
- nobind
- persist-key
- persist-tun
- cipher aes-128-cbc
- auth sha1
- tls-client
- remote-cert-tls server
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
- auth-user-pass ${config.sops.templates.pia.path}
- compress
- verb 1
- reneg-sec 0
+ nix.settings.experimental-features = ["nix-command" "flakes"];
- crl-verify /etc/openvpn/crl.rsa.2048.pem
- ca /etc/openvpn/ca.rsa.2048.crt
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/root/.dotfiles/secrets/omatrix/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.dnstokenfull = {owner="acme";};
+ sops.templates."certs.secret".content = ''
+ CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull}
+ '';
- disable-occ
- '';
+ documentation = {
+ enable = false;
+ };
- services.openvpn.servers = {
- pia = {
- autoStart = true;
- updateResolvConf = false;
- config = "config ${config.sops.templates.vpn.path}";
- };
- };
+ security.acme = {
+ acceptTerms = true;
+ preliminarySelfsigned = false;
+ defaults.email = "mrswarsel@gmail.com";
+ defaults.dnsProvider = "cloudflare";
+ defaults.environmentFile = "${config.sops.templates."certs.secret".path}";
+ };
- services.transmission = {
- enable = true;
- credentialsFile = config.sops.templates."transmission-rpc".path;
- user = "vpn";
- settings = {
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ virtualHosts = {
- alt-speed-down= 8000;
- alt-speed-enabled= false;
- alt-speed-time-begin= 0;
- alt-speed-time-day= 127;
- alt-speed-time-enabled= true;
- alt-speed-time-end= 360;
- alt-speed-up= 2000;
- bind-address-ipv4= "0.0.0.0";
- bind-address-ipv6= "::";
- blocklist-enabled= false;
- blocklist-url= "http://www.example.com/blocklist";
- cache-size-mb= 256;
- dht-enabled= false;
- download-dir= "/test";
- download-limit= 100;
- download-limit-enabled= 0;
- download-queue-enabled= true;
- download-queue-size= 5;
- encryption= 2;
- idle-seeding-limit= 30;
- idle-seeding-limit-enabled= false;
- incomplete-dir= "/var/lib/transmission-daemon/Downloads";
- incomplete-dir-enabled= false;
- lpd-enabled= false;
- max-peers-global= 200;
- message-level= 1;
- peer-congestion-algorithm= "";
- peer-id-ttl-hours= 6;
- peer-limit-global= 100;
- peer-limit-per-torrent= 40;
- peer-port= 22371;
- peer-port-random-high= 65535;
- peer-port-random-low= 49152;
- peer-port-random-on-start= false;
- peer-socket-tos= "default";
- pex-enabled= false;
- port-forwarding-enabled= false;
- preallocation= 1;
- prefetch-enabled= true;
- queue-stalled-enabled= true;
- queue-stalled-minutes= 30;
- ratio-limit= 2;
- ratio-limit-enabled= false;
- rename-partial-files= true;
- rpc-authentication-required= true;
- rpc-bind-address= "0.0.0.0";
- rpc-enabled= true;
- rpc-host-whitelist= "";
- rpc-host-whitelist-enabled= true;
- rpc-port= 9091;
- rpc-url= "/transmission/";
- rpc-whitelist= "127.0.0.1,192.168.3.2";
- rpc-whitelist-enabled= true;
- scrape-paused-torrents-enabled= true;
- script-torrent-done-enabled= false;
- seed-queue-enabled= false;
- seed-queue-size= 10;
- speed-limit-down= 6000;
- speed-limit-down-enabled= true;
- speed-limit-up= 500;
- speed-limit-up-enabled= true;
- start-added-torrents= true;
- trash-original-torrent-files= false;
- umask= 2;
- upload-limit= 100;
- upload-limit-enabled= 0;
- upload-slots-per-torrent= 14;
- utp-enabled= false;
- };
+ "swatrix.swarsel.win" = {
+ enableACME = true;
+ forceSSL = true;
+ acmeRoot = null;
+ locations = {
+ "~ ^(/_matrix|/_synapse/client)" = {
+ proxyPass = "http://localhost:8008";
+ extraConfig = ''
+ client_max_body_size 0;
+ '';
};
+ };
+ };
+ };
+ };
- # services.nginx = {
- # enable = true;
- # virtualHosts = {
-
- # "192.168.1.192" = {
- # locations = {
- # "/transmission" = {
- # proxyPass = "http://127.0.0.1:9091";
- # extraConfig = ''
- # proxy_set_header Host $host;
- # proxy_set_header X-Real-IP $remote_addr;
- # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- # '';
- # };
- # };
- # };
- # };
- # };
-
-
- # sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
- # sops.templates."matrix_user_register.sh".content = ''
- # register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
- # '';
- # sops.templates.matrixshared.owner = "matrix-synapse";
- # sops.templates.matrixshared.content = ''
- # registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
- # '';
- # sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
- # sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
- # sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
- # sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
- # sops.templates.mautrixtelegram.owner = "matrix-synapse";
- # sops.templates.mautrixtelegram.content = ''
- # MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
- # MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
- # MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
- # MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
- # '';
+ boot.tmp.cleanOnBoot = true;
+ zramSwap.enable = false;
+ networking.hostName = "swatrix";
+ networking.enableIPv6 = false;
+ # networking.domain = "subnet03112148.vcn03112148.oraclevcn.com";
+ networking.domain = "swarsel.win";
+ networking.firewall.extraCommands = ''
+ iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 8008 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 29317 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 29318 -j ACCEPT
+ iptables -I INPUT -m state --state NEW -p tcp --dport 29328 -j ACCEPT
+ '';
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../../secrets/keys/authorized_keys
+ ];
+ system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change
+ environment.shellAliases = {
+ nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
+ boot.loader.grub.device = "nodev";
- # ----------------
- # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
- # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
- # sops.templates.mautrixwhatsapp.content = ''
- # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
- # '';
+ sops.secrets.matrixsharedsecret = {owner="matrix-synapse";};
+ sops.templates."matrix_user_register.sh".content = ''
+ register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008
+ '';
+ sops.templates.matrixshared.owner = "matrix-synapse";
+ sops.templates.matrixshared.content = ''
+ registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret}
+ '';
+ sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";};
+ sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";};
+ sops.templates.mautrixtelegram.owner = "matrix-synapse";
+ sops.templates.mautrixtelegram.content = ''
+ MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as}
+ MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs}
+ MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id}
+ MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash}
+ '';
+ # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";};
+ # sops.templates.mautrixwhatsapp.owner = "matrix-synapse";
+ # sops.templates.mautrixwhatsapp.content = ''
+ # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared}
+ # '';
- services.postgresql.enable = true;
- services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
- CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
- CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
- CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
- CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
- CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
- TEMPLATE template0
- LC_COLLATE = "C"
- LC_CTYPE = "C";
- '';
+ services.postgresql.enable = true;
+ services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
+ CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
+ CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram';
+ CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp';
+ CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal';
+ CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ '';
- services.matrix-synapse = {
- settings.app_service_config_files = [
- "/var/lib/matrix-synapse/telegram-registration.yaml"
- "/var/lib/matrix-synapse/whatsapp-registration.yaml"
- "/var/lib/matrix-synapse/signal-registration.yaml"
- "/var/lib/matrix-synapse/doublepuppet.yaml"
- ];
- enable = false;
- settings.server_name = matrixDomain;
- settings.public_baseurl = "https://${matrixDomain}";
- extraConfigFiles = [
- config.sops.templates.matrixshared.path
- ];
- settings.listeners = [
- { port = 8008;
- bind_addresses = [ "0.0.0.0" ];
- type = "http";
- tls = false;
- x_forwarded = true;
- resources = [
- {
- names = [ "client" "federation" ];
- compress = true;
- }
- ];
- }
- ];
- };
+ services.matrix-synapse = {
+ settings.app_service_config_files = [
+ "/var/lib/matrix-synapse/telegram-registration.yaml"
+ "/var/lib/matrix-synapse/whatsapp-registration.yaml"
+ "/var/lib/matrix-synapse/signal-registration.yaml"
+ "/var/lib/matrix-synapse/doublepuppet.yaml"
+ ];
+ enable = true;
+ settings.server_name = matrixDomain;
+ settings.public_baseurl = "https://${matrixDomain}";
+ extraConfigFiles = [
+ config.sops.templates.matrixshared.path
+ ];
+ settings.listeners = [
+ { port = 8008;
+ bind_addresses = [ "0.0.0.0" ];
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [
+ {
+ names = [ "client" "federation" ];
+ compress = true;
+ }
+ ];
+ }
+ ];
+ };
- services.mautrix-telegram = {
- enable = false;
- environmentFile = config.sops.templates.mautrixtelegram.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29317";
- hostname = "0.0.0.0";
- port = "29317";
- provisioning.enabled = true;
- id = "telegram";
- # ephemeral_events = true; # not needed due to double puppeting
- public = {
- enabled = false;
- };
- database = "postgresql:///mautrix-telegram?host=/run/postgresql";
- };
- bridge = {
- # login_shared_secret_map = {
- # matrixDomain = "as_token:doublepuppet";
- # };
- relaybot.authless_portals = true;
- allow_avatar_remove = true;
- allow_contact_info = true;
- sync_channel_members = true;
- startup_sync = true;
- sync_create_limit = 0;
- sync_direct_chats = true;
- telegram_link_preview = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
- # Animated stickers conversion requires additional packages in the
- # service's path.
- # If this isn't a fresh installation, clearing the bridge's uploaded
- # file cache might be necessary (make a database backup first!):
- # delete from telegram_file where \
- # mime_type in ('application/gzip', 'application/octet-stream')
- animated_sticker = {
- target = "gif";
- args = {
- width = 256;
- height = 256;
- fps = 30; # only for webm
- background = "020202"; # only for gif, transparency not supported
- };
- };
- };
+ services.mautrix-telegram = {
+ enable = true;
+ environmentFile = config.sops.templates.mautrixtelegram.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
};
- };
- # systemd.services.mautrix-telegram.path = with pkgs; [
- # lottieconverter # for animated stickers conversion, unfree package
- # ffmpeg # if converting animated stickers to webm (very slow!)
- # ];
-
- services.mautrix-whatsapp = {
- enable = false;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
- };
- appservice = {
- address= "http://localhost:29318";
- hostname = "0.0.0.0";
- port = 29318;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
- };
+ appservice = {
+ address= "http://localhost:29317";
+ hostname = "0.0.0.0";
+ port = "29317";
+ provisioning.enabled = true;
+ id = "telegram";
+ # ephemeral_events = true; # not needed due to double puppeting
+ public = {
+ enabled = false;
};
- bridge = {
- displayname_template = "{{or .FullName .PushName .JID}} (WA)";
- history_sync = {
- backfill = true;
- max_initial_conversations = -1;
- message_count = -1;
- request_full_sync = true;
- full_sync_config = {
- days_limit = 900;
- size_mb_limit = 5000;
- storage_quota_mb = 5000;
- };
- };
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- sync_manual_marked_unread = true;
- send_presence_on_typing = true;
- parallel_member_sync = true;
- url_previews = true;
- caption_in_message = true;
- extev_polls = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
+ database = "postgresql:///mautrix-telegram?host=/run/postgresql";
+ };
+ bridge = {
+ # login_shared_secret_map = {
+ # matrixDomain = "as_token:doublepuppet";
+ # };
+ relaybot.authless_portals = true;
+ allow_avatar_remove = true;
+ allow_contact_info = true;
+ sync_channel_members = true;
+ startup_sync = true;
+ sync_create_limit = 0;
+ sync_direct_chats = true;
+ telegram_link_preview = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
+ # Animated stickers conversion requires additional packages in the
+ # service's path.
+ # If this isn't a fresh installation, clearing the bridge's uploaded
+ # file cache might be necessary (make a database backup first!):
+ # delete from telegram_file where \
+ # mime_type in ('application/gzip', 'application/octet-stream')
+ animated_sticker = {
+ target = "gif";
+ args = {
+ width = 256;
+ height = 256;
+ fps = 30; # only for webm
+ background = "020202"; # only for gif, transparency not supported
};
};
};
};
+ };
+ systemd.services.mautrix-telegram.path = with pkgs; [
+ lottieconverter # for animated stickers conversion, unfree package
+ ffmpeg # if converting animated stickers to webm (very slow!)
+ ];
- services.mautrix-signal = {
- enable = false;
- # environmentFile = config.sops.templates.mautrixwhatsapp.path;
- settings = {
- homeserver = {
- address = "http://localhost:8008";
- domain = matrixDomain;
+ services.mautrix-whatsapp = {
+ enable = true;
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
+ };
+ appservice = {
+ address= "http://localhost:29318";
+ hostname = "0.0.0.0";
+ port = 29318;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql";
};
- appservice = {
-
- address= "http://localhost:29328";
- hostname = "0.0.0.0";
- port = 29328;
- database = {
- type = "postgres";
- uri = "postgresql:///mautrix-signal?host=/run/postgresql";
+ };
+ bridge = {
+ displayname_template = "{{or .FullName .PushName .JID}} (WA)";
+ history_sync = {
+ backfill = true;
+ max_initial_conversations = -1;
+ message_count = -1;
+ request_full_sync = true;
+ full_sync_config = {
+ days_limit = 900;
+ size_mb_limit = 5000;
+ storage_quota_mb = 5000;
};
};
- bridge = {
- displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
- login_shared_secret_map = {
- matrixDomain = "as_token:doublepuppet";
- };
- caption_in_message = true;
- permissions = {
- "*" = "relaybot";
- "@swarsel:${matrixDomain}" = "admin";
- };
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ sync_manual_marked_unread = true;
+ send_presence_on_typing = true;
+ parallel_member_sync = true;
+ url_previews = true;
+ caption_in_message = true;
+ extev_polls = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
};
};
};
+ };
- # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
- # messages out after a while.
-
- systemd.timers."restart-bridges" = {
- wantedBy = [ "timers.target" ];
- timerConfig = {
- OnBootSec = "1d";
- OnUnitActiveSec = "1d";
- Unit = "restart-bridges.service";
- };
- };
-
- systemd.services."restart-bridges" = {
- script = ''
- systemctl restart mautrix-whatsapp.service
- systemctl restart mautrix-signal.service
- systemctl restart mautrix-telegram.service
- '';
- serviceConfig = {
- Type = "oneshot";
- User = "root";
+ services.mautrix-signal = {
+ enable = true;
+ registerToSynapse = false; # this has the same effect as registering to app_service_config_file above
+ # environmentFile = config.sops.templates.mautrixwhatsapp.path;
+ settings = {
+ homeserver = {
+ address = "http://localhost:8008";
+ domain = matrixDomain;
};
- };
-
-
- users.groups.navidrome = {
- gid = 61593;
- };
-
- users.groups.mpd = {};
-
- users.users.navidrome = {
- isSystemUser = true;
- uid = 61593;
- group = "navidrome";
- extraGroups = [ "audio" "utmp" ];
- };
-
- users.users.mpd = {
- isSystemUser = true;
- group = "mpd";
- extraGroups = [ "audio" "utmp" ];
- };
-
- sound = {
- enable = true;
- };
-
- hardware.enableAllFirmware = true;
-
- sops.secrets.mpdpass = { owner = "mpd";};
+ appservice = {
- services.navidrome = {
- enable = true;
- settings = {
- Address = "0.0.0.0";
- Port = 4040;
- MusicFolder = "/mnt/";
- EnableSharing = true;
- EnableTranscodingConfig = true;
- Scanner.GroupAlbumReleases = true;
- ScanSchedule = "@every 24h";
- # Insert these values locally as sops-nix does not work for them
- # LastFM.ApiKey = TEMPLATE;
- # LastFM.Secret = TEMPLATE;
- # Spotify.ID = TEMPLATE;
- # Spotify.Secret = TEMPLATE;
- UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png";
- UIWelcomeMessage = "~SwarselSound~";
+ address= "http://localhost:29328";
+ hostname = "0.0.0.0";
+ port = 29328;
+ database = {
+ type = "postgres";
+ uri = "postgresql:///mautrix-signal?host=/run/postgresql";
+ };
};
- };
- services.mpd = {
- enable = true;
- musicDirectory = "/mnt/Eternor/Musik";
- user = "mpd";
- group = "mpd";
- network = {
- port = 3254;
- listenAddress = "any";
+ bridge = {
+ displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)";
+ login_shared_secret_map = {
+ matrixDomain = "as_token:doublepuppet";
+ };
+ caption_in_message = true;
+ permissions = {
+ "*" = "relaybot";
+ "@swarsel:${matrixDomain}" = "admin";
+ };
};
- credentials = [
- {
- passwordFile = config.sops.secrets.mpdpass.path;
- permissions = [
- "read"
- "add"
- "control"
- "admin"
- ];
- }
- ];
};
+ };
+ # restart the bridges daily. this is done for the signal bridge mainly which stops carrying
+ # messages out after a while.
- users.groups.spotifyd = {
- gid = 65136;
+ systemd.timers."restart-bridges" = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnBootSec = "1d";
+ OnUnitActiveSec = "1d";
+ Unit = "restart-bridges.service";
};
+ };
- users.users.spotifyd = {
- isSystemUser = true;
- uid = 65136;
- group = "spotifyd";
- extraGroups = [ "audio" "utmp" ];
+ systemd.services."restart-bridges" = {
+ script = ''
+ systemctl restart mautrix-whatsapp.service
+ systemctl restart mautrix-signal.service
+ systemctl restart mautrix-telegram.service
+ '';
+ serviceConfig = {
+ Type = "oneshot";
+ User = "root";
};
+ };
- services.spotifyd = {
- enable = true;
- settings = {
- global = {
- dbus_type = "session";
- use_mpris = false;
- device = "default:CARD=PCH";
- device_name = "SwarselSpot";
- mixer = "alsa";
- zeroconf_port = 1025;
- };
- };
- };
+}
- # Network shares
- # add a user with sudo smbpasswd -a <user>
- services.samba = {
- package = pkgs.samba4Full;
- extraConfig = ''
- workgroup = WORKGROUP
- server role = standalone server
- dns proxy = no
+
+
+
+
+
+
+
- Paperless
+
+
+
+- NixOS
+
+
+
+{ config, pkgs, modulesPath, ... }:
- pam password change = yes
- map to guest = bad user
- create mask = 0664
- force create mode = 0664
- directory mask = 0775
- force directory mode = 0775
- follow symlinks = yes
- '';
+{
- # ^^ `samba4Full` is compiled with avahi, ldap, AD etc support compared to the default package, `samba`
- # Required for samba to register mDNS records for auto discovery
- # See https://github.com/NixOS/nixpkgs/blob/592047fc9e4f7b74a4dc85d1b9f5243dfe4899e3/pkgs/top-level/all-packages.nix#L27268
- enable = true;
- # openFirewall = true;
- shares.test = {
- browseable = "yes";
- "read only" = "no";
- "guest ok" = "no";
- path = "/test2";
- writable = "true";
- comment = "Eternor";
- "valid users" = "@smbtest2";
- };
- };
+ imports = [
+ (modulesPath + "/virtualisation/proxmox-lxc.nix")
+ ./hardware-configuration.nix
+ ];
- services.avahi = {
- publish.enable = true;
- publish.userServices = true;
- # ^^ Needed to allow samba to automatically register mDNS records without the need for an `extraServiceFile`
- nssmdns = true;
- # ^^ Not one hundred percent sure if this is needed- if it aint broke, don't fix it
- enable = true;
- };
- services.samba-wsdd = {
- # This enables autodiscovery on windows since SMB1 (and thus netbios) support was discontinued
- enable = true;
- };
+ services.xserver = {
+ layout = "us";
+ xkbVariant = "altgr-intl";
+ };
+ nix.settings.experimental-features = ["nix-command" "flakes"];
+ proxmoxLXC.manageNetwork = true; # manage network myself
+ proxmoxLXC.manageHostName = false; # manage hostname myself
+ networking.useDHCP = true;
+ networking.enableIPv6 = false;
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "yes";
+ listenAddresses = [{
+ port = 22;
+ addr = "0.0.0.0";
+ }];
+ };
+ users.users.root.openssh.authorizedKeys.keyFiles = [
+ ../../../secrets/keys/authorized_keys
+ ];
+ system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change
+ environment.shellAliases = {
+ nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;";
+ };
+ users.groups.lxc_shares = {
+ gid = 10000;
+ members = [
+ "paperless"
+ "root"
+ ];
+ };
+ environment.systemPackages = with pkgs; [
+ git
+ gnupg
+ ssh-to-age
+ ];
+ networking.hostName = "paperless"; # Define your hostname.
+ networking.firewall.enable = false;
+ sops.age.sshKeyPaths = [ "/etc/ssh/sops" ];
+ sops.defaultSopsFile = "/root/.dotfiles/secrets/paperless/secrets.yaml";
+ sops.validateSopsFiles = false;
+ sops.secrets.admin = { owner = "paperless";};
+ services.paperless = {
+ enable = true;
+ mediaDir = "/media";
+ user = "paperless";
+ port = 28981;
+ passwordFile = config.sops.secrets.admin.path;
+ address = "0.0.0.0";
+ extraConfig = {
+ PAPERLESS_OCR_LANGUAGE = "deu+eng";
+ PAPERLESS_URL = "scan.swarsel.win";
+ PAPERLESS_OCR_USER_ARGS = builtins.toJSON {
+ optimize = 1;
+ pdfa_image_compression = "lossless";
+ };
+ };
+ };
- }
+}
@@ -5565,8 +5574,8 @@
3
-- Make users non-mutable
-
+
- Make users non-mutable
+
This ensures that all user-configuration happens here in the config file.
@@ -5647,8 +5656,8 @@
3
-- Enable automatic garbage collection
-
+
- Enable automatic garbage collection
+
The nix store fills up over time, until /boot/efi
is filled. This snippet cleans it automatically on a weekly basis.
@@ -5666,8 +5675,8 @@
3
-- Enable automatic store optimisation
-
+
- Enable automatic store optimisation
+
This enables hardlinking identical files in the nix store, to save on disk space. I have read this incurs a significant I/O overhead, I need to keep an eye on this.
@@ -8734,3598 +8743,4213 @@
3
];
};
- };
+ };
+
+ nixOnDroidConfigurations = {
+
+ default = nix-on-droid.lib.nixOnDroidConfiguration {
+ modules = [
+ ./profiles/mysticant/configuration.nix
+ ];
+ };
+
+ };
+
+ packages.x86_64-linux = {
+
+ };
+
+ };
+}
+
+
+
+
+
+
+
+
+
4. Emacs
+
+
+
+
4.1. Initialization (early-init.el)
+
+
+In this section I handle my early init file; it takes care of frame-setup for emacsclient buffers.
+
+
+
+
4.1.1. Increase startup performance
+
+
+First, I use some advice from doomemacs regarding garbace collection; here I make sure that during startup, the garbace collectur will not run, which will improve startup times. Now, that might not really be needed since I will usually only start the emacs server once during startup and then not touch it again, however, since I am building my emacs configuration using NixOS, there is some merit to this since I will usually need to restart the server once I rebuild my configuration.
+
+
+
+Also, inspired by a setting I have seen in protesilaos' configuration, I apply the same idea to the file-name-handler-alist
and vc-handled-backends
.
+
+
+
+In the end, we need to restore those values to values that will work during normal operation. For that, I add a hook to the startup function that will revert the values once Emacs has finished initialization.
+
+
+
+Also packed into the hook function is the line (fset 'epg-wait-for-status 'ignore)
. This line is needed at the end of the configuration in order to allow for my Yubikey to be used to encrypt and decrypt .gpg
files. Without it, Emacs will just hang forever and basically crash.
+
+
+
+
(defvar swarsel-file-name-handler-alist file-name-handler-alist)
+(defvar swarsel-vc-handled-backends vc-handled-backends)
+
+(setq gc-cons-threshold most-positive-fixnum
+ gc-cons-percentage 0.6
+ file-name-handler-alist nil
+ vc-handled-backends nil)
+
+(add-hook 'emacs-startup-hook
+ (lambda ()
+ (progn
+ (setq gc-cons-threshold (* 1000 1000 8)
+ gc-cons-percentage 0.1
+ file-name-handler-alist swarsel-file-name-handler-alist
+ vc-handled-backends swarsel-vc-handled-backends)
+ (fset 'epg-wait-for-status 'ignore)
+ )))
+
+
+
+
+
+
+
4.1.2. Setup frames
+
+
+Next, I will setup the basic frame for my emacs buffers. Note that I use a tiling window manager, so I do not need to hold myself up with sizing the windows myself. I also disable some GUI tools that I (like many others) do not find to be particularly useful. Also I inhibit many startup functions here, even though it does not affect me greatly since I use another solution for that.
+
+
+
+We also make require immediate compilation of native code.
+
+
+
+For the default-frame-alist
, I used to also set '(right-divider-width . 4)
and '(bottom-divider-width . 4)
, but I did not like the look of the divider bar and usually know my splits anyways, so this is no longer set.
+
+
+
+
(tool-bar-mode 0)
+(menu-bar-mode 0)
+(scroll-bar-mode 0)
+
+(setq frame-inhibit-implied-resize t
+ ring-bell-function 'ignore
+ use-dialog-box nil
+ use-file-dialog nil
+ use-short-answers t
+ inhibit-startup-message t
+ inhibit-splash-screen t
+ inhibit-startup-screen t
+ inhibit-x-resources t
+ inhibit-startup-buffer-menu t
+ inhibit-startup-echo-area-message user-login-name ; this needs to be set to the username or it will not have an effect
+ comp-deferred-compilation nil ; compile all Elisp to native code immediately
+ )
+
+(setq-default left-margin-width 1
+ right-margin-width 1)
+
+(setq-default default-frame-alist
+ (append
+ (list
+ '(undecorated . t) ; no title bar, borders etc.
+ '(background-color . "#1D252C") ; load doom-citylight colors to avoid white flash
+ '(foreground-color . "#A0B3C5") ; load doom-citylight colors to avoid white flash
+ '(vertical-scroll-bars . nil)
+ '(horizontal-scroll-bars . nil)
+ '(internal-border-width . 5)
+ '(tool-bar-lines . 0)
+ '(menu-bar-lines . 0))))
+
+
+
+
+
+
+
4.1.3. Make C-i, C-m, C-[ available in graphic sessions
+
+
+By default, emacs binds
+
+
+C-i
to the TAB
key
+C-m
to the RET
key
+C-[
to the ECS
key
+
+
+
+These keybinds exist to make Emacs work well in terminal mode. However, most of the time I am using Emacs in a graphic session, and I would hence like to have these keybinds available for personal use.
+
- nixOnDroidConfigurations = {
+
+NOTE: To use these keybinds, you need to enclose the binding in angled brackets (<>
). Then they can be used normally
+
- default = nix-on-droid.lib.nixOnDroidConfiguration {
- modules = [
- ./profiles/mysticant/configuration.nix
- ];
- };
+
+
+(add-hook
+ 'after-make-frame-functions
+ (lambda (frame)
+ (with-selected-frame frame
+ (when (display-graphic-p)
+ (define-key input-decode-map (kbd "C-i") [DUMMY-i])
+ (define-key input-decode-map (kbd "C-[") [DUMMY-lsb])
+ (define-key input-decode-map (kbd "C-m") [DUMMY-m])
+ ))))
- };
- packages.x86_64-linux = {
- };
- };
-}
+
+
+
+
+
+
+
4.2. Personal settings
+
+
+This section is used to define my own functions, own variables, and own keybindings.
+
+
+
+
4.2.1. Custom functions
+
+
+In this section I define extra functions that I need. Some of these functions I wrote myself, some I found after internet reseach. For functions I found on the internet, I will link the original source I found it in.
+
+
+
+- Emacs/Evil state toggle
+
+
+Since I am rebinding the C-z
hotkey for emacs-evil-state toggling, I want to have a function that still lets me perform this action quickly.
+
+
+
+
+(defun swarsel/toggle-evil-state ()
+ (interactive)
+ (if (or (evil-emacs-state-p) (evil-insert-state-p))
+ (evil-normal-state)
+ (evil-emacs-state)))
+
+- Switching to last used buffer
+
+
+I often find myself bouncing between two buffers when I do not want to use a window split. This funnction simply jumps to the last used buffer.
+
+
+
+
+(defun swarsel/last-buffer () (interactive) (switch-to-buffer nil))
+
+
+
+- mu4e functions
+
+
+I use these functions to let me switch between my main email accounts, as mu4e by itself has trouble doing so. mu4e-switch-account
allows for manual choosing of the sender account, while mu4e-rfs--matching-address
and mu4e-send-from-correct-address
are used when replying to a mail; they switch the sender account to the one that received the mail.
+
+
+
+By default, the sender email will not be changed after sending a mail; however, I want Emacs to always use my main address when not replying to another email. For that I use mu4e-restore-default
.
+
+
+
+Used here: mu4e
+
+
+
+
+(defun swarsel/mu4e-switch-account ()
+ (interactive)
+ (let ((account (completing-read "Select account: " mu4e-user-mail-address-list)))
+ (setq user-mail-address account)))
+
+(defun swarsel/mu4e-rfs--matching-address ()
+ (cl-loop for to-data in (mu4e-message-field mu4e-compose-parent-message :to)
+ for to-email = (pcase to-data
+ (`(_ . email) email)
+ (x (mu4e-contact-email x)))
+ for to-name = (pcase to-data
+ (`(_ . name) name)
+ (x (mu4e-contact-name x)))
+ when (mu4e-user-mail-address-p to-email)
+ return (list to-name to-email)))
+
+(defun swarsel/mu4e-send-from-correct-address ()
+ (when mu4e-compose-parent-message
+ (save-excursion
+ (when-let ((dest (swarsel/mu4e-rfs--matching-address)))
+ (cl-destructuring-bind (from-user from-addr) dest
+ (setq user-mail-address from-addr)
+ (message-position-on-field "From")
+ (message-beginning-of-line)
+ (delete-region (point) (line-end-position))
+ (insert (format "%s <%s>" (or from-user user-full-name) from-addr)))))))
+
+(defun swarsel/mu4e-restore-default ()
+ (setq user-mail-address "leon@swarsel.win"
+ user-full-name "Leon Schwarzäugl"))
+
+
+
-
-
4. Emacs
-
-
-
4.1. Initialization (early-init.el)
-
+
+
- Create non-existant directories when finding file
+
-In this section I handle my early init file; it takes care of frame-setup for emacsclient buffers.
+This function will check if a directory for which a file we want to open exists; if not, it will offer to create the directories for me.
+
+
+
+(defun swarsel/with-buffer-name-prompt-and-make-subdirs ()
+ (let ((parent-directory (file-name-directory buffer-file-name)))
+ (when (and (not (file-exists-p parent-directory))
+ (y-or-n-p (format "Directory `%s' does not exist! Create it? " parent-directory)))
+ (make-directory parent-directory t))))
+
+(add-to-list 'find-file-not-found-functions #'swarsel/with-buffer-name-prompt-and-make-subdirs)
+
+
-
-
4.1.1. Increase startup performance
-
+
+
+
- [crux] Duplicate Lines
+
-First, I use some advice from doomemacs regarding garbace collection; here I make sure that during startup, the garbace collectur will not run, which will improve startup times. Now, that might not really be needed since I will usually only start the emacs server once during startup and then not touch it again, however, since I am building my emacs configuration using NixOS, there is some merit to this since I will usually need to restart the server once I rebuild my configuration.
+When programming, I like to be able to duplicate a line. There are easier functions than the one below, but they either
+
+- screw with undo/redo
+- move the cursor wildly
+
+
-Also, inspired by a setting I have seen in protesilaos' configuration, I apply the same idea to the file-name-handler-alist
and vc-handled-backends
.
+The below function avoids these problems. Originally I used the function duplicate-line
found here: https://stackoverflow.com/questions/88399/how-do-i-duplicate-a-whole-line-in-emacs
-In the end, we need to restore those values to values that will work during normal operation. For that, I add a hook to the startup function that will revert the values once Emacs has finished initialization.
+However, this function does not work on regions. Later, I found a solution implemented by crux. I do not need the whole package, so I just extracted the three functions I needed from it.
+
+
+(defun crux-get-positions-of-line-or-region ()
+ "Return positions (beg . end) of the current line or region."
+ (let (beg end)
+ (if (and mark-active (> (point) (mark)))
+ (exchange-point-and-mark))
+ (setq beg (line-beginning-position))
+ (if mark-active
+ (exchange-point-and-mark))
+ (setq end (line-end-position))
+ (cons beg end)))
+
+(defun crux-duplicate-current-line-or-region (arg)
+ "Duplicates the current line or region ARG times.
+ If there's no region, the current line will be duplicated. However, if
+ there's a region, all lines that region covers will be duplicated."
+ (interactive "p")
+ (pcase-let* ((origin (point))
+ (`(,beg . ,end) (crux-get-positions-of-line-or-region))
+ (region (buffer-substring-no-properties beg end)))
+ (dotimes (_i arg)
+ (goto-char end)
+ (newline)
+ (insert region)
+ (setq end (point)))
+ (goto-char (+ origin (* (length region) arg) arg))))
+
+(defun crux-duplicate-and-comment-current-line-or-region (arg)
+ "Duplicates and comments the current line or region ARG times.
+If there's no region, the current line will be duplicated. However, if
+there's a region, all lines that region covers will be duplicated."
+ (interactive "p")
+ (pcase-let* ((origin (point))
+ (`(,beg . ,end) (crux-get-positions-of-line-or-region))
+ (region (buffer-substring-no-properties beg end)))
+ (comment-or-uncomment-region beg end)
+ (setq end (line-end-position))
+ (dotimes (_ arg)
+ (goto-char end)
+ (newline)
+ (insert region)
+ (setq end (point)))
+ (goto-char (+ origin (* (length region) arg) arg))))
+
+
+
+
+
+
- [prot] org-id-headings
+
-Also packed into the hook function is the line (fset 'epg-wait-for-status 'ignore)
. This line is needed at the end of the configuration in order to allow for my Yubikey to be used to encrypt and decrypt .gpg
files. Without it, Emacs will just hang forever and basically crash.
+These functions by protesilaos generate heading links in an org-file similar to the normal org-store-link
approach when not using properties. This approach has a weakness however - if the heading name is changed, the link breaks. These functions generate a unique identifier for each heading which will not break and also works when exporting the file to html, for example.
-
(defvar swarsel-file-name-handler-alist file-name-handler-alist)
-(defvar swarsel-vc-handled-backends vc-handled-backends)
+
+(defun prot-org--id-get ()
+ "Get the CUSTOM_ID of the current entry.
+If the entry already has a CUSTOM_ID, return it as-is, else
+create a new one."
+ (let* ((pos (point))
+ (id (org-entry-get pos "CUSTOM_ID")))
+ (if (and id (stringp id) (string-match-p "\\S-" id))
+ id
+ (setq id (org-id-new "h"))
+ (org-entry-put pos "CUSTOM_ID" id)
+ id)))
-(setq gc-cons-threshold most-positive-fixnum
- gc-cons-percentage 0.6
- file-name-handler-alist nil
- vc-handled-backends nil)
+(declare-function org-map-entries "org")
-(add-hook 'emacs-startup-hook
- (lambda ()
- (progn
- (setq gc-cons-threshold (* 1000 1000 8)
- gc-cons-percentage 0.1
- file-name-handler-alist swarsel-file-name-handler-alist
- vc-handled-backends swarsel-vc-handled-backends)
- (fset 'epg-wait-for-status 'ignore)
- )))
+(defun prot-org-id-headlines ()
+ "Add missing CUSTOM_ID to all headlines in current file."
+ (interactive)
+ (org-map-entries
+ (lambda () (prot-org--id-get))))
+
+(defun prot-org-id-headline ()
+ "Add missing CUSTOM_ID to headline at point."
+ (interactive)
+ (prot-org--id-get))
-
-
-
4.1.2. Setup frames
-
-
-Next, I will setup the basic frame for my emacs buffers. Note that I use a tiling window manager, so I do not need to hold myself up with sizing the windows myself. I also disable some GUI tools that I (like many others) do not find to be particularly useful. Also I inhibit many startup functions here, even though it does not affect me greatly since I use another solution for that.
-
-
+
+
- Inhibit Messages in Echo Area
+
-We also make require immediate compilation of native code.
+Emacs likes to send messages to the echo area; this is generally a good thing. However, it bothers me a lot when I am currently working in minibuffer where I receive an echo area message that is actually important and it is then overwritten by e.g. the mu4e update message. This section makes it possible to find the root function calling the message function and disabling it here.
-For the default-frame-alist
, I used to also set '(right-divider-width . 4)
and '(bottom-divider-width . 4)
, but I did not like the look of the divider bar and usually know my splits anyways, so this is no longer set.
+Usage: Enable the (advice-add 'message :around #'who-called-me?)
by running this code block, which will show a full trace of all messages being sent to the echo area:
-
(tool-bar-mode 0)
-(menu-bar-mode 0)
-(scroll-bar-mode 0)
+
+(advice-add 'message :around #'who-called-me?)
-(setq frame-inhibit-implied-resize t
- ring-bell-function 'ignore
- use-dialog-box nil
- use-file-dialog nil
- use-short-answers t
- inhibit-startup-message t
- inhibit-splash-screen t
- inhibit-startup-screen t
- inhibit-x-resources t
- inhibit-startup-buffer-menu t
- inhibit-startup-echo-area-message user-login-name ; this needs to be set to the username or it will not have an effect
- comp-deferred-compilation nil ; compile all Elisp to native code immediately
- )
+
+
-(setq-default left-margin-width 1
- right-margin-width 1)
+
+Once the root function has been found, it can be disabled via advice=add
as in the last block in this section. To disable the stack tracing, run (advice-remove 'message #'who-called-me?)
or the following code block:
+
-(setq-default default-frame-alist
- (append
- (list
- '(undecorated . t) ; no title bar, borders etc.
- '(background-color . "#1D252C") ; load doom-citylight colors to avoid white flash
- '(foreground-color . "#A0B3C5") ; load doom-citylight colors to avoid white flash
- '(vertical-scroll-bars . nil)
- '(horizontal-scroll-bars . nil)
- '(internal-border-width . 5)
- '(tool-bar-lines . 0)
- '(menu-bar-lines . 0))))
+
+
+(advice-remove 'message #'who-called-me?)
-
-
-
-
4.1.3. Make C-i, C-m, C-[ available in graphic sessions
-
-
-By default, emacs binds
-
-
-C-i
to the TAB
key
-C-m
to the RET
key
-C-[
to the ECS
key
-
-These keybinds exist to make Emacs work well in terminal mode. However, most of the time I am using Emacs in a graphic session, and I would hence like to have these keybinds available for personal use.
+Lastly, individual messages can be reenabled using the (advice-remove '<FUNCTION-NAME> #'suppress-messages)
approach. Use this when you accidentally disabled a helpful message.
-
-NOTE: To use these keybinds, you need to enclose the binding in angled brackets (<>
). Then they can be used normally
-
-(add-hook
- 'after-make-frame-functions
- (lambda (frame)
- (with-selected-frame frame
- (when (display-graphic-p)
- (define-key input-decode-map (kbd "C-i") [DUMMY-i])
- (define-key input-decode-map (kbd "C-[") [DUMMY-lsb])
- (define-key input-decode-map (kbd "C-m") [DUMMY-m])
- ))))
+(defun suppress-messages (old-fun &rest args)
+ (cl-flet ((silence (&rest args1) (ignore)))
+ (advice-add 'message :around #'silence)
+ (unwind-protect
+ (apply old-fun args)
+ (advice-remove 'message #'silence))))
+
+(advice-add 'pixel-scroll-precision :around #'suppress-messages)
+(advice-add 'mu4e--server-filter :around #'suppress-messages)
+(advice-add 'org-unlogged-message :around #'suppress-messages)
+(advice-add 'magit-auto-revert-mode--init-kludge :around #'suppress-messages)
+(advice-add 'push-mark :around #'suppress-messages)
+
+;; to reenable
+;; (advice-remove 'timer-event-handler #'suppress-messages)
+
+(defun who-called-me? (old-fun format &rest args)
+ (let ((trace nil) (n 1) (frame nil))
+ (while (setf frame (backtrace-frame n))
+ (setf n (1+ n)
+ trace (cons (cadr frame) trace)) )
+ (apply old-fun (concat "<<%S>>\n" format) (cons trace args))))
+;; enable to get message backtrace, the first function shown in backtrace calls the other functions
+;; (advice-add 'message :around #'who-called-me?)
+;; disable to stop receiving backtrace
+(advice-remove 'message #'who-called-me?)
-
-
-
-
4.2. Personal settings
-
-
-This section is used to define my own functions, own variables, and own keybindings.
-
-
-
-
4.2.1. Custom functions
-
+
+
- Move up one directory for find-file
+
-In this section I define extra functions that I need. Some of these functions I wrote myself, some I found after internet reseach. For functions I found on the internet, I will link the original source I found it in.
+I find it very annoying that the standard behavior for M-DEL only deletes one word when using find-file. This function makes it so that we always go up by one directory level instead.
-
-
-- Emacs/Evil state toggle
-
+
-Since I am rebinding the C-z
hotkey for emacs-evil-state toggling, I want to have a function that still lets me perform this action quickly.
+This function was found here: https://www.reddit.com/r/emacs/comments/re31i6/how_to_go_up_one_directory_when_using_findfile_cx/
-(defun swarsel/toggle-evil-state ()
- (interactive)
- (if (or (evil-emacs-state-p) (evil-insert-state-p))
- (evil-normal-state)
- (evil-emacs-state)))
+(defun up-directory (path)
+ "Move up a directory in PATH without affecting the kill buffer."
+ (interactive "p")
+ (if (string-match-p "/." (minibuffer-contents))
+ (let ((end (point)))
+ (re-search-backward "/.")
+ (forward-char)
+ (delete-region (point) end))))
+
+(define-key minibuffer-local-filename-completion-map
+ [C-backspace] #'up-directory)
-- Switching to last used buffer
-
+
- org-mode: General setup
+
-I often find myself bouncing between two buffers when I do not want to use a window split. This funnction simply jumps to the last used buffer.
+Sets up the basic settings that I want to have active in org-mode buffers.
+
+
+
+Used here: General org-mode
-(defun swarsel/last-buffer () (interactive) (switch-to-buffer nil))
+(defun swarsel/org-mode-setup ()
+ (org-indent-mode)
+ (variable-pitch-mode 1)
+ ;;(auto-fill-mode 0)
+ (setq display-line-numbers-type 'relative
+ display-line-numbers-current-absolute 1
+ display-line-numbers-width-start nil
+ display-line-numbers-width 6
+ display-line-numbers-grow-only 1)
+ (add-hook 'org-tab-first-hook 'org-end-of-line)
+ (visual-line-mode 1))
-
- mu4e functions
-
+
- org-mode: Visual-fill column
+
-I use these functions to let me switch between my main email accounts, as mu4e by itself has trouble doing so. mu4e-switch-account
allows for manual choosing of the sender account, while mu4e-rfs--matching-address
and mu4e-send-from-correct-address
are used when replying to a mail; they switch the sender account to the one that received the mail.
+This function sets the width of buffers in org-mode.
-By default, the sender email will not be changed after sending a mail; however, I want Emacs to always use my main address when not replying to another email. For that I use mu4e-restore-default
.
+Used in: Centered org-mode Buffers
+
+
+(defun swarsel/org-mode-visual-fill ()
+ (setq visual-fill-column-width 150
+ visual-fill-column-center-text t)
+ (visual-fill-column-mode 1))
+
+
+
+
+
+
- org-mode: Auto-tangle and export Configuration Files
+
-Used here: mu4e
+This section automatically tangles all configuration blocks in this file to the defined Emacs org-file. It also exports the configuration file as html.
+
+
-(defun swarsel/mu4e-switch-account ()
- (interactive)
- (let ((account (completing-read "Select account: " mu4e-user-mail-address-list)))
- (setq user-mail-address account)))
+(defun swarsel/org-babel-tangle-config ()
+ (when (string-equal (buffer-file-name)
+ swarsel-swarsel-org-filepath)
+ ;; Dynamic scoping to the rescue
+ (let ((org-confirm-babel-evaluate nil))
+ (org-html-export-to-html)
+ (org-babel-tangle)))
+ (when (string-equal (buffer-file-name)
+ swarsel-emacs-org-filepath)
+ ;; Dynamic scoping to the rescue
+ (let ((org-confirm-babel-evaluate nil))
+ (org-html-export-to-html)
+ (org-babel-tangle)))
+ (when (string-equal (buffer-file-name)
+ swarsel-nix-org-filepath)
+ ;; Dynamic scoping to the rescue
+ (let ((org-confirm-babel-evaluate nil))
+ (org-babel-tangle))))
-(defun swarsel/mu4e-rfs--matching-address ()
- (cl-loop for to-data in (mu4e-message-field mu4e-compose-parent-message :to)
- for to-email = (pcase to-data
- (`(_ . email) email)
- (x (mu4e-contact-email x)))
- for to-name = (pcase to-data
- (`(_ . name) name)
- (x (mu4e-contact-name x)))
- when (mu4e-user-mail-address-p to-email)
- return (list to-name to-email)))
+(setq org-html-htmlize-output-type nil)
-(defun swarsel/mu4e-send-from-correct-address ()
- (when mu4e-compose-parent-message
- (save-excursion
- (when-let ((dest (swarsel/mu4e-rfs--matching-address)))
- (cl-destructuring-bind (from-user from-addr) dest
- (setq user-mail-address from-addr)
- (message-position-on-field "From")
- (message-beginning-of-line)
- (delete-region (point) (line-end-position))
- (insert (format "%s <%s>" (or from-user user-full-name) from-addr)))))))
+(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config)))
-(defun swarsel/mu4e-restore-default ()
- (setq user-mail-address "leon@swarsel.win"
- user-full-name "Leon Schwarzäugl"))
-
- Create non-existant directories when finding file
-
+
- org-mode: Fold current heading
+
+
+Normally emacs cycles between three states:
+
+
+
+- fully folded
+- One heading expanded
+- All headings expanded
+
+
-This function will check if a directory for which a file we want to open exists; if not, it will offer to create the directories for me.
+However, I want to be able to fold a single heading consistently.
-(defun swarsel/with-buffer-name-prompt-and-make-subdirs ()
- (let ((parent-directory (file-name-directory buffer-file-name)))
- (when (and (not (file-exists-p parent-directory))
- (y-or-n-p (format "Directory `%s' does not exist! Create it? " parent-directory)))
- (make-directory parent-directory t))))
-
-(add-to-list 'find-file-not-found-functions #'swarsel/with-buffer-name-prompt-and-make-subdirs)
+(defun org-fold-outer ()
+ (interactive)
+ (org-beginning-of-line)
+ (if (string-match "^*+" (thing-at-point 'line t))
+ (outline-up-heading 1))
+ (outline-hide-subtree)
+ )
-
- [crux] Duplicate Lines
-
-
-When programming, I like to be able to duplicate a line. There are easier functions than the one below, but they either
-
-
-
-- screw with undo/redo
-- move the cursor wildly
-
-
+
- corfu: Do not interrupt navigation
+
-The below function avoids these problems. Originally I used the function duplicate-line
found here: https://stackoverflow.com/questions/88399/how-do-i-duplicate-a-whole-line-in-emacs
+These three functions allow me to keep using the normal navigation keys even when a corfu completion pops up.
-However, this function does not work on regions. Later, I found a solution implemented by crux. I do not need the whole package, so I just extracted the three functions I needed from it.
+These functions are used here: Corfu
-(defun crux-get-positions-of-line-or-region ()
- "Return positions (beg . end) of the current line or region."
- (let (beg end)
- (if (and mark-active (> (point) (mark)))
- (exchange-point-and-mark))
- (setq beg (line-beginning-position))
- (if mark-active
- (exchange-point-and-mark))
- (setq end (line-end-position))
- (cons beg end)))
+(defun swarsel/corfu-normal-return (&optional arg)
+ (interactive)
+ (corfu-quit)
+ (newline)
+ )
-(defun crux-duplicate-current-line-or-region (arg)
- "Duplicates the current line or region ARG times.
- If there's no region, the current line will be duplicated. However, if
- there's a region, all lines that region covers will be duplicated."
- (interactive "p")
- (pcase-let* ((origin (point))
- (`(,beg . ,end) (crux-get-positions-of-line-or-region))
- (region (buffer-substring-no-properties beg end)))
- (dotimes (_i arg)
- (goto-char end)
- (newline)
- (insert region)
- (setq end (point)))
- (goto-char (+ origin (* (length region) arg) arg))))
+(defun swarsel/corfu-quit-and-up (&optional arg)
+ (interactive)
+ (corfu-quit)
+ (evil-previous-visual-line))
-(defun crux-duplicate-and-comment-current-line-or-region (arg)
- "Duplicates and comments the current line or region ARG times.
-If there's no region, the current line will be duplicated. However, if
-there's a region, all lines that region covers will be duplicated."
- (interactive "p")
- (pcase-let* ((origin (point))
- (`(,beg . ,end) (crux-get-positions-of-line-or-region))
- (region (buffer-substring-no-properties beg end)))
- (comment-or-uncomment-region beg end)
- (setq end (line-end-position))
- (dotimes (_ arg)
- (goto-char end)
- (newline)
- (insert region)
- (setq end (point)))
- (goto-char (+ origin (* (length region) arg) arg))))
+(defun swarsel/corfu-quit-and-down (&optional arg)
+ (interactive)
+ (corfu-quit)
+ (evil-next-visual-line))
-
- [prot] org-id-headings
-
+
- python shell reloading
+
-These functions by protesilaos generate heading links in an org-file similar to the normal org-store-link
approach when not using properties. This approach has a weakness however - if the heading name is changed, the link breaks. These functions generate a unique identifier for each heading which will not break and also works when exporting the file to html, for example.
+The standard Emacs behaviour for the Python process shell is a bit annoying. This is my attempt at making it show automatically on opening a python buffer and making it refresh on its own as well. This does not nicely work yet.
-(defun prot-org--id-get ()
- "Get the CUSTOM_ID of the current entry.
-If the entry already has a CUSTOM_ID, return it as-is, else
-create a new one."
- (let* ((pos (point))
- (id (org-entry-get pos "CUSTOM_ID")))
- (if (and id (stringp id) (string-match-p "\\S-" id))
- id
- (setq id (org-id-new "h"))
- (org-entry-put pos "CUSTOM_ID" id)
- id)))
+ ;; run the python inferior shell immediately upon entering a python buffer
+ ;; (add-hook 'python-mode-hook 'swarsel/run-python)
-(declare-function org-map-entries "org")
+ ;; (defun swarsel/run-python ()
+ ;; (save-selected-window
+ ;; (switch-to-buffer-other-window (process-buffer (python-shell-get-or-create-process (python-shell-parse-command))))))
-(defun prot-org-id-headlines ()
- "Add missing CUSTOM_ID to all headlines in current file."
+;; reload python shell automatically
+(defun my-python-shell-run ()
(interactive)
- (org-map-entries
- (lambda () (prot-org--id-get))))
+ (when (get-buffer-process "*Python*")
+ (set-process-query-on-exit-flag (get-buffer-process "*Python*") nil)
+ (kill-process (get-buffer-process "*Python*"))
+ ;; Uncomment If you want to clean the buffer too.
+ ;;(kill-buffer "*Python*")
+ ;; Not so fast!
+ (sleep-for 0.5))
+ (run-python (python-shell-parse-command) nil nil)
+ (python-shell-send-buffer)
+ ;; Pop new window only if shell isnt visible
+ ;; in any frame.
+ (unless (get-buffer-window "*Python*" t)
+ (python-shell-switch-to-shell)))
-(defun prot-org-id-headline ()
- "Add missing CUSTOM_ID to headline at point."
+(defun my-python-shell-run-region ()
(interactive)
- (prot-org--id-get))
+ (python-shell-send-region (region-beginning) (region-end))
+ (python-shell-switch-to-shell))
-
- Inhibit Messages in Echo Area
-
+
+
+
+
4.2.2. Custom Keybindings
+
-Emacs likes to send messages to the echo area; this is generally a good thing. However, it bothers me a lot when I am currently working in minibuffer where I receive an echo area message that is actually important and it is then overwritten by e.g. the mu4e update message. This section makes it possible to find the root function calling the message function and disabling it here.
+This defines a set of keybinds that I want to have available globally. I have one set of keys that is globally available through the C-SPC
prefix. This set is used mostly for functions that I have trouble remembering the original keybind for, or that I just want to have gathered in a common space.
-Usage: Enable the (advice-add 'message :around #'who-called-me?)
by running this code block, which will show a full trace of all messages being sent to the echo area:
+I also define some keybinds to some combinations directly. Those are used mostly for custom functions that I call often enough to warrant this.
-(advice-add 'message :around #'who-called-me?)
+;; Make ESC quit prompts
+(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
-
-
+;; Set up general keybindings
+(use-package general
+ :config
+ (general-create-definer swarsel/leader-keys
+ :keymaps '(normal insert visual emacs)
+ :prefix "SPC"
+ :global-prefix "C-SPC")
-
-Once the root function has been found, it can be disabled via advice=add
as in the last block in this section. To disable the stack tracing, run (advice-remove 'message #'who-called-me?)
or the following code block:
-
+ (swarsel/leader-keys
+ "e" '(:ignore e :which-key "evil")
+ "eo" '(evil-jump-backward :which-key "cursor jump backwards")
+ "eO" '(evil-jump-forward :which-key "cursor jump forwards")
+ "t" '(:ignore t :which-key "toggles")
+ "ts" '(hydra-text-scale/body :which-key "scale text")
+ "te" '(swarsel/toggle-evil-state :which-key "emacs/evil")
+ "tl" '(display-line-numbers-mode :which-key "line numbers")
+ "tp" '(evil-cleverparens-mode :wk "cleverparens")
+ "to" '(olivetti-mode :wk "olivetti")
+ "td" '(darkroom-tentative-mode :wk "darkroom")
+ "tw" '((lambda () (interactive) (toggle-truncate-lines)) :which-key "line wrapping")
+ "m" '(:ignore m :which-key "modes/programs")
+ "mm" '((lambda () (interactive) (mu4e)) :which-key "mu4e")
+ "mg" '((lambda () (interactive) (magit-list-repositories)) :which-key "magit-list-repos")
+ "mc" '((lambda () (interactive) (swarsel/open-calendar)) :which-key "calendar")
+ "mp" '(popper-toggle :which-key "popper")
+ "md" '(dirvish :which-key "dirvish")
+ "o" '(:ignore o :which-key "org")
+ "op" '((lambda () (interactive) (org-present)) :which-key "org-present")
+ "ob" '((lambda () (interactive) (org-babel-mark-block)) :which-key "Mark whole src-block")
+ "ol" '((lambda () (interactive) (org-insert-link)) :which-key "insert link")
+ "os" '((lambda () (interactive) (org-store-link)) :which-key "store link")
+ "od" '((lambda () (interactive) (org-babel-demarcate-block)) :which-key "demarcate (split) src-block")
+ ;; "c" '(:ignore c :which-key "capture")
+ ;; "cj" '((lambda () (interactive) (org-capture nil "jj")) :which-key "journal")
+ ;; "cs" '(markdown-download-screenshot :which-key "screenshot")
+ "l" '(:ignore l :which-key "links")
+ "lc" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (org-overview) )) :which-key "SwarselSystems.org")
+ "le" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "Emacs") ) (org-overview) (org-cycle) )) :which-key "Emacs.org")
+ "ln" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "System") ) (org-overview) (org-cycle))) :which-key "Nixos.org")
+ "ls" '((lambda () (interactive) (find-file "/smb:Swarsel@192.168.1.3:")) :which-key "Server")
+ "lo" '(dired swarsel-obsidian-vault-directory :which-key "obsidian")
+ ;; "la" '((lambda () (interactive) (find-file swarsel-org-anki-filepath)) :which-key "anki")
+ ;; "ln" '((lambda () (interactive) (find-file swarsel-nix-org-filepath)) :which-key "Nix.org")
+ "lp" '((lambda () (interactive) (projectile-switch-project)) :which-key "switch project")
+ "lg" '((lambda () (interactive) (magit-list-repositories)) :which-key "list git repos")
+ ;; "a" '(:ignore a :which-key "anki")
+ ;; "ap" '(anki-editor-push-tree :which-key "push new cards")
+ ;; "an" '((lambda () (interactive) (org-capture nil "a")) :which-key "new card")
+ ;; "as" '(swarsel-anki-set-deck-and-notetype :which-key "change deck and notetype")
+ "h" '(:ignore h :which-key "help")
+ "hy" '(yas-describe-tables :which-key "yas tables")
+ "hb" '(embark-bindings :which-key "current key bindings")
+ "h" '(:ignore t :which-key "describe")
+ "he" 'view-echo-area-messages
+ "hf" 'describe-function
+ "hF" 'describe-face
+ "hl" '(view-lossage :which-key "show command keypresses")
+ "hL" 'find-library
+ "hm" 'describe-mode
+ "ho" 'describe-symbol
+ "hk" 'describe-key
+ "hK" 'describe-keymap
+ "hp" 'describe-package
+ "hv" 'describe-variable
+ "hd" 'devdocs-lookup
+ "w" '(:ignore t :which-key "window")
+ "wl" 'windmove-right
+ "wh" 'windmove-left
+ "wk" 'windmove-up
+ "wj" 'windmove-down
+ "wr" 'winner-redo
+ "wd" 'delete-window
+ "w=" 'balance-windows-area
+ "wD" 'kill-buffer-and-window
+ "wu" 'winner-undo
+ "wr" 'winner-redo
+ "w/" 'evil-window-vsplit
+ "w-" 'evil-window-split
+ "wm" '(delete-other-windows :wk "maximize")
+ "<right>" 'up-list
+ "<left>" 'down-list
+ ))
-
-
-(advice-remove 'message #'who-called-me?)
+;; General often used hotkeys
+(general-define-key
+ "C-M-a" (lambda () (interactive) (org-capture nil "a")) ; make new anki card
+ ;; "C-M-d" 'swarsel-obsidian-daily ; open daily obsidian file and create if not exist
+ ;; "C-M-S" 'swarsel-anki-set-deck-and-notetype ; switch deck and notetype for new anki cards
+ ;; "C-M-s" 'markdown-download-screenshot ; wrapper for org-download-screenshot
+ "C-c d" 'crux-duplicate-current-line-or-region
+ "C-c D" 'crux-duplicate-and-comment-current-line-or-region
+ "<DUMMY-m>" 'swarsel/last-buffer
+ "M-\\" 'indent-region
+ "C-<f9>" 'my-python-shell-run
+ )
-
+
+
+
+
4.2.3. Directory setup / File structure
+
-Lastly, individual messages can be reenabled using the (advice-remove '<FUNCTION-NAME> #'suppress-messages)
approach. Use this when you accidentally disabled a helpful message.
+In this section I setup some aliases that I use for various directories on my system. Some of these are actually used for magit repository finding etc., but many of them serve no real use and I need to clean this up someday.
-
-(defun suppress-messages (old-fun &rest args)
- (cl-flet ((silence (&rest args1) (ignore)))
- (advice-add 'message :around #'silence)
- (unwind-protect
- (apply old-fun args)
- (advice-remove 'message #'silence))))
+;; set Nextcloud directory for journals etc.
+(setq swarsel-sync-directory "~/Nextcloud"
+ swarsel-emacs-directory "~/.emacs.d"
+ swarsel-dotfiles-directory "~/.dotfiles"
+ swarsel-projects-directory "~/Documents/GitHub")
-(advice-add 'pixel-scroll-precision :around #'suppress-messages)
-(advice-add 'mu4e--server-filter :around #'suppress-messages)
-(advice-add 'org-unlogged-message :around #'suppress-messages)
-(advice-add 'magit-auto-revert-mode--init-kludge :around #'suppress-messages)
-(advice-add 'push-mark :around #'suppress-messages)
+(setq swarsel-emacs-org-filepath (expand-file-name "Emacs.org" swarsel-dotfiles-directory)
+ swarsel-nix-org-filepath (expand-file-name "Nix.org" swarsel-dotfiles-directory)
+ swarsel-swarsel-org-filepath (expand-file-name "SwarselSystems.org" swarsel-dotfiles-directory)
+ )
-;; to reenable
-;; (advice-remove 'timer-event-handler #'suppress-messages)
-(defun who-called-me? (old-fun format &rest args)
- (let ((trace nil) (n 1) (frame nil))
- (while (setf frame (backtrace-frame n))
- (setf n (1+ n)
- trace (cons (cadr frame) trace)) )
- (apply old-fun (concat "<<%S>>\n" format) (cons trace args))))
+;; set Emacs main configuration .org names
+(setq swarsel-emacs-org-file "Emacs.org"
+ swarsel-anki-org-file "Anki.org"
+ swarsel-tasks-org-file "Tasks.org"
+ swarsel-archive-org-file "Archive.org"
+ swarsel-org-folder-name "Org"
+ swarsel-obsidian-daily-folder-name "⭐ Personal/Journal"
+ swarsel-obsidian-folder-name "Obsidian"
+ swarsel-obsidian-vault-name "Main")
-;; enable to get message backtrace, the first function shown in backtrace calls the other functions
-;; (advice-add 'message :around #'who-called-me?)
-;; disable to stop receiving backtrace
-(advice-remove 'message #'who-called-me?)
+;; set directory paths
+(setq swarsel-org-directory (expand-file-name swarsel-org-folder-name swarsel-sync-directory)) ; path to org folder
+(setq swarsel-obsidian-directory (expand-file-name swarsel-obsidian-folder-name swarsel-sync-directory)) ; path to obsidian
+(setq swarsel-obsidian-vault-directory (expand-file-name swarsel-obsidian-vault-name swarsel-obsidian-directory)) ; path to obsidian vault
+(setq swarsel-obsidian-daily-directory (expand-file-name swarsel-obsidian-daily-folder-name swarsel-obsidian-vault-directory)) ; path to obsidian daily folder
+
+;; filepaths to certain documents
+(setq swarsel-org-anki-filepath (expand-file-name swarsel-anki-org-file swarsel-org-directory) ; path to anki export file
+ swarsel-org-tasks-filepath (expand-file-name swarsel-tasks-org-file swarsel-org-directory)
+ swarsel-org-archive-filepath (expand-file-name swarsel-archive-org-file swarsel-org-directory))
+
-
-
- Move up one directory for find-file
-
+
+
+
4.2.4. Unclutter .emacs.d
+
-I find it very annoying that the standard behavior for M-DEL only deletes one word when using find-file. This function makes it so that we always go up by one directory level instead.
+In this section I move the custom.el
out of it's standard location in .emacs.d
. Firstly, I dislike using this file at all since I would rather have fully stateful configuration as commanded by this file. Secondly, this file is too easily permanently changed. Recently I figured out the last bits that I needed to remove from custom.el to no longer be reliant on it, so I now just write it to a temporary file (through make-temp=file
) which will be cleaned on shutdown. However, I like to retain the custom framework because it is nice for testing out theme customizations, hence why I still load the file.
-This function was found here: https://www.reddit.com/r/emacs/comments/re31i6/how_to_go_up_one_directory_when_using_findfile_cx/
+This section also sets the emacs directory to the ~/.cache/
directory which is useful for files that I do not want to have lying around in my .emacs.d
.
-(defun up-directory (path)
- "Move up a directory in PATH without affecting the kill buffer."
- (interactive "p")
- (if (string-match-p "/." (minibuffer-contents))
- (let ((end (point)))
- (re-search-backward "/.")
- (forward-char)
- (delete-region (point) end))))
+;; Change the user-emacs-directory to keep unwanted things out of ~/.emacs.d
+(setq user-emacs-directory (expand-file-name "~/.cache/emacs/")
+ url-history-file (expand-file-name "url/history" user-emacs-directory))
-(define-key minibuffer-local-filename-completion-map
- [C-backspace] #'up-directory)
+;; Use no-littering to automatically set common paths to the new user-emacs-directory
+(use-package no-littering)
+(setq custom-file (make-temp-file "emacs-custom-"))
+(load custom-file t)
-
-
- org-mode: General setup
-
-
-Sets up the basic settings that I want to have active in org-mode buffers.
-
-
+
+
+
4.2.5. Move backup files to another location
+
-Used here: General org-mode
+Many people dislike the Emacs backup files; I do enjoy them, but have to admit that they clutter the filesystem a little too much. Also, I rarely need to access these over different sessions. Hence I move them to /tmp
- if Emacs unexpectedly crashes, the files can be recovered, but the backup files will not gather everywhere and will be deleted upon shutdown.
-(defun swarsel/org-mode-setup ()
- (org-indent-mode)
- (variable-pitch-mode 1)
- ;;(auto-fill-mode 0)
- (setq display-line-numbers-type 'relative
- display-line-numbers-current-absolute 1
- display-line-numbers-width-start nil
- display-line-numbers-width 6
- display-line-numbers-grow-only 1)
- (add-hook 'org-tab-first-hook 'org-end-of-line)
- (visual-line-mode 1))
+(let ((backup-dir "~/tmp/emacs/backups")
+ (auto-saves-dir "~/tmp/emacs/auto-saves/"))
+ (dolist (dir (list backup-dir auto-saves-dir))
+ (when (not (file-directory-p dir))
+ (make-directory dir t)))
+ (setq backup-directory-alist `(("." . ,backup-dir))
+ auto-save-file-name-transforms `((".*" ,auto-saves-dir t))
+ auto-save-list-file-prefix (concat auto-saves-dir ".saves-")
+ tramp-backup-directory-alist `((".*" . ,backup-dir))
+ tramp-auto-save-directory auto-saves-dir))
+
+(setq backup-by-copying t ; Don't delink hardlinks
+ delete-old-versions t ; Clean up the backups
+ version-control t ; Use version numbers on backups,
+ kept-new-versions 5 ; keep some new versions
+ kept-old-versions 2) ; and some old ones, too
-
-
- org-mode: Visual-fill column
-
-
-This function sets the width of buffers in org-mode.
-
-
+
+
+
+
4.3. General init.el setup + UI
+
-Used in: Centered org-mode Buffers
+In this general section I have settings that I either consider to be integral to my experience when using emacs or have no other section that I feel they belong to.
-
-
-
-(defun swarsel/org-mode-visual-fill ()
- (setq visual-fill-column-width 150
- visual-fill-column-center-text t)
- (visual-fill-column-mode 1))
-
-
-
-
-
- org-mode: Auto-tangle and export Configuration Files
-
+
+
4.3.1. General setup
+
-This section automatically tangles all configuration blocks in this file to the defined Emacs org-file. It also exports the configuration file as html.
+Here I set up some things that are too minor to put under other categories.
-
-
+
+- Firstly we disable to having to type `yes` and `no` and switch it to `y` and `n`.
+- We also enable the marking of trailing whitespaces.
+- Also, make emacs highlight the current line globally
+- Emacs defaults to pausing all display redrawing on any input. This may have been useful previously, but is not necessary nowadays.
+- I also disable the suspend-frame function, as I never use it and it is quite confusing when accidentally hitting the keys for it.
+
-(defun swarsel/org-babel-tangle-config ()
- (when (string-equal (buffer-file-name)
- swarsel-swarsel-org-filepath)
- ;; Dynamic scoping to the rescue
- (let ((org-confirm-babel-evaluate nil))
- (org-html-export-to-html)
- (org-babel-tangle)))
- (when (string-equal (buffer-file-name)
- swarsel-emacs-org-filepath)
- ;; Dynamic scoping to the rescue
- (let ((org-confirm-babel-evaluate nil))
- (org-html-export-to-html)
- (org-babel-tangle)))
- (when (string-equal (buffer-file-name)
- swarsel-nix-org-filepath)
- ;; Dynamic scoping to the rescue
- (let ((org-confirm-babel-evaluate nil))
- (org-babel-tangle))))
+;; use UTF-8 everywhere
+(set-language-environment "UTF-8")
-(setq org-html-htmlize-output-type nil)
+;; set default font size
+(defvar swarsel/default-font-size 130)
+(setq swarsel-standard-font "FiraCode Nerd Font Mono"
+ swarsel-alt-font "FiraCode Nerd Font Mono")
-(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config)))
+;; (defalias 'yes-or-no-p 'y-or-n-p)
+;;(setq-default show-trailing-whitespace t)
+(add-hook 'before-save-hook 'delete-trailing-whitespace)
+(global-hl-line-mode 1)
+;; (setq redisplay-dont-pause t) ;; obsolete
+(setq blink-cursor-mode nil) ;; blink-cursor is an unexpected source of slowdown
+(global-subword-mode 1) ; Iterate through CamelCase words
+(setq blink-matching-paren nil) ;; this makes the cursor jump around annoyingly
+(delete-selection-mode 1)
+(setq vc-follow-symlinks t)
+(setq require-final-newline t)
+(winner-mode 1)
+(setq load-prefer-newer t)
+
+(setq undo-limit 80000000
+ evil-want-fine-undo t
+ auto-save-default t
+ password-cache-expiry nil
+ )
+(setq browse-url-browser-function 'browse-url-firefox)
+;; disable a keybind that does more harm than good
+(global-set-key [remap suspend-frame]
+ (lambda ()
+ (interactive)
+ (message "This keybinding is disabled (was 'suspend-frame')")))
+(setq visible-bell nil)
+(setq initial-major-mode 'fundamental-mode
+ initial-scratch-message nil)
+(add-hook 'prog-mode-hook 'display-line-numbers-mode)
+(add-hook 'text-mode-hook 'display-line-numbers-mode)
+(global-visual-line-mode 1)
-
-
- org-mode: Fold current heading
-
+
+
+
4.3.2. Mark all themes as safe
+
-Normally emacs cycles between three states:
+Normally when switching themes in emacs, the user will be warned that themes can run malicious code. I only run one theme really and deem it safe. It is however annoying to be asked this on every new system and it also creates lines in custom.el to answer that query, so here I declare all themes as safe.
-
-- fully folded
-- One heading expanded
-- All headings expanded
-
+
+
+(setq custom-safe-themes t)
+
+
+
+
+
+
4.3.3. Show less compilation warnings
+
-However, I want to be able to fold a single heading consistently.
+When Emacs compiles stuff, it often shows a bunch of warnings that I do not need to deal with. Here we silence those. Some will be disabled completely, and some only when we have native compilation available (which should be most of the time, however).
-
-
-(defun org-fold-outer ()
- (interactive)
- (org-beginning-of-line)
- (if (string-match "^*+" (thing-at-point 'line t))
- (outline-up-heading 1))
- (outline-hide-subtree)
- )
+
+
+(setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
+;; Make native compilation silent and prune its cache.
+(when (native-comp-available-p)
+ (setq native-comp-async-report-warnings-errors 'silent) ; Emacs 28 with native compilation
+ (setq native-compile-prune-cache t)) ; Emacs 29
-
-
- corfu: Do not interrupt navigation
-
+
+
+
4.3.4. Indentation
+
-These three functions allow me to keep using the normal navigation keys even when a corfu completion pops up.
+Here I define several options related to indentation; I first make it so that only whitespace will be used instead of tab characters for indentation, and I also set a small standard indent.
-These functions are used here: Corfu
+We set tab-always-indent
to 'complete
in order to indent first and then do completion if there are any. Also we make it so that python will not complain about missing indentation info.
+
+
+
+Lastly, I load the highlight-indent-guides
package. This adds a neat visual indicator of the indentation level, which is useful for languages like python.
-(defun swarsel/corfu-normal-return (&optional arg)
- (interactive)
- (corfu-quit)
- (newline)
- )
+(setq-default indent-tabs-mode nil
+ tab-width 2)
-(defun swarsel/corfu-quit-and-up (&optional arg)
- (interactive)
- (corfu-quit)
- (evil-previous-visual-line))
+(setq tab-always-indent 'complete)
+(setq python-indent-guess-indent-offset-verbose nil)
-(defun swarsel/corfu-quit-and-down (&optional arg)
- (interactive)
- (corfu-quit)
- (evil-next-visual-line))
+(use-package highlight-indent-guides
+ :hook (prog-mode . highlight-indent-guides-mode)
+ :init
+ (setq highlight-indent-guides-method 'column)
+ (setq highlight-indent-guides-responsive 'top)
+ )
+(with-eval-after-load 'highlight-indent-guides
+ (set-face-attribute 'highlight-indent-guides-even-face nil :background "gray10")
+ (set-face-attribute 'highlight-indent-guides-odd-face nil :background "gray20")
+ (set-face-attribute 'highlight-indent-guides-stack-even-face nil :background "gray40")
+ (set-face-attribute 'highlight-indent-guides-stack-odd-face nil :background "gray50"))
-
-
- python shell reloading
-
+
+
+
4.3.5. Scrolling
+
-The standard Emacs behaviour for the Python process shell is a bit annoying. This is my attempt at making it show automatically on opening a python buffer and making it refresh on its own as well. This does not nicely work yet.
+By default, emacs scrolls half a page when reaching the bottom of the buffer. This is extremely annoying. This sets up more granular scrolling that allows scrolling with a mouse wheel or the two-finger touchscreen gesture. This now also works in buffers with a very small frame.
- ;; run the python inferior shell immediately upon entering a python buffer
- ;; (add-hook 'python-mode-hook 'swarsel/run-python)
-
- ;; (defun swarsel/run-python ()
- ;; (save-selected-window
- ;; (switch-to-buffer-other-window (process-buffer (python-shell-get-or-create-process (python-shell-parse-command))))))
+(setq mouse-wheel-scroll-amount
+ '(1
+ ((shift) . 5)
+ ((meta) . 0.5)
+ ((control) . text-scale))
+ mouse-drag-copy-region nil
+ make-pointer-invisible t
+ mouse-wheel-progressive-speed t
+ mouse-wheel-follow-mouse t)
-;; reload python shell automatically
-(defun my-python-shell-run ()
- (interactive)
- (when (get-buffer-process "*Python*")
- (set-process-query-on-exit-flag (get-buffer-process "*Python*") nil)
- (kill-process (get-buffer-process "*Python*"))
- ;; Uncomment If you want to clean the buffer too.
- ;;(kill-buffer "*Python*")
- ;; Not so fast!
- (sleep-for 0.5))
- (run-python (python-shell-parse-command) nil nil)
- (python-shell-send-buffer)
- ;; Pop new window only if shell isnt visible
- ;; in any frame.
- (unless (get-buffer-window "*Python*" t)
- (python-shell-switch-to-shell)))
+(setq-default scroll-preserve-screen-position t
+ scroll-conservatively 1
+ scroll-margin 0
+ next-screen-context-lines 0)
-(defun my-python-shell-run-region ()
- (interactive)
- (python-shell-send-region (region-beginning) (region-end))
- (python-shell-switch-to-shell))
+(pixel-scroll-precision-mode 1)
-
-
-
-
4.2.2. Custom Keybindings
-
+
+
4.3.6. Evil
+
+
+
+- General evil
+
-This defines a set of keybinds that I want to have available globally. I have one set of keys that is globally available through the C-SPC
prefix. This set is used mostly for functions that I have trouble remembering the original keybind for, or that I just want to have gathered in a common space.
+This setups up evil, which brings vim-like keybindings to emacs. In the same location, I also unbind the C-z
key (I am very unhappy with this implementation, but it is the only thing that works consistently so far) to make it available for cape later.
-I also define some keybinds to some combinations directly. Those are used mostly for custom functions that I call often enough to warrant this.
+Also, I setup initial modes for several major-modes depending on what I deem fit.
-;; Make ESC quit prompts
-(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
-
-;; Set up general keybindings
-(use-package general
+;; Emulate vim in emacs
+(use-package evil
+ :init
+ (setq evil-want-integration t) ; loads evil
+ (setq evil-want-keybinding nil) ; loads "helpful bindings" for other modes
+ (setq evil-want-C-u-scroll t) ; scrolling using C-u
+ (setq evil-want-C-i-jump nil) ; jumping with C-i
+ (setq evil-want-Y-yank-to-eol t) ; give Y some utility
+ (setq evil-shift-width 2) ; uniform indent
+ (setq evil-respect-visual-line-mode t) ; i am torn on this one
+ (setq evil-split-window-below t)
+ (setq evil-vsplit-window-right t)
:config
- (general-create-definer swarsel/leader-keys
- :keymaps '(normal insert visual emacs)
- :prefix "SPC"
- :global-prefix "C-SPC")
+ (evil-mode 1)
+ (define-key evil-normal-state-map (kbd "C-z") nil)
+ (define-key evil-insert-state-map (kbd "C-z") nil)
+ (define-key evil-visual-state-map (kbd "C-z") nil)
+ (define-key evil-motion-state-map (kbd "C-z") nil)
+ (define-key evil-operator-state-map (kbd "C-z") nil)
+ (define-key evil-replace-state-map (kbd "C-z") nil)
+ (define-key global-map (kbd "C-z") nil)
+ (evil-set-undo-system 'undo-tree)
- (swarsel/leader-keys
- "e" '(:ignore e :which-key "evil")
- "eo" '(evil-jump-backward :which-key "cursor jump backwards")
- "eO" '(evil-jump-forward :which-key "cursor jump forwards")
- "t" '(:ignore t :which-key "toggles")
- "ts" '(hydra-text-scale/body :which-key "scale text")
- "te" '(swarsel/toggle-evil-state :which-key "emacs/evil")
- "tl" '(display-line-numbers-mode :which-key "line numbers")
- "tp" '(evil-cleverparens-mode :wk "cleverparens")
- "to" '(olivetti-mode :wk "olivetti")
- "td" '(darkroom-tentative-mode :wk "darkroom")
- "tw" '((lambda () (interactive) (toggle-truncate-lines)) :which-key "line wrapping")
- "m" '(:ignore m :which-key "modes/programs")
- "mm" '((lambda () (interactive) (mu4e)) :which-key "mu4e")
- "mg" '((lambda () (interactive) (magit-list-repositories)) :which-key "magit-list-repos")
- "mc" '((lambda () (interactive) (swarsel/open-calendar)) :which-key "calendar")
- "mp" '(popper-toggle :which-key "popper")
- "md" '(dirvish :which-key "dirvish")
- "o" '(:ignore o :which-key "org")
- "op" '((lambda () (interactive) (org-present)) :which-key "org-present")
- "ob" '((lambda () (interactive) (org-babel-mark-block)) :which-key "Mark whole src-block")
- "ol" '((lambda () (interactive) (org-insert-link)) :which-key "insert link")
- "os" '((lambda () (interactive) (org-store-link)) :which-key "store link")
- "od" '((lambda () (interactive) (org-babel-demarcate-block)) :which-key "demarcate (split) src-block")
- ;; "c" '(:ignore c :which-key "capture")
- ;; "cj" '((lambda () (interactive) (org-capture nil "jj")) :which-key "journal")
- ;; "cs" '(markdown-download-screenshot :which-key "screenshot")
- "l" '(:ignore l :which-key "links")
- "lc" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (org-overview) )) :which-key "SwarselSystems.org")
- "le" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "Emacs") ) (org-overview) (org-cycle) )) :which-key "Emacs.org")
- "ln" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "System") ) (org-overview) (org-cycle))) :which-key "Nixos.org")
- "ls" '((lambda () (interactive) (find-file "/smb:Swarsel@192.168.1.3:")) :which-key "Server")
- "lo" '(dired swarsel-obsidian-vault-directory :which-key "obsidian")
- ;; "la" '((lambda () (interactive) (find-file swarsel-org-anki-filepath)) :which-key "anki")
- ;; "ln" '((lambda () (interactive) (find-file swarsel-nix-org-filepath)) :which-key "Nix.org")
- "lp" '((lambda () (interactive) (projectile-switch-project)) :which-key "switch project")
- "lg" '((lambda () (interactive) (magit-list-repositories)) :which-key "list git repos")
- ;; "a" '(:ignore a :which-key "anki")
- ;; "ap" '(anki-editor-push-tree :which-key "push new cards")
- ;; "an" '((lambda () (interactive) (org-capture nil "a")) :which-key "new card")
- ;; "as" '(swarsel-anki-set-deck-and-notetype :which-key "change deck and notetype")
- "h" '(:ignore h :which-key "help")
- "hy" '(yas-describe-tables :which-key "yas tables")
- "hb" '(embark-bindings :which-key "current key bindings")
- "h" '(:ignore t :which-key "describe")
- "he" 'view-echo-area-messages
- "hf" 'describe-function
- "hF" 'describe-face
- "hl" '(view-lossage :which-key "show command keypresses")
- "hL" 'find-library
- "hm" 'describe-mode
- "ho" 'describe-symbol
- "hk" 'describe-key
- "hK" 'describe-keymap
- "hp" 'describe-package
- "hv" 'describe-variable
- "hd" 'devdocs-lookup
- "w" '(:ignore t :which-key "window")
- "wl" 'windmove-right
- "wh" 'windmove-left
- "wk" 'windmove-up
- "wj" 'windmove-down
- "wr" 'winner-redo
- "wd" 'delete-window
- "w=" 'balance-windows-area
- "wD" 'kill-buffer-and-window
- "wu" 'winner-undo
- "wr" 'winner-redo
- "w/" 'evil-window-vsplit
- "w-" 'evil-window-split
- "wm" '(delete-other-windows :wk "maximize")
- "<right>" 'up-list
- "<left>" 'down-list
- ))
+ ;; Don't use evil-mode in these contexts, or use it in a specific mode
+ (evil-set-initial-state 'messages-buffer-mode 'emacs)
+ (evil-set-initial-state 'dashboard-mode 'emacs)
+ (evil-set-initial-state 'dired-mode 'emacs)
+ (evil-set-initial-state 'cfw:details-mode 'emacs)
+ (evil-set-initial-state 'Custom-mode 'emacs) ; god knows why this mode is in uppercase
+ (evil-set-initial-state 'mu4e-headers-mode 'normal)
+ (evil-set-initial-state 'python-inferior-mode 'normal)
+ (add-hook 'org-capture-mode-hook 'evil-insert-state)
+ (add-to-list 'evil-buffer-regexps '("COMMIT_EDITMSG" . insert)))
-;; General often used hotkeys
-(general-define-key
- "C-M-a" (lambda () (interactive) (org-capture nil "a")) ; make new anki card
- ;; "C-M-d" 'swarsel-obsidian-daily ; open daily obsidian file and create if not exist
- ;; "C-M-S" 'swarsel-anki-set-deck-and-notetype ; switch deck and notetype for new anki cards
- ;; "C-M-s" 'markdown-download-screenshot ; wrapper for org-download-screenshot
- "C-c d" 'crux-duplicate-current-line-or-region
- "C-c D" 'crux-duplicate-and-comment-current-line-or-region
- "<DUMMY-m>" 'swarsel/last-buffer
- "M-\\" 'indent-region
- "C-<f9>" 'my-python-shell-run
- )
+
+
+
+
+- evil-collection
+
+
+This gives support for many different modes, and works beautifully out of the box.
+
+
+
+(use-package evil-collection
+ :after evil
+ :config
+ (evil-collection-init)
+ (setq forge-add-default-bindings nil))
-
-
-
4.2.3. Directory setup / File structure
-
+
+
- evil-snipe
+
-In this section I setup some aliases that I use for various directories on my system. Some of these are actually used for magit repository finding etc., but many of them serve no real use and I need to clean this up someday.
+This package changes the char-search commands like f
by showing the results in a more visual manner. It also gives a 2-character search using s
and S
.
-
-;; set Nextcloud directory for journals etc.
-(setq swarsel-sync-directory "~/Nextcloud"
- swarsel-emacs-directory "~/.emacs.d"
- swarsel-dotfiles-directory "~/.dotfiles"
- swarsel-projects-directory "~/Documents/GitHub")
-
-(setq swarsel-emacs-org-filepath (expand-file-name "Emacs.org" swarsel-dotfiles-directory)
- swarsel-nix-org-filepath (expand-file-name "Nix.org" swarsel-dotfiles-directory)
- swarsel-swarsel-org-filepath (expand-file-name "SwarselSystems.org" swarsel-dotfiles-directory)
- )
-
-
-;; set Emacs main configuration .org names
-(setq swarsel-emacs-org-file "Emacs.org"
- swarsel-anki-org-file "Anki.org"
- swarsel-tasks-org-file "Tasks.org"
- swarsel-archive-org-file "Archive.org"
- swarsel-org-folder-name "Org"
- swarsel-obsidian-daily-folder-name "⭐ Personal/Journal"
- swarsel-obsidian-folder-name "Obsidian"
- swarsel-obsidian-vault-name "Main")
-
-
-;; set directory paths
-(setq swarsel-org-directory (expand-file-name swarsel-org-folder-name swarsel-sync-directory)) ; path to org folder
-(setq swarsel-obsidian-directory (expand-file-name swarsel-obsidian-folder-name swarsel-sync-directory)) ; path to obsidian
-(setq swarsel-obsidian-vault-directory (expand-file-name swarsel-obsidian-vault-name swarsel-obsidian-directory)) ; path to obsidian vault
-(setq swarsel-obsidian-daily-directory (expand-file-name swarsel-obsidian-daily-folder-name swarsel-obsidian-vault-directory)) ; path to obsidian daily folder
+;; enables 2-char inline search
+ (use-package evil-snipe
+ :after evil
+ :demand
+ :config
+ (evil-snipe-mode +1)
+ ;; replace 1-char searches (f&t) with this better UI
+ (evil-snipe-override-mode +1))
+
+
+
+
+
- evil-cleverparens
+
+
+This helps keeping parentheses balanced which is useful when writing in languages like Elisp. I do not activate this by default, as most languages do not profit from this enough in my eyes.
+
-;; filepaths to certain documents
-(setq swarsel-org-anki-filepath (expand-file-name swarsel-anki-org-file swarsel-org-directory) ; path to anki export file
- swarsel-org-tasks-filepath (expand-file-name swarsel-tasks-org-file swarsel-org-directory)
- swarsel-org-archive-filepath (expand-file-name swarsel-archive-org-file swarsel-org-directory))
+
+
;; for parentheses-heavy languades modify evil commands to keep balance of parantheses
+(use-package evil-cleverparens)
+
+
+
+
+
- evil-surround
+
+
+This minor-mode adds functionality for doing better surround-commands; for example ci[
will let you change the word within square brackets.
+
+
+
+;; enables surrounding text with S
+(use-package evil-surround
+ :config
+ (global-evil-surround-mode 1))
+
+
-
-
4.2.4. Unclutter .emacs.d
-
+
+
4.3.7. ispell
+
-In this section I move the custom.el
out of it's standard location in .emacs.d
. Firstly, I dislike using this file at all since I would rather have fully stateful configuration as commanded by this file. Secondly, this file is too easily permanently changed. Recently I figured out the last bits that I needed to remove from custom.el to no longer be reliant on it, so I now just write it to a temporary file (through make-temp=file
) which will be cleaned on shutdown. However, I like to retain the custom framework because it is nice for testing out theme customizations, hence why I still load the file.
+This should setup a wordlist that can be used as a dictionary. However, for some reason this does not work, and I will need to further investigate this issue.
+
+
+;; set the NixOS wordlist by hand
+(setq ispell-alternate-dictionary "/nix/store/gjmvnbs97cnw19wnqh9m075cdbhy8r8g-wordlist-WORDLIST")
+
+
+
+
+
+
+
4.3.8. Font Configuration
+
-This section also sets the emacs directory to the ~/.cache/
directory which is useful for files that I do not want to have lying around in my .emacs.d
.
+Here I define my fonts to be used. Honestly I do not understand the face-attributes and pitches of emacs all too well. It seems this configuration works fine, but I might have to revisit this at some point in the future.
-;; Change the user-emacs-directory to keep unwanted things out of ~/.emacs.d
-(setq user-emacs-directory (expand-file-name "~/.cache/emacs/")
- url-history-file (expand-file-name "url/history" user-emacs-directory))
+(dolist (face '(default fixed-pitch))
+ (set-face-attribute face nil
+ :font "FiraCode Nerd Font Mono"))
+(add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono"))
-;; Use no-littering to automatically set common paths to the new user-emacs-directory
-(use-package no-littering)
-(setq custom-file (make-temp-file "emacs-custom-"))
-(load custom-file t)
+(set-face-attribute 'default nil :height 100)
+(set-face-attribute 'fixed-pitch nil :height 1.0)
+
+(set-face-attribute 'variable-pitch nil
+ :family "IBM Plex Sans"
+ :weight 'regular
+ :height 1.06)
+
+;; these settings used to be in custom.el
-
-
4.2.5. Move backup files to another location
-
+
+
4.3.9. Theme
+
-Many people dislike the Emacs backup files; I do enjoy them, but have to admit that they clutter the filesystem a little too much. Also, I rarely need to access these over different sessions. Hence I move them to /tmp
- if Emacs unexpectedly crashes, the files can be recovered, but the backup files will not gather everywhere and will be deleted upon shutdown.
+I have grown to love the doom-citylights
theme and have modeled my whole system after it. Also solaire-mode is a nice mode that inverts the alt-faces with the normal faces for specific 'minor' buffers (like Help-buffers).
-(let ((backup-dir "~/tmp/emacs/backups")
- (auto-saves-dir "~/tmp/emacs/auto-saves/"))
- (dolist (dir (list backup-dir auto-saves-dir))
- (when (not (file-directory-p dir))
- (make-directory dir t)))
- (setq backup-directory-alist `(("." . ,backup-dir))
- auto-save-file-name-transforms `((".*" ,auto-saves-dir t))
- auto-save-list-file-prefix (concat auto-saves-dir ".saves-")
- tramp-backup-directory-alist `((".*" . ,backup-dir))
- tramp-auto-save-directory auto-saves-dir))
+(use-package solaire-mode
+ :custom
+ (solaire-global-mode +1))
-(setq backup-by-copying t ; Don't delink hardlinks
- delete-old-versions t ; Clean up the backups
- version-control t ; Use version numbers on backups,
- kept-new-versions 5 ; keep some new versions
- kept-old-versions 2) ; and some old ones, too
+(use-package doom-themes
+ :hook
+ (server-after-make-frame . (lambda () (load-theme
+ 'doom-city-lights t)))
+ :config
+ (load-theme 'doom-city-lights t)
+ (doom-themes-treemacs-config)
+ (doom-themes-org-config))
-
-
-
4.3. General init.el setup + UI
-
+
+
4.3.10. Icons
+
-In this general section I have settings that I either consider to be integral to my experience when using emacs or have no other section that I feel they belong to.
+This section loads the base icons used in my configuration. I am using nerd-icons
over all-the-icons
since the former seems to have more integrations with different packages than the latter.
-
-
-
4.3.1. General setup
-
+
-Here I set up some things that are too minor to put under other categories.
+Used in:
-- Firstly we disable to having to type `yes` and `no` and switch it to `y` and `n`.
-- We also enable the marking of trailing whitespaces.
-- Also, make emacs highlight the current line globally
-- Emacs defaults to pausing all display redrawing on any input. This may have been useful previously, but is not necessary nowadays.
-- I also disable the suspend-frame function, as I never use it and it is quite confusing when accidentally hitting the keys for it.
+- Vertico and friends
+- IN USE Corfu
-;; use UTF-8 everywhere
-(set-language-environment "UTF-8")
-
-;; set default font size
-(defvar swarsel/default-font-size 130)
-(setq swarsel-standard-font "FiraCode Nerd Font Mono"
- swarsel-alt-font "FiraCode Nerd Font Mono")
-
-;; (defalias 'yes-or-no-p 'y-or-n-p)
-;;(setq-default show-trailing-whitespace t)
-(add-hook 'before-save-hook 'delete-trailing-whitespace)
-(global-hl-line-mode 1)
-;; (setq redisplay-dont-pause t) ;; obsolete
-(setq blink-cursor-mode nil) ;; blink-cursor is an unexpected source of slowdown
-(global-subword-mode 1) ; Iterate through CamelCase words
-(setq blink-matching-paren nil) ;; this makes the cursor jump around annoyingly
-(delete-selection-mode 1)
-(setq vc-follow-symlinks t)
-(setq require-final-newline t)
-(winner-mode 1)
-(setq load-prefer-newer t)
-
-(setq undo-limit 80000000
- evil-want-fine-undo t
- auto-save-default t
- password-cache-expiry nil
- )
-(setq browse-url-browser-function 'browse-url-firefox)
-;; disable a keybind that does more harm than good
-(global-set-key [remap suspend-frame]
- (lambda ()
- (interactive)
- (message "This keybinding is disabled (was 'suspend-frame')")))
-
-(setq visible-bell nil)
-(setq initial-major-mode 'fundamental-mode
- initial-scratch-message nil)
-
-(add-hook 'prog-mode-hook 'display-line-numbers-mode)
-(add-hook 'text-mode-hook 'display-line-numbers-mode)
-(global-visual-line-mode 1)
+(use-package nerd-icons)
-
-
4.3.2. Mark all themes as safe
-
+
+
4.3.11. Variable Pitch Mode
+
-Normally when switching themes in emacs, the user will be warned that themes can run malicious code. I only run one theme really and deem it safe. It is however annoying to be asked this on every new system and it also creates lines in custom.el to answer that query, so here I declare all themes as safe.
+This minor mode allows mixing fixed and variable pitch fonts within the same buffer.
-(setq custom-safe-themes t)
+(use-package mixed-pitch
+ :custom
+ (mixed-pitch-set-height nil)
+ (mixed-pitch-variable-pitch-cursor nil)
+ :hook
+ (text-mode . mixed-pitch-mode))
+
-
-
4.3.3. Show less compilation warnings
-
+
+
4.3.12. Modeline
+
-When Emacs compiles stuff, it often shows a bunch of warnings that I do not need to deal with. Here we silence those. Some will be disabled completely, and some only when we have native compilation available (which should be most of the time, however).
+Here I set up the modeline with some information that I find useful. Specficially I am using the doom modeline. Most informations I disable for it, except for the cursor information (row + column) as well as a widget for mu4e
and git information.
-
-
-(setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
-;; Make native compilation silent and prune its cache.
-(when (native-comp-available-p)
- (setq native-comp-async-report-warnings-errors 'silent) ; Emacs 28 with native compilation
- (setq native-compile-prune-cache t)) ; Emacs 29
+
+
+(use-package doom-modeline
+ :init
+ (doom-modeline-mode)
+ (column-number-mode)
+ :custom
+ ((doom-modeline-height 22)
+ (doom-modeline-indent-info nil)
+ (doom-modeline-buffer-encoding nil)))
+
-
-
4.3.4. Indentation
-
+
+
4.3.13. Helper Modes
+
+
+
+- Vertico, Orderless, Marginalia, Consult, Embark
+
-Here I define several options related to indentation; I first make it so that only whitespace will be used instead of tab characters for indentation, and I also set a small standard indent.
+This set of packages uses the default emacs completion framework and works together to provide a very nice user experience:
-
-We set tab-always-indent
to 'complete
in order to indent first and then do completion if there are any. Also we make it so that python will not complain about missing indentation info.
-
+
+- Vertico simply provides a vertically stacking completion
+- Marginalia adds more information to completion results
+- Orderless allows for fuzzy matching
+- Consult provides better implementations for several user functions, e.g.
consult-line
or consult-outline
+- Embark allows acting on the results in the minibuffer while the completion is still ongoing - this is extremely useful since it allows to, for example, read the documentation for several functions without closing the help search. It can also collect the results of a grep operation into a seperate buffer that edits the result in their original location.
+
-Lastly, I load the highlight-indent-guides
package. This adds a neat visual indicator of the indentation level, which is useful for languages like python.
+Nerd icons is originally enabled here: Icons
-
+
+
+- vertico
+
-(setq-default indent-tabs-mode nil
- tab-width 2)
-
-(setq tab-always-indent 'complete)
-(setq python-indent-guess-indent-offset-verbose nil)
+(setq read-buffer-completion-ignore-case t
+ read-file-name-completion-ignore-case t
+ completion-ignore-case t)
-(use-package highlight-indent-guides
- :hook (prog-mode . highlight-indent-guides-mode)
+(use-package vertico
+ :custom
+ (vertico-scroll-margin 0)
+ (vertico-count 10)
+ (vertico-resize t)
+ (vertico-cycle t)
:init
- (setq highlight-indent-guides-method 'column)
- (setq highlight-indent-guides-responsive 'top)
- )
-
-(with-eval-after-load 'highlight-indent-guides
- (set-face-attribute 'highlight-indent-guides-even-face nil :background "gray10")
- (set-face-attribute 'highlight-indent-guides-odd-face nil :background "gray20")
- (set-face-attribute 'highlight-indent-guides-stack-even-face nil :background "gray40")
- (set-face-attribute 'highlight-indent-guides-stack-odd-face nil :background "gray50"))
+ (vertico-mode)
+ (vertico-mouse-mode))
-
-
-
4.3.5. Scrolling
-
+
+
- vertico-directory
+
-By default, emacs scrolls half a page when reaching the bottom of the buffer. This is extremely annoying. This sets up more granular scrolling that allows scrolling with a mouse wheel or the two-finger touchscreen gesture. This now also works in buffers with a very small frame.
+This package allows for Ido
-like directory navigation.
-
-(setq mouse-wheel-scroll-amount
- '(1
- ((shift) . 5)
- ((meta) . 0.5)
- ((control) . text-scale))
- mouse-drag-copy-region nil
- make-pointer-invisible t
- mouse-wheel-progressive-speed t
- mouse-wheel-follow-mouse t)
-
-(setq-default scroll-preserve-screen-position t
- scroll-conservatively 1
- scroll-margin 0
- next-screen-context-lines 0)
-
-(pixel-scroll-precision-mode 1)
+(use-package vertico-directory
+ :ensure nil
+ :after vertico
+ :bind (:map vertico-map
+ ("RET" . vertico-directory-enter)
+ ("C-DEL" . vertico-directory-delete-word)
+ ("DEL" . vertico-directory-delete-char))
+ ;; Tidy shadowed file names
+ :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
-
-
-
4.3.6. Evil
-
-
-
-- General evil
-
-
-This setups up evil, which brings vim-like keybindings to emacs. In the same location, I also unbind the C-z
key (I am very unhappy with this implementation, but it is the only thing that works consistently so far) to make it available for cape later.
-
-
+
+
- orderless
+
-Also, I setup initial modes for several major-modes depending on what I deem fit.
+The completion styles that I chose here can possibly still be improved. I need to spend more time on this.
-;; Emulate vim in emacs
-(use-package evil
- :init
- (setq evil-want-integration t) ; loads evil
- (setq evil-want-keybinding nil) ; loads "helpful bindings" for other modes
- (setq evil-want-C-u-scroll t) ; scrolling using C-u
- (setq evil-want-C-i-jump nil) ; jumping with C-i
- (setq evil-want-Y-yank-to-eol t) ; give Y some utility
- (setq evil-shift-width 2) ; uniform indent
- (setq evil-respect-visual-line-mode t) ; i am torn on this one
- (setq evil-split-window-below t)
- (setq evil-vsplit-window-right t)
- :config
- (evil-mode 1)
- (define-key evil-normal-state-map (kbd "C-z") nil)
- (define-key evil-insert-state-map (kbd "C-z") nil)
- (define-key evil-visual-state-map (kbd "C-z") nil)
- (define-key evil-motion-state-map (kbd "C-z") nil)
- (define-key evil-operator-state-map (kbd "C-z") nil)
- (define-key evil-replace-state-map (kbd "C-z") nil)
- (define-key global-map (kbd "C-z") nil)
- (evil-set-undo-system 'undo-tree)
-
- ;; Don't use evil-mode in these contexts, or use it in a specific mode
- (evil-set-initial-state 'messages-buffer-mode 'emacs)
- (evil-set-initial-state 'dashboard-mode 'emacs)
- (evil-set-initial-state 'dired-mode 'emacs)
- (evil-set-initial-state 'cfw:details-mode 'emacs)
- (evil-set-initial-state 'Custom-mode 'emacs) ; god knows why this mode is in uppercase
- (evil-set-initial-state 'mu4e-headers-mode 'normal)
- (evil-set-initial-state 'python-inferior-mode 'normal)
- (add-hook 'org-capture-mode-hook 'evil-insert-state)
- (add-to-list 'evil-buffer-regexps '("COMMIT_EDITMSG" . insert)))
+(use-package orderless
+ :custom
+ (completion-styles '(orderless flex basic))
+ (completion-category-overrides '((file (styles . (partial-completion)))
+ (eglot (styles orderless)))))
-
- evil-collection
-
+
- consult
+
-This gives support for many different modes, and works beautifully out of the box.
+The big winner here are the convenient keybinds being setup here for general use. Also, I setup vim-navigation for minibuffer completions. consult-buffer
is set twice because I am still used to that weird C-M-j
command that I chose for ivy-switch-buffer
when I first started using Emacs. I want to move to the other command but for now it is not feasible to delete the other one.
-(use-package evil-collection
- :after evil
+(use-package consult
:config
- (evil-collection-init)
- (setq forge-add-default-bindings nil))
+ (setq consult-fontify-max-size 1024)
+ :bind
+ (("C-x b" . consult-buffer)
+ ("C-c <C-m>" . consult-global-mark)
+ ("C-c C-a" . consult-org-agenda)
+ ("C-x O" . consult-org-heading)
+ ("C-M-j" . consult-buffer)
+ ("C-s" . consult-line)
+ ("M-g M-g" . consult-goto-line)
+ ("M-g i" . consult-imenu)
+ ("M-s M-s" . consult-line-multi)
+ :map minibuffer-local-map
+ ("C-j" . next-line)
+ ("C-k" . previous-line)))
+
-
- evil-snipe
-
+
- embark
+
-This package changes the char-search commands like f
by showing the results in a more visual manner. It also gives a 2-character search using s
and S
.
+I have stripped down the embark keybinds heavily. It is very useful to me even in it's current state, but it quickly becomes overwhelming. embark-dwim
acts on a candidate without closing the minibuffer, which is very useful. embark-act
lets the user choose from all actions, but has an overwhelming interface.
-
;; enables 2-char inline search
- (use-package evil-snipe
- :after evil
- :demand
- :config
- (evil-snipe-mode +1)
- ;; replace 1-char searches (f&t) with this better UI
- (evil-snipe-override-mode +1))
+
+(use-package embark
+ :bind
+ (("C-." . embark-act)
+ ("M-." . embark-dwim)
+ ("C-h B" . embark-bindings)
+ ("C-c c" . embark-collect))
+ :custom
+ (prefix-help-command #'embark-prefix-help-command)
+ (embark-quit-after-action '((t . nil)))
+ :config
+ (add-to-list 'display-buffer-alist
+ '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
+ nil
+ (window-parameters (mode-line-format . none)))))
+
-
- evil-cleverparens
-
+
- embark-consult
+
-This helps keeping parentheses balanced which is useful when writing in languages like Elisp. I do not activate this by default, as most languages do not profit from this enough in my eyes.
+Provides previews for embark.
-
;; for parentheses-heavy languades modify evil commands to keep balance of parantheses
-(use-package evil-cleverparens)
-
+
+(use-package embark-consult
+ :after (embark consult)
+ :demand t ; only necessary if you have the hook below
+ ;; if you want to have consult previews as you move around an
+ ;; auto-updating embark collect buffer
+ :hook
+ (embark-collect-mode . consult-preview-at-point-mode))
-
- evil-surround
-
+
- marginalia
+
-This minor-mode adds functionality for doing better surround-commands; for example ci[
will let you change the word within square brackets.
+I set the annotation-mode of marginalia to heavy
. This gives even more information on the stuff that you are looking at. One thing I am missing from ivy is the highlighting on mode
-commands based on the current state of the mode. Also, I do not understand all the shorthands used by marginalia yet.
-
-;; enables surrounding text with S
-(use-package evil-surround
- :config
- (global-evil-surround-mode 1))
+(use-package marginalia
+ :after vertico
+ :init
+ (marginalia-mode)
+ (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))
-
-
-
-
4.3.7. ispell
-
+
- nerd-icons-completion
+
-This should setup a wordlist that can be used as a dictionary. However, for some reason this does not work, and I will need to further investigate this issue.
+As stated above, this simply provides nerd-icons to the completion framework.
-;; set the NixOS wordlist by hand
-(setq ispell-alternate-dictionary "/nix/store/gjmvnbs97cnw19wnqh9m075cdbhy8r8g-wordlist-WORDLIST")
+(use-package nerd-icons-completion
+ :after (marginalia nerd-icons)
+ :hook (marginalia-mode . nerd-icons-completion-marginalia-setup)
+ :init
+ (nerd-icons-completion-mode))
+
-
-
-
4.3.8. Font Configuration
-
+
+
+
+
- Helpful + which-key: Better help defaults
+
-Here I define my fonts to be used. Honestly I do not understand the face-attributes and pitches of emacs all too well. It seems this configuration works fine, but I might have to revisit this at some point in the future.
+This pair of packages provides information on keybinds in addition to function names, which makes it easier to remember keybinds (which-key
). The helpful
package provides a better Help
framework for Emacs. For some reason, the Help windows are always being focused by the cursor even though I have set help-window-select
to nil. I do not understand why.
-(dolist (face '(default fixed-pitch))
- (set-face-attribute face nil
- :font "FiraCode Nerd Font Mono"))
-(add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono"))
-
-(set-face-attribute 'default nil :height 100)
-(set-face-attribute 'fixed-pitch nil :height 1.0)
-
-(set-face-attribute 'variable-pitch nil
- :family "IBM Plex Sans"
- :weight 'regular
- :height 1.06)
-
-;; these settings used to be in custom.el
+(use-package which-key
+ :init (which-key-mode)
+ :diminish which-key-mode
+ :config
+ (setq which-key-idle-delay 0.3))
+(use-package helpful
+ :bind
+ (("C-h f" . helpful-callable)
+ ("C-h v" . helpful-variable)
+ ("C-h k" . helpful-key)
+ ("C-h C-." . helpful-at-point))
+ :config
+ (setq help-window-select nil))
+
+
-
-
4.3.9. Theme
-
+
+
4.3.14. Ligatures
+
-I have grown to love the doom-citylights
theme and have modeled my whole system after it. Also solaire-mode is a nice mode that inverts the alt-faces with the normal faces for specific 'minor' buffers (like Help-buffers).
+Personally, I think ligatures are fancy. With this mode, they stay 'cursorable'. However, I do not need them in all modes, so I only use them in programming modes.
-(use-package solaire-mode
- :custom
- (solaire-global-mode +1))
-
-(use-package doom-themes
- :hook
- (server-after-make-frame . (lambda () (load-theme
- 'doom-city-lights t)))
+(use-package ligature
+ :init
+ (global-ligature-mode t)
:config
- (load-theme 'doom-city-lights t)
- (doom-themes-treemacs-config)
- (doom-themes-org-config))
+ (ligature-set-ligatures 'prog-mode
+ '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
+ ":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
+ "!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
+ "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
+ "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
+ "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
+ "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
+ "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
+ ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
+ "<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
+ "##" "#(" "#?" "#_" "%%" ".=" ".." ".?" "+>" "++" "?:" "?="
+ "?." "??" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)" "\\\\"
+ "://" ";;")))
-
-
4.3.10. Icons
-
+
+
4.3.15. Popup (popper) + Shackle Buffers
+
-This section loads the base icons used in my configuration. I am using nerd-icons
over all-the-icons
since the former seems to have more integrations with different packages than the latter.
+The popper package allows to declare different buffers as 'popup-type', which sort of acts like a scratchpad. It can be toggled at any time using popper-toggle
and the resulting frame can be freely customized (with shackle
) to a certain size. It is also possible to prevent a buffer from appearing - I do this for example to the *Warnings*
buffer, since usually I am not interested in it's output.
-Used in:
+popper-echo-mode
shows all buffers that are currently stored as a popup in the echo area when a popup is opened - this is useful since you can cycle between all popup buffers.
-
-(use-package nerd-icons)
+(use-package popper
+ :bind (("M-[" . popper-toggle))
+ :init
+ (setq popper-reference-buffers
+ '("\\*Messages\\*"
+ ("\\*Warnings\\*" . hide)
+ "Output\\*$"
+ "\\*Async Shell Command\\*"
+ "\\*Async-native-compile-log\\*"
+ help-mode
+ helpful-mode
+ "*Occur*"
+ "*scratch*"
+ "*julia*"
+ "*Python*"
+ "*rustic-compilation*"
+ "*cargo-run*"
+ ;; ("*tex-shell*" . hide)
+ (compilation-mode . hide)))
+ (popper-mode +1)
+ (popper-echo-mode +1))
+
+(use-package shackle
+ :config
+ (setq shackle-rules '(("*Messages*" :select t :popup t :align right :size 0.3)
+ ("*Warnings*" :ignore t :popup t :align right :size 0.3)
+ ("*Occur*" :select t :popup t :align below :size 0.2)
+ ("*scratch*" :select t :popup t :align below :size 0.2)
+ ("*Python*" :select t :popup t :align below :size 0.2)
+ ("*rustic-compilation*" :select t :popup t :align below :size 0.4)
+ ("*cargo-run*" :select t :popup t :align below :size 0.2)
+ ("*tex-shell*" :ignore t :popup t :align below :size 0.2)
+ (helpful-mode :select t :popup t :align right :size 0.35)
+ (help-mode :select t :popup t :align right :size 0.4)))
+ (shackle-mode 1))
-
-
4.3.11. Variable Pitch Mode
-
+
+
4.3.16. Indicate first and last line of buffer
+
-This minor mode allows mixing fixed and variable pitch fonts within the same buffer.
+This places little angled indicators on the fringe of a window which indicate buffer boundaries. This is not super useful, but makes use of a space that I want to keep for aesthetic reasons anyways and makes it a bit more useful in the process.
-(use-package mixed-pitch
- :custom
- (mixed-pitch-set-height nil)
- (mixed-pitch-variable-pitch-cursor nil)
- :hook
- (text-mode . mixed-pitch-mode))
-
+(setq-default indicate-buffer-boundaries t)
-
-
4.3.12. Modeline
-
+
+
4.3.17. Authentication
+
-Here I set up the modeline with some information that I find useful. Specficially I am using the doom modeline. Most informations I disable for it, except for the cursor information (row + column) as well as a widget for mu4e
and git information.
+This defines the authentication sources used by org-calfw
(Calendar) and Forge.
-(use-package doom-modeline
- :init
- (doom-modeline-mode)
- (column-number-mode)
- :custom
- ((doom-modeline-height 22)
- (doom-modeline-indent-info nil)
- (doom-modeline-buffer-encoding nil)))
-
+(setq auth-sources '( "~/.emacs.d/.caldav" "~/.emacs.d/.authinfo.gpg")
+ auth-source-cache-expiry nil) ; default is 2h
-
-
4.3.13. Helper Modes
-
-
-- Vertico, Orderless, Marginalia, Consult, Embark
-
+
+
4.4. Modules
+
-This set of packages uses the default emacs completion framework and works together to provide a very nice user experience:
+This section houses all configuration bits that are related to a specific package that is not fundamental to my Emacs experience.
-
-- Vertico simply provides a vertically stacking completion
-- Marginalia adds more information to completion results
-- Orderless allows for fuzzy matching
-- Consult provides better implementations for several user functions, e.g.
consult-line
or consult-outline
-- Embark allows acting on the results in the minibuffer while the completion is still ongoing - this is extremely useful since it allows to, for example, read the documentation for several functions without closing the help search. It can also collect the results of a grep operation into a seperate buffer that edits the result in their original location.
-
-
-Nerd icons is originally enabled here: Icons
+At some point this will receive further sorting, but for now this is good enough.
-
-- vertico
-
-
-
-(setq read-buffer-completion-ignore-case t
- read-file-name-completion-ignore-case t
- completion-ignore-case t)
-
-(use-package vertico
- :custom
- (vertico-scroll-margin 0)
- (vertico-count 10)
- (vertico-resize t)
- (vertico-cycle t)
- :init
- (vertico-mode)
- (vertico-mouse-mode))
-
-
-
-
-- vertico-directory
-
+
+
4.4.1. Org Mode
+
-This package allows for Ido
-like directory navigation.
+org-mode is probably my most-used mode in Emcas. It acts as my organizer, config management tool and calender even.
-
-
(use-package vertico-directory
- :ensure nil
- :after vertico
- :bind (:map vertico-map
- ("RET" . vertico-directory-enter)
- ("C-DEL" . vertico-directory-delete-word)
- ("DEL" . vertico-directory-delete-char))
- ;; Tidy shadowed file names
- :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
-
-
-
+
+Note that nearly all headings within the Org-mode
heading are coded within the use-package
setup, so be very careful about moving stuff about here.
+
-
-
- orderless
-
+
+- General org-mode
+
-The completion styles that I chose here can possibly still be improved. I need to spend more time on this.
+This sets up the basic org-mode. I wrote a function to handle some of the initial org-mode behaviour in org-mode setup.
+
+This part of the configuration mostly makes some aesthetic changes, enables neat LaTeX and points Emacs to some files that it needs for org-mode
-(use-package orderless
- :custom
- (completion-styles '(orderless flex basic))
- (completion-category-overrides '((file (styles . (partial-completion)))
- (eglot (styles orderless)))))
+(use-package org
+ ;;:diminish (org-indent-mode)
+ :hook (org-mode . swarsel/org-mode-setup)
+ :bind
+ (("C-<tab>" . org-fold-outer)
+ ("C-c s" . org-store-link))
+ :config
+ (setq org-ellipsis " ⤵"
+ org-link-descriptive t
+ org-hide-emphasis-markers t)
+ (setq org-startup-folded t)
+ (setq org-support-shift-select t)
+
+ ;; (setq org-agenda-start-with-log-mode t)
+ ;; (setq org-log-done 'time)
+ ;; (setq org-log-into-drawer t)
+ (setq org-startup-with-inline-images t)
+ (setq org-image-actual-width nil)
+ (setq org-format-latex-options '(:foreground "White" :background default :scale 2.0 :html-foreground "Black" :html-background "Transparent" :html-scale 1.0 :matchers ("begin" "$1" "$" "$$" "\\(" "\\[")))
-- consult
-
+
- org-agenda
+
-The big winner here are the convenient keybinds being setup here for general use. Also, I setup vim-navigation for minibuffer completions. consult-buffer
is set twice because I am still used to that weird C-M-j
command that I chose for ivy-switch-buffer
when I first started using Emacs. I want to move to the other command but for now it is not feasible to delete the other one.
+Here I setup a plethora of keywords, keybinds and paths to give my org-agenda more power.
-(use-package consult
- :config
- (setq consult-fontify-max-size 1024)
- :bind
- (("C-x b" . consult-buffer)
- ("C-c <C-m>" . consult-global-mark)
- ("C-c C-a" . consult-org-agenda)
- ("C-x O" . consult-org-heading)
- ("C-M-j" . consult-buffer)
- ("C-s" . consult-line)
- ("M-g M-g" . consult-goto-line)
- ("M-g i" . consult-imenu)
- ("M-s M-s" . consult-line-multi)
- :map minibuffer-local-map
- ("C-j" . next-line)
- ("C-k" . previous-line)))
+(setq org-agenda-files '("/home/swarsel/Nextcloud/Org/Tasks.org"
+ "/home/swarsel/Nextcloud/Org/Archive.org"
+ "/home/swarsel/Nextcloud/Org/Anki.org"
+ "/home/swarsel/Calendars/leon_cal.org"))
+
+(setq org-refile-targets
+ '((swarsel-archive-org-file :maxlevel . 1)
+ (swarsel-anki-org-file :maxlevel . 1)
+ (swarsel-tasks-org-file :maxlevel . 1)))
+
+(setq org-todo-keywords
+ '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)")
+ (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)" "WAIT(w@/!)" "HOLD(h)" "|" "COMPLETED(c)" "CANC(k@)")))
+
+
+;; Configure custom agenda views
+(setq org-agenda-custom-commands
+ '(("d" "Dashboard"
+ ((agenda "" ((org-deadline-warning-days 7)))
+ (todo "NEXT"
+ ((org-agenda-overriding-header "Next Tasks")))
+ (tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects")))))
+
+ ("n" "Next Tasks"
+ ((todo "NEXT"
+ ((org-agenda-overriding-header "Next Tasks")))))
+
+ ("W" "Work Tasks" tags-todo "+work-email")
+
+
+ ("w" "Workflow Status"
+ ((todo "WAIT"
+ ((org-agenda-overriding-header "Waiting on External")
+ (org-agenda-files org-agenda-files)))
+ (todo "REVIEW"
+ ((org-agenda-overriding-header "In Review")
+ (org-agenda-files org-agenda-files)))
+ (todo "PLAN"
+ ((org-agenda-overriding-header "In Planning")
+ (org-agenda-todo-list-sublevels nil)
+ (org-agenda-files org-agenda-files)))
+ (todo "BACKLOG"
+ ((org-agenda-overriding-header "Project Backlog")
+ (org-agenda-todo-list-sublevels nil)
+ (org-agenda-files org-agenda-files)))
+ (todo "READY"
+ ((org-agenda-overriding-header "Ready for Work")
+ (org-agenda-files org-agenda-files)))
+ (todo "ACTIVE"
+ ((org-agenda-overriding-header "Active Projects")
+ (org-agenda-files org-agenda-files)))
+ (todo "COMPLETED"
+ ((org-agenda-overriding-header "Completed Projects")
+ (org-agenda-files org-agenda-files)))
+ (todo "CANC"
+ ((org-agenda-overriding-header "Cancelled Projects")
+ (org-agenda-files org-agenda-files)))))))
+
-
- embark
-
+
- org capture templates
+
-I have stripped down the embark keybinds heavily. It is very useful to me even in it's current state, but it quickly becomes overwhelming. embark-dwim
acts on a candidate without closing the minibuffer, which is very useful. embark-act
lets the user choose from all actions, but has an overwhelming interface.
+I wrote these capture templates to allow myself to quickly create Anki cards from within Emacs. I nearly never use this feature, but it cannot hurt to have.
-(use-package embark
- :bind
- (("C-." . embark-act)
- ("M-." . embark-dwim)
- ("C-h B" . embark-bindings)
- ("C-c c" . embark-collect))
- :custom
- (prefix-help-command #'embark-prefix-help-command)
- (embark-quit-after-action '((t . nil)))
- :config
- (add-to-list 'display-buffer-alist
- '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
- nil
- (window-parameters (mode-line-format . none)))))
+(setq org-capture-templates
+ `(
+ ("a" "Anki basic"
+ entry
+ (file+headline swarsel-org-anki-filepath "Dispatch")
+ (function swarsel-anki-make-template-string))
+ ("A" "Anki cloze"
+ entry
+ (file+headline org-swarsel-anki-file "Dispatch")
+ "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: Cloze\n:ANKI_DECK: 🦁 All::01 ❤️ Various::00 ✨ Allgemein\n:END:\n** Text\n%?\n** Extra\n")
+ ("t" "Tasks / Projects")
+ ("tt" "Task" entry (file+olp swarsel-org-tasks-filepath "Inbox")
+ "* TODO %?\n %U\n %a\n %i" :empty-lines 1)
+ ))
+)
-
- embark-consult
-
+
- Font Faces
+
-Provides previews for embark.
+Again, my understanding of the font-faces in Emacs is limited. This is mostly just tuned so that my org-files look acceptable.
-(use-package embark-consult
- :after (embark consult)
- :demand t ; only necessary if you have the hook below
- ;; if you want to have consult previews as you move around an
- ;; auto-updating embark collect buffer
- :hook
- (embark-collect-mode . consult-preview-at-point-mode))
+
+
+;; Set faces for heading levels
+(with-eval-after-load 'org-faces (dolist (face '((org-level-1 . 1.1)
+ (org-level-2 . 0.9)
+ (org-level-3 . 0.9)
+ (org-level-4 . 0.9)
+ (org-level-5 . 0.9)
+ (org-level-6 . 0.9)
+ (org-level-7 . 0.9)
+ (org-level-8 . 0.9)))
+ (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
+
+ ;; Ensure that anything that should be fixed-pitch in Org files appears that way
+ (set-face-attribute 'org-block nil :inherit 'fixed-pitch)
+ (set-face-attribute 'org-table nil :inherit 'fixed-pitch)
+ (set-face-attribute 'org-formula nil :inherit 'fixed-pitch)
+ (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch))
+ (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
+ (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
+ (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
+ (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch))
+
-
- marginalia
-
+
- org-appear
+
-I set the annotation-mode of marginalia to heavy
. This gives even more information on the stuff that you are looking at. One thing I am missing from ivy is the highlighting on mode
-commands based on the current state of the mode. Also, I do not understand all the shorthands used by marginalia yet.
+This package makes emphasis-markers appear when the cursor moves over them. Very useful as I enjoy the clean look of not always seeing them, but it is annoying not to be able to edit them properly.
-
(use-package marginalia
- :after vertico
+
+(use-package org-appear
+ :hook (org-mode . org-appear-mode)
:init
- (marginalia-mode)
- (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))
+ (setq org-appear-autolinks t)
+ (setq org-appear-autokeywords t)
+ (setq org-appear-autoentities t)
+ (setq org-appear-autosubmarkers t))
-
- nerd-icons-completion
-
+
- Centered org-mode Buffers
+
-As stated above, this simply provides nerd-icons to the completion framework.
+I like org-mode buffers to be centered, as I do not find that enormous lines are of big use.
+
+
+
+Function definition in: Visual-fill column
-(use-package nerd-icons-completion
- :after (marginalia nerd-icons)
- :hook (marginalia-mode . nerd-icons-completion-marginalia-setup)
- :init
- (nerd-icons-completion-mode))
-
+(use-package visual-fill-column
+ :hook (org-mode . swarsel/org-mode-visual-fill))
-
-
-
- Helpful + which-key: Better help defaults
-
+
- Fix headings not folding sometimes
+
-This pair of packages provides information on keybinds in addition to function names, which makes it easier to remember keybinds (which-key
). The helpful
package provides a better Help
framework for Emacs. For some reason, the Help windows are always being focused by the cursor even though I have set help-window-select
to nil. I do not understand why.
+There is a weird bug in org-mode that makes it so that headings were not folding correctly sometimes. This setting seems to fix it.
-(use-package which-key
- :init (which-key-mode)
- :diminish which-key-mode
- :config
- (setq which-key-idle-delay 0.3))
+(setq org-fold-core-style 'overlays)
-(use-package helpful
- :bind
- (("C-h f" . helpful-callable)
- ("C-h v" . helpful-variable)
- ("C-h k" . helpful-key)
- ("C-h C-." . helpful-at-point))
- :config
- (setq help-window-select nil))
-
-
-
-
4.3.14. Ligatures
-
+
- Babel
+
-Personally, I think ligatures are fancy. With this mode, they stay 'cursorable'. However, I do not need them in all modes, so I only use them in programming modes.
+org-babel allows to run blocks in other programming languages within an org-mode buffer, similar to what e.g. jupyterhub offers for python.
+
+
+
+It also offers a very useful utility of exporting org-mode buffers to different formats; the feature I enjoy most is what makes this file useful: the tangling functionality.
+
+
+- Language Configuration
+
+
+- This configures the languages that babel recognizes.
+
-(use-package ligature
- :init
- (global-ligature-mode t)
- :config
- (ligature-set-ligatures 'prog-mode
- '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
- ":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
- "!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
- "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
- "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
- "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
- "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
- "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
- ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
- "<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
- "##" "#(" "#?" "#_" "%%" ".=" ".." ".?" "+>" "++" "?:" "?="
- "?." "??" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)" "\\\\"
- "://" ";;")))
+(org-babel-do-load-languages
+ 'org-babel-load-languages
+ '((emacs-lisp . t)
+ (python . t)
+ (js . t)
+ (shell . t)
+ ))
+
+(push '("conf-unix" . conf-unix) org-src-lang-modes)
-
-
-
4.3.15. Popup (popper) + Shackle Buffers
-
-
-The popper package allows to declare different buffers as 'popup-type', which sort of acts like a scratchpad. It can be toggled at any time using popper-toggle
and the resulting frame can be freely customized (with shackle
) to a certain size. It is also possible to prevent a buffer from appearing - I do this for example to the *Warnings*
buffer, since usually I am not interested in it's output.
+
+
- old easy structure templates
+
+
+
+org 9.2 changed the way structure templates work. This brings back the old way it worked.
-popper-echo-mode
shows all buffers that are currently stored as a popup in the echo area when a popup is opened - this is useful since you can cycle between all popup buffers.
+Usage: Type <
, followed by one of the below keywords and press RET
. The corresponding source block should appear.
-(use-package popper
- :bind (("M-[" . popper-toggle))
- :init
- (setq popper-reference-buffers
- '("\\*Messages\\*"
- ("\\*Warnings\\*" . hide)
- "Output\\*$"
- "\\*Async Shell Command\\*"
- "\\*Async-native-compile-log\\*"
- help-mode
- helpful-mode
- "*Occur*"
- "*scratch*"
- "*julia*"
- "*Python*"
- "*rustic-compilation*"
- "*cargo-run*"
- ;; ("*tex-shell*" . hide)
- (compilation-mode . hide)))
- (popper-mode +1)
- (popper-echo-mode +1))
-
-(use-package shackle
- :config
- (setq shackle-rules '(("*Messages*" :select t :popup t :align right :size 0.3)
- ("*Warnings*" :ignore t :popup t :align right :size 0.3)
- ("*Occur*" :select t :popup t :align below :size 0.2)
- ("*scratch*" :select t :popup t :align below :size 0.2)
- ("*Python*" :select t :popup t :align below :size 0.2)
- ("*rustic-compilation*" :select t :popup t :align below :size 0.4)
- ("*cargo-run*" :select t :popup t :align below :size 0.2)
- ("*tex-shell*" :ignore t :popup t :align below :size 0.2)
- (helpful-mode :select t :popup t :align right :size 0.35)
- (help-mode :select t :popup t :align right :size 0.4)))
- (shackle-mode 1))
+(require 'org-tempo)
+(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
+(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
+(add-to-list 'org-structure-template-alist '("py" . "src python :results output"))
+(add-to-list 'org-structure-template-alist '("nix" . "src nix :tangle"))
+
+
-
-
-
-
4.3.16. Indicate first and last line of buffer
-
+
+
+
+
- aucTex
+
-This places little angled indicators on the fringe of a window which indicate buffer boundaries. This is not super useful, but makes use of a space that I want to keep for aesthetic reasons anyways and makes it a bit more useful in the process.
+This provides several utilities for LaTeX in Emacs, including many completions and convenience functions for math-mode.
-(setq-default indicate-buffer-boundaries t)
+(use-package auctex)
+(setq TeX-auto-save t)
+(setq TeX-save-query nil)
+(setq TeX-parse-self t)
+ (setq-default TeX-master nil)
+
+(add-hook 'LaTeX-mode-hook 'visual-line-mode)
+(add-hook 'LaTeX-mode-hook 'flyspell-mode)
+(add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)
+(add-hook 'LaTeX-mode-hook 'reftex-mode)
+(setq LaTeX-electric-left-right-brace t)
+(setq font-latex-fontify-script nil)
+(setq TeX-electric-sub-and-superscript t)
+ ;; (setq reftex-plug-into-AUCTeX t)
-
-
-
4.3.17. Authentication
-
+
+
- org-download
+
-This defines the authentication sources used by org-calfw
(Calendar) and Forge.
+This package allows to download and copy images into org-mode buffers. Sadly it does not work in a very stable manner - if you copy images that are also links to another page (like is often the case in a Google image search), Emacs might crash from this.
-(setq auth-sources '( "~/.emacs.d/.caldav" "~/.emacs.d/.authinfo.gpg")
- auth-source-cache-expiry nil) ; default is 2h
+(use-package org-download
+ :after org
+ :defer nil
+ :custom
+ (org-download-method 'directory)
+ (org-download-image-dir "./images")
+ (org-download-heading-lvl 0)
+ (org-download-timestamp "org_%Y%m%d-%H%M%S_")
+ ;;(org-image-actual-width 500)
+ (org-download-screenshot-method "grim -g \"$(slurp)\" %s")
+ :bind
+ ("C-M-y" . org-download-screenshot)
+ :config
+ (require 'org-download))
-
-
-
-
4.4. Modules
-
+
+
- org-fragtog
+
-This section houses all configuration bits that are related to a specific package that is not fundamental to my Emacs experience.
+This package automatically toggles LaTeX-fragments in org-files. It seems to also work in markdown-files which is a nice addition, as my Obsidian notes are held in markdown.
-
-At some point this will receive further sorting, but for now this is good enough.
-
-
-
-
4.4.1. Org Mode
-
-
-org-mode is probably my most-used mode in Emcas. It acts as my organizer, config management tool and calender even.
-
+
+
+(use-package org-fragtog)
+(add-hook 'org-mode-hook 'org-fragtog-mode)
+(add-hook 'markdown-mode-hook 'org-fragtog-mode)
-
-Note that nearly all headings within the Org-mode
heading are coded within the use-package
setup, so be very careful about moving stuff about here.
-
+
-
-- General org-mode
-
+
+
+- org-modern
+
-This sets up the basic org-mode. I wrote a function to handle some of the initial org-mode behaviour in org-mode setup.
-
-This part of the configuration mostly makes some aesthetic changes, enables neat LaTeX and points Emacs to some files that it needs for org-mode
+This just makes org-mode a little bit more beautiful, mostly by making the begin_src
and end_src
tags in source-blocks turn into more beautiful icons, as well as hiding #+
tags before them, as well as in the properties section of the file.
-(use-package org
- ;;:diminish (org-indent-mode)
- :hook (org-mode . swarsel/org-mode-setup)
- :bind
- (("C-<tab>" . org-fold-outer)
- ("C-c s" . org-store-link))
- :config
- (setq org-ellipsis " ⤵"
- org-link-descriptive t
- org-hide-emphasis-markers t)
- (setq org-startup-folded t)
- (setq org-support-shift-select t)
-
- ;; (setq org-agenda-start-with-log-mode t)
- ;; (setq org-log-done 'time)
- ;; (setq org-log-into-drawer t)
- (setq org-startup-with-inline-images t)
- (setq org-image-actual-width nil)
- (setq org-format-latex-options '(:foreground "White" :background default :scale 2.0 :html-foreground "Black" :html-background "Transparent" :html-scale 1.0 :matchers ("begin" "$1" "$" "$$" "\\(" "\\[")))
+(use-package org-modern
+ :config (setq org-modern-block-name
+ '((t . t)
+ ("src" "»" "∥")))
+ :hook (org-mode . org-modern-mode))
-- org-agenda
-
+
- Presentations
+
-Here I setup a plethora of keywords, keybinds and paths to give my org-agenda more power.
+Recently I have grown fond of holding presentations using Emacs :)
-(setq org-agenda-files '("/home/swarsel/Nextcloud/Org/Tasks.org"
- "/home/swarsel/Nextcloud/Org/Archive.org"
- "/home/swarsel/Nextcloud/Org/Anki.org"
- "/home/swarsel/Calendars/leon_cal.org"))
+ (use-package org-present
+ :bind (:map org-present-mode-keymap
+ ("q" . org-present-quit)
+ ("<left>" . swarsel/org-present-prev)
+ ("<up>" . 'ignore)
+ ("<down>" . 'ignore)
+ ("<right>" . swarsel/org-present-next))
+ :hook ((org-present-mode . swarsel/org-present-start)
+ (org-present-mode-quit . swarsel/org-present-end))
+ )
-(setq org-refile-targets
- '((swarsel-archive-org-file :maxlevel . 1)
- (swarsel-anki-org-file :maxlevel . 1)
- (swarsel-tasks-org-file :maxlevel . 1)))
-(setq org-todo-keywords
- '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)")
- (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)" "WAIT(w@/!)" "HOLD(h)" "|" "COMPLETED(c)" "CANC(k@)")))
+ (use-package hide-mode-line)
+
+ (defun swarsel/org-present-start ()
+ (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch)
+ (header-line (:height 4.0) variable-pitch)
+ (org-document-title (:height 1.75) org-document-title)
+ (org-code (:height 1.55) org-code)
+ (org-verbatim (:height 1.55) org-verbatim)
+ (org-block (:height 1.25) org-block)
+ (org-block-begin-line (:height 0.7) org-block)
+ ))
+ (dolist (face '((org-level-1 . 1.1)
+ (org-level-2 . 1.2)
+ (org-level-3 . 1.2)
+ (org-level-4 . 1.2)
+ (org-level-5 . 1.2)
+ (org-level-6 . 1.2)
+ (org-level-7 . 1.2)
+ (org-level-8 . 1.2)))
+ (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
+ (setq header-line-format " ")
+ (setq visual-fill-column-width 90)
+ (setq indicate-buffer-boundaries nil)
+ (setq inhibit-message nil)
+ (breadcrumb-mode 0)
+ (org-display-inline-images)
+ (global-hl-line-mode 0)
+ (display-line-numbers-mode 0)
+ (org-modern-mode 0)
+ (evil-insert-state 1)
+ (beginning-of-buffer)
+ (org-present-read-only)
+ ;; (org-present-hide-cursor)
+ (swarsel/org-present-slide)
+ )
-;; Configure custom agenda views
-(setq org-agenda-custom-commands
- '(("d" "Dashboard"
- ((agenda "" ((org-deadline-warning-days 7)))
- (todo "NEXT"
- ((org-agenda-overriding-header "Next Tasks")))
- (tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects")))))
+ (defun swarsel/org-present-end ()
+ (setq-local face-remapping-alist '((default variable-pitch default)))
+ (dolist (face '((org-level-1 . 1.1)
+ (org-level-2 . 0.9)
+ (org-level-3 . 0.9)
+ (org-level-4 . 0.9)
+ (org-level-5 . 0.9)
+ (org-level-6 . 0.9)
+ (org-level-7 . 0.9)
+ (org-level-8 . 0.9)))
+ (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
+ (setq header-line-format nil)
+ (setq visual-fill-column-width 150)
+ (setq indicate-buffer-boundaries t)
+ (setq inhibit-message nil)
+ (breadcrumb-mode 1)
+ (global-hl-line-mode 1)
+ (display-line-numbers-mode 1)
+ (org-remove-inline-images)
+ (org-modern-mode 1)
+ (evil-normal-state 1)
+ ;; (org-present-show-cursor)
+ )
- ("n" "Next Tasks"
- ((todo "NEXT"
- ((org-agenda-overriding-header "Next Tasks")))))
+ (defun swarsel/org-present-slide ()
+ (org-overview)
+ (org-show-entry)
+ (org-show-children)
+ )
- ("W" "Work Tasks" tags-todo "+work-email")
+ (defun swarsel/org-present-prev ()
+ (interactive)
+ (org-present-prev)
+ (swarsel/org-present-slide))
+ (defun swarsel/org-present-next ()
+ (interactive)
+ (unless (eobp)
+ (org-next-visible-heading 1)
+ (org-fold-show-entry))
+ (when (eobp)
+ (org-present-next)
+ (swarsel/org-present-slide)
+ ))
- ("w" "Workflow Status"
- ((todo "WAIT"
- ((org-agenda-overriding-header "Waiting on External")
- (org-agenda-files org-agenda-files)))
- (todo "REVIEW"
- ((org-agenda-overriding-header "In Review")
- (org-agenda-files org-agenda-files)))
- (todo "PLAN"
- ((org-agenda-overriding-header "In Planning")
- (org-agenda-todo-list-sublevels nil)
- (org-agenda-files org-agenda-files)))
- (todo "BACKLOG"
- ((org-agenda-overriding-header "Project Backlog")
- (org-agenda-todo-list-sublevels nil)
- (org-agenda-files org-agenda-files)))
- (todo "READY"
- ((org-agenda-overriding-header "Ready for Work")
- (org-agenda-files org-agenda-files)))
- (todo "ACTIVE"
- ((org-agenda-overriding-header "Active Projects")
- (org-agenda-files org-agenda-files)))
- (todo "COMPLETED"
- ((org-agenda-overriding-header "Completed Projects")
- (org-agenda-files org-agenda-files)))
- (todo "CANC"
- ((org-agenda-overriding-header "Cancelled Projects")
- (org-agenda-files org-agenda-files)))))))
+(defun clojure-leave-clojure-mode-function ()
+ )
+(add-hook 'buffer-list-update-hook #'clojure-leave-clojure-mode-function)
+ (add-hook 'org-present-mode-hook 'swarsel/org-present-start)
+ (add-hook 'org-present-mode-quit-hook 'swarsel/org-present-end)
+ (add-hook 'org-present-after-navigate-functions 'swarsel/org-present-slide)
-
- org capture templates
-
+
+
+
+
4.4.2. Nix Mode
+
-I wrote these capture templates to allow myself to quickly create Anki cards from within Emacs. I nearly never use this feature, but it cannot hurt to have.
+This adds a rudimentary nix-mode to Emacs. I have not really tried this out, as I am mostly editing nix-files in org-mode anyways.
-(setq org-capture-templates
- `(
- ("a" "Anki basic"
- entry
- (file+headline swarsel-org-anki-filepath "Dispatch")
- (function swarsel-anki-make-template-string))
+(use-package nix-mode
+ :mode "\\.nix\\'")
- ("A" "Anki cloze"
- entry
- (file+headline org-swarsel-anki-file "Dispatch")
- "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: Cloze\n:ANKI_DECK: 🦁 All::01 ❤️ Various::00 ✨ Allgemein\n:END:\n** Text\n%?\n** Extra\n")
- ("t" "Tasks / Projects")
- ("tt" "Task" entry (file+olp swarsel-org-tasks-filepath "Inbox")
- "* TODO %?\n %U\n %a\n %i" :empty-lines 1)
- ))
-)
-
-
- Font Faces
-
-
-Again, my understanding of the font-faces in Emacs is limited. This is mostly just tuned so that my org-files look acceptable.
-
-
+
+
+
4.4.3. Markdown Mode
+
+
+
+- Mode
+
+(setq markdown-command "pandoc")
+(use-package markdown-mode
+ :ensure t
+ :mode ("README\\.md\\'" . gfm-mode)
+ :init (setq markdown-command "multimarkdown")
+ :bind (:map markdown-mode-map
+ ("C-c C-e" . markdown-do)))
-;; Set faces for heading levels
-(with-eval-after-load 'org-faces (dolist (face '((org-level-1 . 1.1)
- (org-level-2 . 0.9)
- (org-level-3 . 0.9)
- (org-level-4 . 0.9)
- (org-level-5 . 0.9)
- (org-level-6 . 0.9)
- (org-level-7 . 0.9)
- (org-level-8 . 0.9)))
- (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
-
- ;; Ensure that anything that should be fixed-pitch in Org files appears that way
- (set-face-attribute 'org-block nil :inherit 'fixed-pitch)
- (set-face-attribute 'org-table nil :inherit 'fixed-pitch)
- (set-face-attribute 'org-formula nil :inherit 'fixed-pitch)
- (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch))
- (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
- (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
- (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
- (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch))
+
+
+
+
+- LaTeX in Markdown
+
+
+
+(add-hook 'markdown-mode-hook
+ (lambda ()
+ (local-set-key (kbd "C-c C-x C-l") 'org-latex-preview)
+ (local-set-key (kbd "C-c C-x C-u") 'markdown-toggle-url-hiding)
+ ))
-- org-appear
-
+
+
+
+
4.4.4. Olivetti
+
-This package makes emphasis-markers appear when the cursor moves over them. Very useful as I enjoy the clean look of not always seeing them, but it is annoying not to be able to edit them properly.
+Olivetti is a mode specialized for writing prose in Emacs. I went for a very simple setup with little distractions.
+
+
+
+This mode is not automatically activated anywhere because I only rarely need it.
-(use-package org-appear
- :hook (org-mode . org-appear-mode)
+(use-package olivetti
:init
- (setq org-appear-autolinks t)
- (setq org-appear-autokeywords t)
- (setq org-appear-autoentities t)
- (setq org-appear-autosubmarkers t))
+ (setq olivetti-body-width 100)
+ (setq olivetti-recall-visual-line-mode-entry-state t))
-
-
- Centered org-mode Buffers
-
-
-I like org-mode buffers to be centered, as I do not find that enormous lines are of big use.
-
-
+
+
+
4.4.5. darkroom
+
-Function definition in: Visual-fill column
+Darkroom is package that reduces all forms of distraction to a minimum - this can be useful when simply reading a file for example. For this mode I have increased the text scale by a large margin to make for comfortable reading
+This mode is not automatically activated anywhere because I only rarely need it.
-(use-package visual-fill-column
- :hook (org-mode . swarsel/org-mode-visual-fill))
+(use-package darkroom
+ :init
+ (setq darkroom-text-scale-increase 3))
-
-
- Fix headings not folding sometimes
-
+
+
+
4.4.6. Ripgrep
+
-There is a weird bug in org-mode that makes it so that headings were not folding correctly sometimes. This setting seems to fix it.
+This is the ripgrep command for Emacs.
-(setq org-fold-core-style 'overlays)
+(use-package rg)
-
-
- Babel
-
+
+
+
4.4.7. Tree-sitter
+
-org-babel allows to run blocks in other programming languages within an org-mode buffer, similar to what e.g. jupyterhub offers for python.
+Tree-sitter is a parsing library integrated into Emacs to provide better syntax highlighting and code analysis. It generates concrete syntax trees for source code, enabling more accurate and efficient text processing. Emacs' tree-sitter integration enhances language support, offering features like incremental parsing and precise syntax-aware editing. This improves the development experience by providing robust and dynamic syntax features, making it easier for me to navigate and manipulate code.
-It also offers a very useful utility of exporting org-mode buffers to different formats; the feature I enjoy most is what makes this file useful: the tangling functionality.
+In order to update the language grammars, run the next command below.
+
+
+
+(mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))
+
+
-
-- Language Configuration
-
-
-- This configures the languages that babel recognizes.
-
-
-
-(org-babel-do-load-languages
- 'org-babel-load-languages
- '((emacs-lisp . t)
- (python . t)
- (js . t)
- (shell . t)
- ))
+
+
+(use-package emacs
+ :ensure nil
+ :init
+ (setq treesit-language-source-alist
+ '((bash . ("https://github.com/tree-sitter/tree-sitter-bash"))
+ (c . ("https://github.com/tree-sitter/tree-sitter-c"))
+ (cmake . ("https://github.com/uyha/tree-sitter-cmake"))
+ (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp"))
+ (css . ("https://github.com/tree-sitter/tree-sitter-css"))
+ (elisp . ("https://github.com/Wilfred/tree-sitter-elisp"))
+ (go . ("https://github.com/tree-sitter/tree-sitter-go"))
+ (html . ("https://github.com/tree-sitter/tree-sitter-html"))
+ (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript"))
+ (json . ("https://github.com/tree-sitter/tree-sitter-json"))
+ (julia . ("https://github.com/tree-sitter/tree-sitter-julia"))
+ (latex . ("https://github.com/latex-lsp/tree-sitter-latex"))
+ (make . ("https://github.com/alemuller/tree-sitter-make"))
+ (markdown . ("https://github.com/ikatyang/tree-sitter-markdown"))
+ (R . ("https://github.com/r-lib/tree-sitter-r"))
+ (python . ("https://github.com/tree-sitter/tree-sitter-python"))
+ (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "typescript/src" "typescript"))
+ (rust . ("https://github.com/tree-sitter/tree-sitter-rust"))
+ (sql . ("https://github.com/m-novikov/tree-sitter-sql"))
+ (toml . ("https://github.com/tree-sitter/tree-sitter-toml"))
+ (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src"))
+ (yaml . ("https://github.com/ikatyang/tree-sitter-yaml"))))
+ )
+
+(use-package treesit-auto
+ :config
+ (global-treesit-auto-mode)
+ (setq treesit-auto-install 'prompt))
-(push '("conf-unix" . conf-unix) org-src-lang-modes)
-
-
- old easy structure templates
-
-
-
-org 9.2 changed the way structure templates work. This brings back the old way it worked.
-
-
-
-Usage: Type <
, followed by one of the below keywords and press RET
. The corresponding source block should appear.
-
-
+
+
+
4.4.8. direnv (envrc)
+
-(require 'org-tempo)
-(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
-(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
-(add-to-list 'org-structure-template-alist '("py" . "src python :results output"))
-(add-to-list 'org-structure-template-alist '("nix" . "src nix :tangle"))
+(use-package direnv
+ :custom (direnv-always-show-summary nil)
+ :config (direnv-mode))
-
-
-
-
-
-
- aucTex
-
+
+
+
+
4.4.9. avy
+
-This provides several utilities for LaTeX in Emacs, including many completions and convenience functions for math-mode.
+avy
provides the ability to search for any character on the screen (not only in the current buffer!) - I enjoy this utility a lot and use it possibly even more often than the native vim commands.
-(use-package auctex)
-(setq TeX-auto-save t)
-(setq TeX-save-query nil)
-(setq TeX-parse-self t)
- (setq-default TeX-master nil)
-
-(add-hook 'LaTeX-mode-hook 'visual-line-mode)
-(add-hook 'LaTeX-mode-hook 'flyspell-mode)
-(add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)
-(add-hook 'LaTeX-mode-hook 'reftex-mode)
-(setq LaTeX-electric-left-right-brace t)
-(setq font-latex-fontify-script nil)
-(setq TeX-electric-sub-and-superscript t)
- ;; (setq reftex-plug-into-AUCTeX t)
+(use-package avy
+ :bind
+ (("M-o" . avy-goto-char-timer))
+ :config
+ (setq avy-all-windows 'all-frames))
-
-
- org-download
-
+
+
+
4.4.10. crdt (Collaborative Editing)
+
-This package allows to download and copy images into org-mode buffers. Sadly it does not work in a very stable manner - if you copy images that are also links to another page (like is often the case in a Google image search), Emacs might crash from this.
+With this it is possible to work on the same file collaboratively. I have never tried it out, but it sounds cool.
-(use-package org-download
- :after org
- :defer nil
- :custom
- (org-download-method 'directory)
- (org-download-image-dir "./images")
- (org-download-heading-lvl 0)
- (org-download-timestamp "org_%Y%m%d-%H%M%S_")
- ;;(org-image-actual-width 500)
- (org-download-screenshot-method "grim -g \"$(slurp)\" %s")
- :bind
- ("C-M-y" . org-download-screenshot)
- :config
- (require 'org-download))
+(use-package crdt)
-
-
- org-fragtog
-
+
+
+
4.4.11. devdocs
+
-This package automatically toggles LaTeX-fragments in org-files. It seems to also work in markdown-files which is a nice addition, as my Obsidian notes are held in markdown.
+devdocs
is a very nice package that provides documentation from https:devdocs.io. This is very useful since e.g. pyright
provides only a very bad documentation and I do not want to leave Emacs all the time just to read documentation.
+
+
+
+To install a documentation, use the devdocs=install
command and select the appropriate version. devdocs-update-all
can be used to download and reinstall all installed documents if a newer version is available. Check documentation with devdocs-lookup
(C-SPC h d
).
-(use-package org-fragtog)
-(add-hook 'org-mode-hook 'org-fragtog-mode)
-(add-hook 'markdown-mode-hook 'org-fragtog-mode)
+(use-package devdocs)
+
+(add-hook 'python-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1"))))
+(add-hook 'python-ts-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1"))))
+
+(add-hook 'c-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("c"))))
+(add-hook 'c-ts-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("c"))))
+
+(add-hook 'c++-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("cpp"))))
+(add-hook 'c++-ts-mode-hook
+ (lambda () (setq-local devdocs-current-docs '("cpp"))))
+
+; (devdocs-update-all)
-
-
- org-modern
-
+
+
+
4.4.12. Projectile
+
-This just makes org-mode a little bit more beautiful, mostly by making the begin_src
and end_src
tags in source-blocks turn into more beautiful icons, as well as hiding #+
tags before them, as well as in the properties section of the file.
+projectile is useful for keeping track of your git projects within Emacs. I mostly use it to quickly switch between projects.
-(use-package org-modern
- :config (setq org-modern-block-name
- '((t . t)
- ("src" "»" "∥")))
- :hook (org-mode . org-modern-mode))
+(use-package projectile
+ :diminish projectile-mode
+ :config (projectile-mode)
+ :custom ((projectile-completion-system 'auto)) ;; integrate ivy into completion system
+ :bind-keymap
+ ("C-c p" . projectile-command-map) ; all projectile commands under this
+ :init
+ ;; NOTE: Set this to the folder where you keep your Git repos!
+ (when (file-directory-p swarsel-projects-directory)
+ (setq projectile-project-search-path (list swarsel-projects-directory)))
+(setq projectile-switch-project-action #'magit-status))
-
-
- Presentations
-
+
+
+
4.4.13. Magit
+
-Recently I have grown fond of holding presentations using Emacs :)
+magit is the best git utility I have ever used - it has a beautiful interface and is very verbose. Here I mostly just setup the list of repositories that I want to expost to magit.
+
+
+
+Also, Emacs needs a little extra love to accept my Yubikey for git commits etc. We also set that here.
- (use-package org-present
- :bind (:map org-present-mode-keymap
- ("q" . org-present-quit)
- ("<left>" . swarsel/org-present-prev)
- ("<up>" . 'ignore)
- ("<down>" . 'ignore)
- ("<right>" . swarsel/org-present-next))
- :hook ((org-present-mode . swarsel/org-present-start)
- (org-present-mode-quit . swarsel/org-present-end))
- )
-
-
- (use-package hide-mode-line)
-
- (defun swarsel/org-present-start ()
- (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch)
- (header-line (:height 4.0) variable-pitch)
- (org-document-title (:height 1.75) org-document-title)
- (org-code (:height 1.55) org-code)
- (org-verbatim (:height 1.55) org-verbatim)
- (org-block (:height 1.25) org-block)
- (org-block-begin-line (:height 0.7) org-block)
- ))
- (dolist (face '((org-level-1 . 1.1)
- (org-level-2 . 1.2)
- (org-level-3 . 1.2)
- (org-level-4 . 1.2)
- (org-level-5 . 1.2)
- (org-level-6 . 1.2)
- (org-level-7 . 1.2)
- (org-level-8 . 1.2)))
- (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
-
- (setq header-line-format " ")
- (setq visual-fill-column-width 90)
- (setq indicate-buffer-boundaries nil)
- (setq inhibit-message nil)
- (breadcrumb-mode 0)
- (org-display-inline-images)
- (global-hl-line-mode 0)
- (display-line-numbers-mode 0)
- (org-modern-mode 0)
- (evil-insert-state 1)
- (beginning-of-buffer)
- (org-present-read-only)
- ;; (org-present-hide-cursor)
- (swarsel/org-present-slide)
- )
-
- (defun swarsel/org-present-end ()
- (setq-local face-remapping-alist '((default variable-pitch default)))
- (dolist (face '((org-level-1 . 1.1)
- (org-level-2 . 0.9)
- (org-level-3 . 0.9)
- (org-level-4 . 0.9)
- (org-level-5 . 0.9)
- (org-level-6 . 0.9)
- (org-level-7 . 0.9)
- (org-level-8 . 0.9)))
- (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face)))
- (setq header-line-format nil)
- (setq visual-fill-column-width 150)
- (setq indicate-buffer-boundaries t)
- (setq inhibit-message nil)
- (breadcrumb-mode 1)
- (global-hl-line-mode 1)
- (display-line-numbers-mode 1)
- (org-remove-inline-images)
- (org-modern-mode 1)
- (evil-normal-state 1)
- ;; (org-present-show-cursor)
- )
-
- (defun swarsel/org-present-slide ()
- (org-overview)
- (org-show-entry)
- (org-show-children)
- )
+(use-package magit
+ :config
+ (setq magit-repository-directories `((,swarsel-projects-directory . 1)
+ (,swarsel-emacs-directory . 0)
+ (,swarsel-obsidian-directory . 0)
+ ("~/.dotfiles/" . 0)))
+ :custom
+ (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) ; stay in the same window
+
+
+
+
+
+
4.4.14. Yubikey support
+
+
+The following settings are needed to make sure emacs works for magit commits and pushes. It is not a beautiful solution since commiting uses pinentry-emacs and pushing uses pinentry-gtk2, but it works for now at least.
+
- (defun swarsel/org-present-prev ()
- (interactive)
- (org-present-prev)
- (swarsel/org-present-slide))
+
+
- (defun swarsel/org-present-next ()
- (interactive)
- (unless (eobp)
- (org-next-visible-heading 1)
- (org-fold-show-entry))
- (when (eobp)
- (org-present-next)
- (swarsel/org-present-slide)
- ))
+;; yubikey support for pushing commits
+;; commiting is enabled through nixos gpg-agent config
+(use-package pinentry)
+(pinentry-start)
+(setq epg-pinentry-mode 'loopback)
+(setenv "SSH_AUTH_SOCK" (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))
+
+
+
+
+
+
4.4.15. Forge
+
+
+NOTE: Make sure to configure a GitHub token before using this package!
+
+
-(add-hook 'buffer-list-update-hook #'clojure-leave-clojure-mode-function)
- (add-hook 'org-present-mode-hook 'swarsel/org-present-start)
- (add-hook 'org-present-mode-quit-hook 'swarsel/org-present-end)
- (add-hook 'org-present-after-navigate-functions 'swarsel/org-present-slide)
+
+
+(use-package forge
+ :after magit)
+(with-eval-after-load 'forge
+ (add-to-list 'forge-alist
+ '("sgit.iue.tuwien.ac.at"
+ "sgit.iue.tuwien.ac.at/api/v1"
+ "sgit.iue.tuwien.ac.at"
+ forge-gitea-repository)))
-
-
-
-
4.4.2. Nix Mode
-
+
+
4.4.16. git-timemachine
+
-This adds a rudimentary nix-mode to Emacs. I have not really tried this out, as I am mostly editing nix-files in org-mode anyways.
+This is just a nice utility to browse different versions of a file of a git project within Emacs.
-(use-package nix-mode
- :mode "\\.nix\\'")
+(use-package git-timemachine
+ :hook (git-time-machine-mode . evil-normalize-keymaps)
+ :init (setq git-timemachine-show-minibuffer-details t))
-
-
4.4.3. Markdown Mode
-
-
-
-- Mode
-
+
+
4.4.17. Delimiters (brackets): rainbow-delimiters, highlight-parentheses
+
+
+- rainbow-delimiters colors all delimiters, also ones not in current selection
+- paren highlights the current delimiter selection especially bold
+- highlight-parentheses boldly highlights all delimiters in current selection
+
+
+
+I am not completely sure on electric-pair-mode yet, sometimes it is very helpful, sometimes it annoys me to no end.
+
+
-(setq markdown-command "pandoc")
+(use-package rainbow-delimiters
+ :hook (prog-mode . rainbow-delimiters-mode))
+
+(use-package highlight-parentheses
+ :config
+ (setq highlight-parentheses-colors '("black" "white" "black" "black" "black" "black" "black"))
+ (setq highlight-parentheses-background-colors '("magenta" "blue" "cyan" "green" "yellow" "orange" "red"))
+ (global-highlight-parentheses-mode t))
+
+(electric-pair-mode 1)
+(setq electric-pair-preserve-balance t)
+(setq electric-pair-skip-self nil)
+(setq electric-pair-delete-adjacent-pairs t)
+;; don't skip newline when auto-pairing parenthesis
+(setq electric-pair-skip-whitespace-chars '(9 32))
+
+;; in org-mode buffers, do not pair < and > in order not to interfere with org-tempo
+(add-hook 'org-mode-hook (lambda ()
+ (setq-local electric-pair-inhibit-predicate
+ `(lambda (c)
+ (if (char-equal c ?<) t (,electric-pair-inhibit-predicate c))))))
+
-(use-package markdown-mode
- :ensure t
- :mode ("README\\.md\\'" . gfm-mode)
- :init (setq markdown-command "multimarkdown")
- :bind (:map markdown-mode-map
- ("C-c C-e" . markdown-do)))
-
-
- LaTeX in Markdown
-
+
+
+
4.4.18. rainbow-mode
+
+
+Complimentary to the delimiters-packages above, this package sets the background color of the delimiters, which makes it easier to see at a glance where we are in a delimiter-tree.
+
+
-(add-hook 'markdown-mode-hook
- (lambda ()
- (local-set-key (kbd "C-c C-x C-l") 'org-latex-preview)
- (local-set-key (kbd "C-c C-x C-u") 'markdown-toggle-url-hiding)
- ))
+(use-package rainbow-mode
+ :config (rainbow-mode))
-
-
-
-
4.4.4. Olivetti
-
+
+
4.4.19. Corfu
+
-Olivetti is a mode specialized for writing prose in Emacs. I went for a very simple setup with little distractions.
+This is the company equivalent to the vertico gang.
+I dislike the standard behaviour that makes the cursor move into the completion framework on presses of <up>
and <down>
.
-This mode is not automatically activated anywhere because I only rarely need it.
+Nerd icons is originally enabled here: Icons
+
+
+
+Navigation functions defined here: corfu: Do not interrupt navigation
-(use-package olivetti
+;; (use-package corfu
+;; :custom
+;; (corfu-cycle t)
+;; :init
+;; (global-corfu-mode))
+
+(use-package corfu
:init
- (setq olivetti-body-width 100)
- (setq olivetti-recall-visual-line-mode-entry-state t))
+ (global-corfu-mode)
+ (corfu-history-mode)
+ (corfu-popupinfo-mode) ; Popup completion info
+ :custom
+ (corfu-auto t)
+ (corfu-auto-prefix 3)
+ (corfu-auto-delay 0.3)
+ (corfu-cycle t)
+ (corfu-quit-no-match 'separator)
+ (corfu-separator ?\s)
+ ;; (corfu-quit-no-match t)
+ (corfu-popupinfo-max-height 70)
+ (corfu-popupinfo-delay '(0.5 . 0.2))
+ ;; (corfu-preview-current 'insert) ; insert previewed candidate
+ (corfu-preselect 'prompt)
+ (corfu-on-exact-match nil) ; Don't auto expand tempel snippets
+ ;; Optionally use TAB for cycling, default is `corfu-complete'.
+ :bind (:map corfu-map
+ ("M-SPC" . corfu-insert-separator)
+ ("<return>" . swarsel/corfu-normal-return)
+ ;; ("C-<return>" . swarsel/corfu-complete)
+ ("S-<up>" . corfu-popupinfo-scroll-down)
+ ("S-<down>" . corfu-popupinfo-scroll-up)
+ ("C-<up>" . corfu-previous)
+ ("C-<down>" . corfu-next)
+ ("<insert-state> <up>" . swarsel/corfu-quit-and-up)
+ ("<insert-state> <down>" . swarsel/corfu-quit-and-down))
+ )
+
+(use-package nerd-icons-corfu)
+
+(add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)
+
+(setq nerd-icons-corfu-mapping
+ '((array :style "cod" :icon "symbol_array" :face font-lock-type-face)
+ (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face)
+ ;; ...
+ (t :style "cod" :icon "code" :face font-lock-warning-face)))
+
+
+
+
+
+
+
4.4.20. cape
+
+
+cape adds even more completion capabilities by adding a lot of completion logic that is exposed as separate functions. I tried out adding these to the completion-at-points-functions
alist, but I felt like it cluttered my suggestions too much. Hence I now just call the respective functions when I need them. For this I setup the C-z
keybinding in General evil.
+
+
+
+I leave the commented out alist extensions here in case I want to try them out at some point in the future.
+
+
+
+
+(use-package cape
+ :bind
+ ("C-z p" . completion-at-point) ;; capf
+ ("C-z t" . complete-tag) ;; etags
+ ("C-z d" . cape-dabbrev) ;; or dabbrev-completion
+ ("C-z h" . cape-history)
+ ("C-z f" . cape-file)
+ ("C-z k" . cape-keyword)
+ ("C-z s" . cape-elisp-symbol)
+ ("C-z e" . cape-elisp-block)
+ ("C-z a" . cape-abbrev)
+ ("C-z l" . cape-line)
+ ("C-z w" . cape-dict)
+ ("C-z :" . cape-emoji)
+ ("C-z \\" . cape-tex)
+ ("C-z _" . cape-tex)
+ ("C-z ^" . cape-tex)
+ ("C-z &" . cape-sgml)
+ ("C-z r" . cape-rfc1345)
+ ;; Add to the global default value of `completion-at-point-functions' which is
+ ;; used by `completion-at-point'. The order of the functions matters, the
+ ;; first function returning a result wins. Note that the list of buffer-local
+ ;; completion functions takes precedence over the global list.
+ ;; (add-to-list 'completion-at-point-functions #'cape-dabbrev)
+ ;; (add-to-list 'completion-at-point-functions #'cape-file)
+ ;; (add-to-list 'completion-at-point-functions #'cape-elisp-block)
+ ;; (add-to-list 'completion-at-point-functions #'cape-history)
+ ;; (add-to-list 'completion-at-point-functions #'cape-keyword)
+ ;; (add-to-list 'completion-at-point-functions #'cape-tex)
+ ;; (add-to-list 'completion-at-point-functions #'cape-sgml)
+ ;; (add-to-list 'completion-at-point-functions #'cape-rfc1345)
+ ;; (add-to-list 'completion-at-point-functions #'cape-abbrev)
+ ;; (add-to-list 'completion-at-point-functions #'cape-dict)
+ ;; (add-to-list 'completion-at-point-functions #'cape-elisp-symbol)
+ ;; (add-to-list 'completion-at-point-functions #'cape-line)
+)
-
-
4.4.5. darkroom
-
+
+
4.4.21. rust
+
-Darkroom is package that reduces all forms of distraction to a minimum - this can be useful when simply reading a file for example. For this mode I have increased the text scale by a large margin to make for comfortable reading
-This mode is not automatically activated anywhere because I only rarely need it.
+This sets up rustic-mode with tree-sitter support - there is still one issue to iron out with automatic adding of dependency crates, but everything else works fine now.
-(use-package darkroom
+(use-package rustic
:init
- (setq darkroom-text-scale-increase 3))
-
-
-
-
-
-
-
4.4.6. Ripgrep
-
-
-This is the ripgrep command for Emacs.
-
+ (setq rust-mode-treesitter-derive t)
+ :config
+ (define-key rust-ts-mode-map (kbd "C-c C-c C-r") 'rustic-cargo-run)
+ (define-key rust-ts-mode-map (kbd "C-c C-c C-b") 'rustic-cargo-build)
+ (define-key rust-ts-mode-map (kbd "C-c C-c C-k") 'rustic-cargo-check)
+ (define-key rust-ts-mode-map (kbd "C-c C-c d") 'rustic-cargo-doc)
+ (define-key rust-ts-mode-map (kbd "C-c C-c a") 'rustic-cargo-add)
+ (setq rustic-format-on-save t)
+ (setq rustic-lsp-client 'eglot)
+ :mode ("\\.rs" . rustic-mode))
-
-
-
4.4.7. Tree-sitter
-
-
-Tree-sitter is a parsing library integrated into Emacs to provide better syntax highlighting and code analysis. It generates concrete syntax trees for source code, enabling more accurate and efficient text processing. Emacs' tree-sitter integration enhances language support, offering features like incremental parsing and precise syntax-aware editing. This improves the development experience by providing robust and dynamic syntax features, making it easier for me to navigate and manipulate code.
-
-
+
+
4.4.22. Tramp
+
-In order to update the language grammars, run the next command below.
+Tramp allows for SSH access of files over Emacs. I have no ideas what the options here mean, but this is a recommended configuration that I found (sadly I lost the link). I need to research more what these options really do.