From 8d8644e2165d9b14bb2aeac94c804b4ac4639bea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leon=20Schwarz=C3=A4ugl?=
-This file has 58383 words spanning 14864 lines and was last revised on 2024-12-28 18:15:25 +0100.
+This file has 60522 words spanning 15453 lines and was last revised on 2024-12-29 02:23:09 +0100.
@@ -738,7 +763,7 @@ Table of Contents
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
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-12-28 18:15:25 +0100) +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-12-29 02:23:09 +0100)
@@ -818,1629 +843,1825 @@-These blocks are used in several places throughout the configurations, but not on all machines necessarily. For example, the theming section needs to be in a NixOS block on NixOS machines but in a home-manager block on non-NixOS. +Handling the flake.nix file used to be a bit of a chore, since it felt like writing so much boilerplate code just to define new systems. The noweb-approach here makes this a little bit less painful.
-Originally, I used this method a lot throughout my configuration. However, as my knowledge of NixOS grew, I have been weeding these snippets out more and more as I find more efficient native solutions. Now, only the theming block remains.
+These blocks are later inserted here: flake.nix template. Adding new flake inputs is very easy, you just add them to Inputs & Inputs@Outputs first by name in the first source-block, and then the path in the second source-block. Any variables to be set for the host configuration are done in let, and the specific setup is done in either nixosConfigurations (for NixOS systems), homeConfigurations (for home-manager systems), or nixOnDroidConfigurations (for Nix on Android) and darwinConfigurations (for Darwin systems, also known as Macs). There also used to be a [BROKEN LINK: h:6a08495a-8566-4bb5-9fac-b03df01f6c81] section that used to define a Proxmox LXC image when I was still using Proxmox as my main server. An example of the repository at that time would be acc0ad6: Add several NixOS hosts on Proxmox and Oracle Cloud
.
-This serves only to reduce code duplication in this file. The tangled files experience no size reduction, since noweb-ref only substitutes these blocks in.
+This sections puts together the flake.nix
file from the Noweb-Ref blocks section. This tangles the flake.nix file; This block only needs to be touched when updating the general structure of the flake. For everything else, see the respective noweb-ref block.
-Also, this section now holds some of the longer configuration files that cannot be defined directly within NixOS configuration. These files are usually symlinked using home.file
.
-
-For styling, I am using the stylix NixOS module, loaded by flake. This package is really great, as it adds nix expressions for basically everything. Ever since switching to this, I did not have to play around with theming anywhere else. +In general, a nix flake consists of one or more inputs and several outputs. The inputs are used to define where nix should be looking for packages, options, and more. The outputs generate expressions that can be used in .nix files as well as system configurations using these files.
-The full list of nerd-fonts can be found here: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/data/fonts/nerd-fonts/manifests/fonts.json
+In the start, I enable some public cache repositories. This saves some time during rebuilds because it avoids building as many packages from scratch - this is mainly important for community flakes like emacs-overlay
, which basically would trigger a rebuild whenever updating the flake. The repository does of course not hold everything, but it lightens the pain.
-This is where the theme for the whole OS is defined. Originally, this noweb-ref section could not be copied to the general NixOS config since they are on different folder structure levels in the config, which would have made the flake impure. By now, I have found out that using the ${self}
method for referencing the flake root, I could circumvent this problem. Also, the noweb-ref block could in general be replaced by a custom attribute set (see for example firefox). The difference here is, however, that this block is used in a NixOS and a home-manager-only configuration, verbatim. If I were to use an attribute set, I would have to duplicate this block once each for NixOS and home-manager. Alas, this block stays (for now).
+In outputs = inputs@ [...]
, the inputs@
makes it so that all inputs are automatically passed to the outputs and can be called as inputs.<name>
, whereas explicit arguments may just be called by using <name>
. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file.
-enable = true; -base16Scheme = "${self}/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"; - }; +{ + description = "SwarseFlake - Nix Flake for all SwarselSystems"; - sansSerif = { - # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); - package = pkgs.cantarell-fonts; - # package = pkgs.montserrat; - name = "Cantarell"; - # name = "FiraCode Nerd Font Propo"; - # name = "Montserrat"; + nixConfig = { + extra-substituters = [ + "https://nix-community.cachix.org" + "https://cache.ngi0.nixos.org/" + ]; + + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=" + ]; }; - monospace = { - package = pkgs.nerd-fonts.fira-mono; # has overrides + inputs = { - name = "FiraCode Nerd Font Mono"; - }; + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - emoji = { - package = pkgs.noto-fonts-emoji; - name = "Noto Color Emoji"; - }; -}; + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05"; --
-On my server, I use a reduced, self-contained emacs configuration that only serves as an elfeed sync server. This is currently unused, however, I am keeping this in here for now as a reference. The big problem here was the bidirectional syncing using bjm/elfeed-updater
. As I am using this both on a laptop client (using elfeed) as well as on a mobile phone (using elfeed-cljsrn over elfeed-web), I set up a Syncthing service to take care of the feeds as well as the db state. However, I could only either achieve changes propagating properly from the laptop to the server or from the phone to the server. Both would not work. This current state represents the state where from-laptop changes would propagate. To allow from-phone changes, change (elfeed-db-load)
in bjm/elfeed-updater
to (elfeed-db-save)
.
-
(require 'package) + # overlay to access bleeding edge emacs + emacs-overlay = { + url = "github:nix-community/emacs-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; -(package-initialize nil) -(setq package-enable-at-startup nil) + # nix user repository + # i use this mainly to not have to build all firefox extensions + # myself as well as for the emacs-init package (tbd) + nur.url = "github:nix-community/NUR"; -(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t) + # provides GL to non-NixOS hosts + nixgl.url = "github:guibou/nixGL"; -(add-to-list 'package-archives - '("melpa" . "https://melpa.org/packages/") t) + # manages all theming using Home-Manager + stylix.url = "github:danth/stylix"; + # nix secrets management + sops-nix.url = "github:Mic92/sops-nix"; -(package-initialize) + # enable secure boot on NixOS + lanzaboote.url = "github:nix-community/lanzaboote"; -(let ((default-directory "~/.emacs.d/elpa/")) - (normal-top-level-add-subdirs-to-load-path)) + # nix for android + nix-on-droid = { + url = "github:nix-community/nix-on-droid/release-24.05"; + inputs.nixpkgs.follows = "nixpkgs"; + }; -(unless (package-installed-p 'use-package) - (package-refresh-contents) - (package-install 'use-package)) + # generate NixOS images + nixos-generators = { + url = "github:nix-community/nixos-generators"; + inputs.nixpkgs.follows = "nixpkgs"; + }; -(require 'use-package) + # hardware quirks on nix + nixos-hardware = { + url = "github:NixOS/nixos-hardware/master"; + }; -(use-package elfeed - :ensure t - :bind (:map elfeed-search-mode-map - ("q" . bjm/elfeed-save-db-and-bury))) + # dynamic library loading + nix-alien = { + url = "github:thiagokokada/nix-alien"; + }; -(require 'elfeed) + # automatic nintendo switch payload injection + nswitch-rcm-nix = { + url = "github:Swarsel/nswitch-rcm-nix"; + }; -(use-package elfeed-org - :ensure t - :config - (elfeed-org) - (setq rmh-elfeed-org-files (list "/var/lib/syncthing/.elfeed/elfeed.org"))) + # weekly updated nix-index database + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; -(use-package elfeed-goodies - :ensure t) + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; -(elfeed-goodies/setup) + impermanence.url = "github:nix-community/impermanence"; -(use-package elfeed-web - :ensure t) + zjstatus = { + url = "github:dj95/zjstatus"; + }; -(global-set-key (kbd "C-x w") 'bjm/elfeed-load-db-and-open) + fw-fanctrl = { + url = "github:TamtamHero/fw-fanctrl/packaging/nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; -(define-key elfeed-show-mode-map (kbd "j") 'elfeed-goodies/split-show-next) -(define-key elfeed-show-mode-map (kbd "k") 'elfeed-goodies/split-show-prev) -(define-key elfeed-search-mode-map (kbd "j") 'next-line) -(define-key elfeed-search-mode-map (kbd "k") 'previous-line) -(define-key elfeed-show-mode-map (kbd "S-SPC") 'scroll-down-command) + nix-darwin = { + url = "github:lnl7/nix-darwin"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + pre-commit-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; -(defun bjm/elfeed-save-db-and-bury () - "Wrapper to save the elfeed db to disk before burying buffer" - (interactive) - (elfeed-db-save) - (quit-window)) + nix-secrets = { + url = "git+ssh://git@github.com/Swarsel/nix-secrets.git?ref=main&shallow=1"; + flake = false; + inputs = { }; + }; -(defun bjm/elfeed-load-db-and-open () - "Wrapper to load the elfeed db from disk before opening" - (interactive) - (elfeed-db-load) - (elfeed) - (elfeed-search-update--force) - (elfeed-update)) + nix-topology.url = "github:oddlama/nix-topology"; -(defun bjm/elfeed-updater () - "Wrapper to load the elfeed db from disk before opening" - (interactive) - (elfeed-db-load)) + }; -(run-with-timer 0 (* 1 60) 'bjm/elfeed-updater) + outputs = + inputs@{ self + , nixpkgs + , home-manager + , nix-darwin + , systems + , ... + }: + let -(setq httpd-port 9812) -(setq httpd-host "0.0.0.0") -(setq httpd-root "/root/.emacs.d/elpa/elfeed-web-20240729.1741/") -(setq elfeed-db-directory "/var/lib/syncthing/.elfeed/db/") + inherit (self) outputs; + lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; }); -(httpd-start) -(elfeed-web-start) --
-This is the configuration file for tridactyl, which provides keyboard-driven navigation in firefox. Pay attention to the warnings in this file; depending on your browsing behaviour, you might expose yourself to some vulnerabilities by copying this configuration. -
+ # NixOS modules that can only be used on NixOS systems + nixModules = [ + inputs.stylix.nixosModules.stylix + inputs.lanzaboote.nixosModules.lanzaboote + inputs.disko.nixosModules.disko + inputs.impermanence.nixosModules.impermanence + inputs.sops-nix.nixosModules.sops + inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm + inputs.nix-topology.nixosModules.default + ./profiles/common/nixos + ]; + # Home-Manager modules wanted on non-NixOS systems + homeModules = [ + inputs.stylix.homeManagerModules.stylix + ]; --sanitise tridactyllocal tridactylsync + # Home-Manager modules wanted on both NixOS and non-NixOS systems + mixedModules = [ + inputs.sops-nix.homeManagerModules.sops + inputs.nix-index-database.hmModules.nix-index + ./profiles/common/home + ]; -colourscheme base16-codeschool + in + { -" General Settings -set update.lastchecktime 1720629386560 -set update.lastnaggedversion 1.24.1 -set update.nag true -set update.nagwait 7 -set update.checkintervalsecs 86400 -set configversion 2.0 -set searchurls.no https://search.nixos.org/options?query= -set searchurls.np https://search.nixos.org/packages?query= -set searchurls.hm https://home-manager-options.extranix.com/?query= -set completions.Tab.statusstylepretty true -set hintfiltermode vimperator-reflow -set hintnames numeric + inherit lib nixModules mixedModules homeModules; -" Binds -bind <C-m> buffer # -bind gd tabdetach -bind gD composite tabduplicate; tabdetach -bind d composite tabprev; tabclose # -bind D tabclose -bind c hint -bindurl ^http(s)?://www\.google\.com c hint -Jc [class="LC20lb MBeuO DKV0Md"],[class="YmvwI"],[class="YyVfkd"],[class="fl"] -bindurl ^http(s)?://news\.ycombinator\.com c hint -Jc [class="titleline"],[class="age"] -bindurl ^http(s)?://lobste\.rs c hint -Jc [class="u-url"],[class="comments_label"] -bindurl ^http(s)?://www\.google\.com gi composite focusinput -l ; text.end_of_line + nixosModules = import ./modules/nixos { inherit lib; }; + homeManagerModules = import ./modules/home { inherit lib; }; + packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); + formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); + overlays = import ./overlays { inherit self lib inputs; }; -" Search in page -set findcase smart -bind / fillcmdline find -bind ? fillcmdline find -? -bind n findnext 1 -bind N findnext -1 + apps = lib.swarselsystems.forAllSystems (system: + let + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" + ]; + appSet = lib.swarselsystems.mkApps system appNames self; + in + { + inherit appSet; + default = appSet.bootstrap; + }); -bind j scrollline 4 -bind k scrollline -4 + devShells = lib.swarselsystems.forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + checks = self.checks.${system}; + in + { + default = pkgs.mkShell { + NIX_CONFIG = "experimental-features = nix-command flakes"; + inherit (checks.pre-commit-check) shellHook; + buildInputs = checks.pre-commit-check.enabledPackages; + nativeBuildInputs = with pkgs; [ + nix + home-manager + git + just + age + ssh-to-age + sops + statix + deadnix + nixpkgs-fmt + ]; + }; + } + ); + checks = lib.swarselsystems.forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + import ./checks { inherit self inputs system pkgs; } + ); -" WARNING: This file defines and runs a command called fixamo_quiet. If you -" also have a malicious addon that operates on `<all_urls>` installed this -" will allow it to steal your firefox account credentials! -" -" With those credentials, an attacker can read anything in your sync account, -" publish addons to the AMO, etc, etc. -" -" Without this command a malicious addon can steal credentials from any site -" that you visit that is not in the restrictedDomains list. -" -" You should comment out the fixamo lines unless you are entirely sure that -" they are what you want. -command fixamo_quiet jsb tri.excmds.setpref("privacy.resistFingerprinting.block_mozAddonManager", "true").then(tri.excmds.setpref("extensions.webextensions.restrictedDomains", '""')) -command fixamo js tri.excmds.setpref("privacy.resistFingerprinting.block_mozAddonManager", "true").then(tri.excmds.setpref("extensions.webextensions.restrictedDomains", '""').then(tri.excmds.fillcmdline_tmp(3000, "Permissions added to user.js. Please restart Firefox to make them take affect."))) -fixamo_quiet -set allowautofocus false + nixosConfigurations = + lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") "nixos"; -" The following modification allows Tridactyl to function on more pages, e.g. raw GitHub pages. -" You may not wish to run this. Mozilla strongly feels that you shouldn't. -" Read https://wiki.mozilla.org/Security/CSP#Goals for more information. -" -" Equivalent to `set csp clobber` before it was removed. -" This weakens your defences against cross-site-scripting attacks -" and other types of code-injection by reducing the strictness -" of Content Security Policy on all sites in a couple of ways. -" -" We remove the sandbox directive -" https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox -" which allows our iframe (and anyone else's) to run on any website. -" -" We weaken the style-src directive -" https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src -" to allow us to theme our elements. -" This exposes you to 'cross site styling' attacks -jsb browser.webRequest.onHeadersReceived.addListener(tri.request.clobberCSP,{urls:["<all_urls>"],types:["main_frame"]},["blocking","responseHeaders"]) + homeConfigurations = -" default is 300ms -set hintdelay 100 + # "swarsel@home-manager" = inputs.home-manager.lib.homeManagerConfiguration { + # pkgs = lib.swarselsystems.pkgsFor.x86_64-linux; + # extraSpecialArgs = { inherit inputs outputs; }; + # modules = homeModules ++ mixedModules ++ [ + # ./hosts/home-manager + # ]; + # }; -" Some pages like github break on the tridactyl quick search. have this as a fallback -unbind <C-f> + lib.swarselsystems.mkHalfHostConfigs (lib.swarselsystems.readHosts "home") "home" lib.swarselsystems.pkgsFor.x86_64-linux; -" Subconfig Settings -seturl www.google.com followpagepatterns.next Next -seturl www.google.com followpagepatterns.prev Previous -" Autocmds -autocmd DocStart undefined mode ignore -autocmd DocStart pokerogue.net mode ignore -autocmd DocStart typelit.io mode ignore -autocmd DocStart vc-impimba-1.m.imp.ac.at/ui/webconsole mode ignore + darwinConfigurations = + lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "darwin") "darwin"; + + nixOnDroidConfigurations = + + # magicant = inputs.nix-on-droid.lib.nixOnDroidConfiguration { + # pkgs = lib.swarselsystems.pkgsFor.aarch64-linux; + # modules = [ + # ./hosts/magicant + # ]; + # }; + + lib.swarselsystems.mkHalfHostConfigs (lib.swarselsystems.readHosts "android") "android" lib.swarselsystems.pkgsFor.aarch64-linux; + + + + topology = + + lib.swarselsystems.forEachSystem (pkgs: import inputs.nix-topology { + inherit pkgs; + modules = [ + # Your own file to define global topology. Works in principle like a nixos module but uses different options. + # ./topology.nix + { inherit (self) nixosConfigurations; } + ]; + }); + + + }; +} + -" For syntax highlighting see https://github.com/tridactyl/vim-tridactyl -" vim: set filetype=tridactyl
-This is the stylesheet used by waybar.
+This file defines a number of checks that can either be run by calling nix flake check
or while in a nix-shell
or nix develop
. This helps me make sure that my flake confirms to my self-imposed standards. The GitHub actions perform less checks than are being done here (they are only checking the formatting, as well as statix
and deadnix
)
@define-color foreground #fdf6e3; -@define-color background #1a1a1a; -@define-color background-alt #292b2e; -@define-color foreground-warning #268bd2; -@define-color background-warning @background; -@define-color foreground-error red; -@define-color background-error @background; -@define-color foreground-critical gold; -@define-color background-critical blue; +{ self, inputs, pkgs, system, ... }: +{ + pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { + src = "${self}"; + hooks = { + check-added-large-files.enable = true; + check-case-conflicts.enable = true; + check-executables-have-shebangs.enable = true; + check-shebang-scripts-are-executable.enable = false; + check-merge-conflicts.enable = true; + deadnix.enable = true; + detect-private-keys.enable = true; + end-of-file-fixer.enable = true; + fix-byte-order-marker.enable = true; + flake-checker.enable = true; + forbid-new-submodules.enable = true; + mixed-line-endings.enable = true; + nixpkgs-fmt.enable = true; + statix.enable = true; + trim-trailing-whitespace.enable = true; + destroyed-symlinks = { + enable = true; + entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; + }; - * { - border: none; - border-radius: 0; - font-family: "FiraCode Nerd Font Propo", "Font Awesome 5 Free"; - font-size: 14px; - min-height: 0; - margin: -1px 0px; -} + shellcheck = { + enable = true; + entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; + }; -window#waybar { - background: transparent; - color: @foreground; - transition-duration: .5s; -} + shfmt = { + enable = true; + entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; + }; -window#waybar.hidden { - opacity: 0.2; + }; + }; } ++
+Here we define inputs and outputs of the flake. First, the following list is for the outputs of the flake. +
++Format: <name>, +
-#mpris { - padding: 0 10px; - background-color: transparent; - color: #1DB954; - font-family: Monospace; - font-size: 12px; -} - -#custom-right-arrow-dark, -#custom-left-arrow-dark { - color: @background; - background: @background-alt; - font-size: 24px; -} +
+Mind the comma at the end. You need this because the ...
is being passed as the last argument in the template at flake.nix template.
+
+Here, just add the input names, urls and other options that are needed, like nixpkgs.follows
. By using the latter option, you tell the package to not provide it's own package repository, but instead 'nest' itself into another, which is very useful.
+A short overview over each input and what it does:
+
~/.config/
.steam-run
. However, I have not yet gotten this to work.nix-index
that is updated weekly. This allows for declarative management, without needing to run the nix-index
command for database assembly.secretsFile
(or similar) option. An example is the LastFM.ApiKey
option in navidrome:
+LastFM.ApiKey = builtins.readFile "${secretsDirectory}/navidrome/lastfm-secret";
+When setting this option normally, the password would normally be written world-readable not only in the nix store, but also in the configuration. Hence, I put such passwords into a private repository. This allows me to keep purity of the flake while keeping a level of security on these secrets. +
++nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; -#custom-nix-updates { - color: white; - padding: 0 3px; -} +nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05"; -#custom-outer-right-arrow-dark, -#custom-outer-left-arrow-dark { - color: @background; - font-size: 24px; -} +systems.url = "github:nix-systems/default-linux"; -#custom-outer-left-arrow-dark, -#custom-left-arrow-dark, -#custom-left-arrow-light { - margin: 0 -1px; -} +# user-level configuration +home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#custom-right-arrow-light, -#custom-left-arrow-light { - color: @background-alt; - background: @background; - font-size: 24px; -} +# overlay to access bleeding edge emacs +emacs-overlay = { + url = "github:nix-community/emacs-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#workspaces, -#clock.1, -#clock.2, -#clock.3, -#pulseaudio, -#memory, -#cpu, -#temperature, -#custom-scratchpad-indicator, -#power-profiles-daemon, -#idle_inhibitor, -#backlight-slider, -#mpris, -#tray { - background: @background; -} +# nix user repository +# i use this mainly to not have to build all firefox extensions +# myself as well as for the emacs-init package (tbd) +nur.url = "github:nix-community/NUR"; -#network, -#custom-vpn, -#clock.2, -#battery, -#cpu, -#custom-pseudobat, -#disk { - background: @background-alt; -} +# provides GL to non-NixOS hosts +nixgl.url = "github:guibou/nixGL"; +# manages all theming using Home-Manager +stylix.url = "github:danth/stylix"; -#workspaces button { - padding: 0 2px; - color: #fdf6e3; -} -#workspaces button.focused { - color: @foreground-warning; -} +# nix secrets management +sops-nix.url = "github:Mic92/sops-nix"; -#workspaces button:hover { - background: @foreground; - color: @background; - border: @foreground; - padding: 0 2px; - box-shadow: inherit; - text-shadow: inherit; -} +# enable secure boot on NixOS +lanzaboote.url = "github:nix-community/lanzaboote"; -#workspaces button.urgent { - color: @background-critical; - background: @foreground-critical; -} +# nix for android +nix-on-droid = { + url = "github:nix-community/nix-on-droid/release-24.05"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#custom-vpn, -#network { - color: #cc99c9; -} +# generate NixOS images +nixos-generators = { + url = "github:nix-community/nixos-generators"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#temperature, -#power-profiles-daemon { - color: #9ec1cf; -} +# hardware quirks on nix +nixos-hardware = { + url = "github:NixOS/nixos-hardware/master"; +}; -#disk { - /*color: #b58900;*/ - color: #9ee09e; -} +# dynamic library loading +nix-alien = { + url = "github:thiagokokada/nix-alien"; +}; -#custom-scratchpad-indicator { - color: #ffffff; -} +# automatic nintendo switch payload injection +nswitch-rcm-nix = { + url = "github:Swarsel/nswitch-rcm-nix"; +}; -#disk.warning { - color: @foreground-error; - background-color: @background-error; -} -#disk.critical, -#temperature.critical { - color: @foreground-critical; - background-color: @background-critical; - animation-name: blink; - animation-duration: 0.5s; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-direction: alternate; -} -#pulseaudio.muted { - color: @foreground-error; -} -#memory { - /*color: #2aa198;*/ - color: #fdfd97; -} -#cpu { - /*color: #6c71c4;*/ - color: #feb144; -} +# weekly updated nix-index database +nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#pulseaudio { - /*color: #268bd2;*/ - color: #ff6663; -} +disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#battery, -#custom-pseudobat { - color: cyan; -} -#battery.discharging { - color: #859900; -} +impermanence.url = "github:nix-community/impermanence"; -@keyframes blink { - to { - color: @foreground-error; - background-color: @background-error; - } -} -@keyframes configblink { - to { - color: @foreground-error; - background-color: transparent; - } -} +zjstatus = { + url = "github:dj95/zjstatus"; +}; -#battery.critical:not(.charging) { - color: @foreground-critical; - background-color: @background-critical; - animation-name: blink; - animation-duration: 0.5s; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-direction: alternate; -} +fw-fanctrl = { + url = "github:TamtamHero/fw-fanctrl/packaging/nix"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#backlight-slider slider { - min-height: 0px; - min-width: 0px; - opacity: 0; - background-image: none; - border: none; - box-shadow: none; -} -#backlight-slider trough { - min-height: 5px; - min-width: 80px; - border-radius: 5px; - background-color: black; -} -#backlight-slider highlight { - min-width: 0px; - border-radius: 5px; - background-color: grey; -} +nix-darwin = { + url = "github:lnl7/nix-darwin"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#clock.1, -#clock.2, -#clock.3 { - font-family: Monospace; -} +pre-commit-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; +}; -#clock, -#pulseaudio, -#memory, -#cpu, -#tray, -#temperature, -#power-profiles-daemon, -#network, -#custom-vpn, -#mpris, -#battery, -#custom-scratchpad-indicator, -#custom-pseudobat, -#disk { - padding: 0 3px; -} +nix-secrets = { + url = "git+ssh://git@github.com/Swarsel/nix-secrets.git?ref=main&shallow=1"; + flake = false; + inputs = { }; +}; + +nix-topology.url = "github:oddlama/nix-topology";
-Handling the flake.nix file used to be a bit of a chore, since it felt like writing so much boilerplate code just to define new systems. The noweb-approach here makes this a little bit less painful.
+Here I define a few variables that I need for my system specifications. First and foremost, pkgs
, which gets passed the emacs-overlay, nur, and nixgl modules to it. With this, I can grab all these packages by referencing pkgs.<name>
instead of having to put e.g. nixgl.auto.nixGLDefault
.
-These blocks are later inserted here: flake.nix template. Adding new flake inputs is very easy, you just add them to Inputs & Inputs@Outputs first by name in the first source-block, and then the path in the second source-block. Any variables to be set for the host configuration are done in let, and the specific setup is done in either nixosConfigurations (for NixOS systems), homeConfigurations (for home-manager systems), or nixOnDroidConfigurations (for Nix on Android) and darwinConfigurations (for Darwin systems, also known as Macs). There also used to be a [BROKEN LINK: h:6a08495a-8566-4bb5-9fac-b03df01f6c81] section that used to define a Proxmox LXC image when I was still using Proxmox as my main server. An example of the repository at that time would be acc0ad6 main Add several NixOS hosts on Proxmox and Oracle Cloud
.
-
-This sections puts together the flake.nix
file from the Noweb-Ref blocks section. This tangles the flake.nix file; This block only needs to be touched when updating the general structure of the flake. For everything else, see the respective noweb-ref block.
+I also define some common module lists that I can simply load depending on the fundamental system (NixOS vs. non-NixOS) - nixModules
, homeModules
, and mixedModules
.
-In general, a nix flake consists of one or more inputs and several outputs. The inputs are used to define where nix should be looking for packages, options, and more. The outputs generate expressions that can be used in .nix files as well as system configurations using these files. +The interesting part is in the start:
+pkgsFor
. This function reads all available systems from nixpkgs and generates pkgs for them.forEachSystem
is a function that can be called to declare an output for each such defined system.forAllSystems
is a crude function that I use for expressions that depend on system
, as the prior two attributes already consumed it at that stage. This is only really used to generate the checks in their own file.mkFullHost
is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching nixosSystem
or darwinSystem
. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options).mkFullHostConfigs
is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in hosts/
under either the nixos/
or darwin/
directory. These directories are being read by readHosts
and delivered to this funtion in the later call in nixosConfigurations or darwinConfigurations.+inherit (self) outputs; +lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; }); + + +# NixOS modules that can only be used on NixOS systems +nixModules = [ + inputs.stylix.nixosModules.stylix + inputs.lanzaboote.nixosModules.lanzaboote + inputs.disko.nixosModules.disko + inputs.impermanence.nixosModules.impermanence + inputs.sops-nix.nixosModules.sops + inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm + inputs.nix-topology.nixosModules.default + ./profiles/common/nixos +]; + +# Home-Manager modules wanted on non-NixOS systems +homeModules = [ + inputs.stylix.homeManagerModules.stylix +]; +# Home-Manager modules wanted on both NixOS and non-NixOS systems +mixedModules = [ + inputs.sops-nix.homeManagerModules.sops + inputs.nix-index-database.hmModules.nix-index + ./profiles/common/home +]; + ++
-In the start, I enable some public cache repositories. This saves some time during rebuilds because it avoids building as many packages from scratch - this is mainly important for community flakes like emacs-overlay
, which basically would trigger a rebuild whenever updating the flake. The repository does of course not hold everything, but it lightens the pain.
+In this section I am creating some attributes that define general concepts of my configuration:
-In outputs = inputs@ [...]
, the inputs@
makes it so that all inputs are automatically passed to the outputs and can be called as inputs.<name>
, whereas explicit arguments may just be called by using <name>
. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file.
+
nixosModules
imports self-defined options that I only want to use on NixOS systems. All modules are held as separately as possible, to allow for easier sharing with other people mostly.homeManagerModules
imports modules that are to be used on NixOS and non-NixOS systems. These are mostly used to define outputs (monitors), keyboards and special commands for machines.packages
holds packages that I am building myself. These are mostly shell scripts, but also a few others such as AppImages and firefox addons.devShells
provides a development shell that can be used as a bootstrap for new installs using nix develop
while inside the flake directory. It received an overhaul in 0a6cf0e feat: add checks to devShell
, since when it is handled using forAllSystems
and now including pre-commit-hook checks.formatter
provides the formatter that is to be used on .nix
files. It can be called by using nix fmt
.check
provides the pre-commit-hook checks that I have explained in Pre-commit-hooks (Checks).
+overlays
imports a few community overlays (such as the emacs-overlay) and also three overlays of my own:
additions
holds derivations that I am adding myself to nixpkgs - i.e. this is where the packages defined in /pkgs
get added to nixpkgs.modifications
holds derivations that I have performed overrides on. The list of interesting attribute overrides can be found by looking at the source code of a derivation and looking at the start of the file for lines of the form <name> ? <val>
. But this can also be used to, for example, fetch a different version of a package instead.nixpkgs-stable
holds the newest version of stable nixpkgs. I only use this on packages that seem broken on unstable, which are not many.zjstatus
holds some options for zellij
, but I have stopped using it since I prefer tmux
.
+They are defined in Overlays (additions, overrides, nixpkgs-stable). The way this is handled was simplified in 647a2ae feat: simplify overlay structure
; however, the old structure might be easier to understand as a reference.
+
-{ - description = "SwarseFlake - Nix Flake for all SwarselSystems"; +inherit lib nixModules mixedModules homeModules; - nixConfig = { - extra-substituters = [ - "https://nix-community.cachix.org" - "https://cache.ngi0.nixos.org/" - ]; +nixosModules = import ./modules/nixos { inherit lib; }; +homeManagerModules = import ./modules/home { inherit lib; }; +packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); +formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); +overlays = import ./overlays { inherit self lib inputs; }; - extra-trusted-public-keys = [ - "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" - "cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=" +apps = lib.swarselsystems.forAllSystems (system: + let + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" ]; - }; + appSet = lib.swarselsystems.mkApps system appNames self; + in + { + inherit appSet; + default = appSet.bootstrap; + }); - inputs = { +devShells = lib.swarselsystems.forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + checks = self.checks.${system}; + in + { + default = pkgs.mkShell { + NIX_CONFIG = "experimental-features = nix-command flakes"; + inherit (checks.pre-commit-check) shellHook; + buildInputs = checks.pre-commit-check.enabledPackages; + nativeBuildInputs = with pkgs; [ + nix + home-manager + git + just + age + ssh-to-age + sops + statix + deadnix + nixpkgs-fmt + ]; + }; + } +); - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; +checks = lib.swarselsystems.forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + import ./checks { inherit self inputs system pkgs; } +); - nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05"; ++
+This section used to be much longer, since I performed all of my imports right here in the past. Since then, I have however refactored and now my important hosts can be defined in little space. Once I have fully transitioned my server to NixOS too this section will become even smaller once more. +
- systems.url = "github:nix-systems/default-linux"; +
+Note: The preceding nixosConfigurations
is found in flake.nix template. Also, the method of generating the hosts was changed in commit
+3a272b1 feat!: dynamically create hosts
, and the deprecated system definitions removed in 7457109 main chore: remove deprecated static host config
. See those commits for a state with a simpler config.
+
lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") "nixos"; ++
+And this defines darwin systems (MacOS), which I only have one of, that serves as a template mostly. +
- # nix user repository - # i use this mainly to not have to build all firefox extensions - # myself as well as for the emacs-init package (tbd) - nur.url = "github:nix-community/NUR"; +
+Note: The preceding darwinConfigurations
is found in flake.nix template. Also, the method of generating the hosts was changed in commit
+3a272b1 feat!: dynamically create hosts
, and the deprecated system definitions removed in 7457109 main chore: remove deprecated static host config
. See those commits for a state with a simpler config.
+
lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "darwin") "darwin"; ++
+In contrast, this defines home-manager systems, which I only have one of, that serves as a template mostly. +
- # manages all theming using Home-Manager - stylix.url = "github:danth/stylix"; ++# "swarsel@home-manager" = inputs.home-manager.lib.homeManagerConfiguration { +# pkgs = lib.swarselsystems.pkgsFor.x86_64-linux; +# extraSpecialArgs = { inherit inputs outputs; }; +# modules = homeModules ++ mixedModules ++ [ +# ./hosts/home-manager +# ]; +# }; - # nix secrets management - sops-nix.url = "github:Mic92/sops-nix"; +lib.swarselsystems.mkHalfHostConfigs (lib.swarselsystems.readHosts "home") "home" lib.swarselsystems.pkgsFor.x86_64-linux; ++
+Nix on Android also demands an own flake output, which is provided here. +
- # enable secure boot on NixOS - lanzaboote.url = "github:nix-community/lanzaboote"; ++# magicant = inputs.nix-on-droid.lib.nixOnDroidConfiguration { +# pkgs = lib.swarselsystems.pkgsFor.aarch64-linux; +# modules = [ +# ./hosts/magicant +# ]; +# }; - # nix for android - nix-on-droid = { - url = "github:nix-community/nix-on-droid/release-24.05"; - inputs.nixpkgs.follows = "nixpkgs"; - }; +lib.swarselsystems.mkHalfHostConfigs (lib.swarselsystems.readHosts "android") "android" lib.swarselsystems.pkgsFor.aarch64-linux; - # generate NixOS images - nixos-generators = { - url = "github:nix-community/nixos-generators"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # hardware quirks on nix - nixos-hardware = { - url = "github:NixOS/nixos-hardware/master"; - }; - - # dynamic library loading - nix-alien = { - url = "github:thiagokokada/nix-alien"; - }; - - # automatic nintendo switch payload injection - nswitch-rcm-nix = { - url = "github:Swarsel/nswitch-rcm-nix"; - }; - - # weekly updated nix-index database - nix-index-database = { - url = "github:nix-community/nix-index-database"; - inputs.nixpkgs.follows = "nixpkgs"; - }; ++
+lib.swarselsystems.forEachSystem (pkgs: import inputs.nix-topology { + inherit pkgs; + modules = [ + # Your own file to define global topology. Works in principle like a nixos module but uses different options. + # ./topology.nix + { inherit (self) nixosConfigurations; } + ]; +}); - disko = { - url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; - }; ++
+This holds most of the NixOS side of configuration. +
+
+This section mainly exists house different `default.nix` files to define some modules that should be loaded on respective systems.
+Every host is housed in the hosts/
directory, which is then subdivided by each respective system (nixos/
, home-manager/
, nix-on-droid/
, darwin/
). As described earlier, some of these configurations (nixos and darwin) can be defined automatically in this flake. For home-manager and nix-on-droid, the system architecture must be defined manually.
+
+This is the template that I use for new deployments of personal machines. Servers are usually highly tailored to their specific task and I do not consider it worth a time to craft a template for that. Also, at least at the current time, I only provide a template for NixOS hosts, as I rarely ever use anything else. +
+{ self, inputs, outputs, config, pkgs, lib, ... }: +let + profilesPath = "${self}/profiles"; + sharedOptions = { + isBtrfs = true; + }; +in +{ - impermanence.url = "github:nix-community/impermanence"; + imports = outputs.nixModules ++ [ + # ---- nixos-hardware here ---- - zjstatus = { - url = "github:dj95/zjstatus"; - }; + ./hardware-configuration.nix + ./disk-config.nix - fw-fanctrl = { - url = "github:TamtamHero/fw-fanctrl/packaging/nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + "${profilesPath}/optional/nixos/virtualbox.nix" + # "${profilesPath}/optional/nixos/vmware.nix" + "${profilesPath}/optional/nixos/autologin.nix" + "${profilesPath}/optional/nixos/nswitch-rcm.nix" + "${profilesPath}/optional/nixos/gaming.nix" - nix-darwin = { - url = "github:lnl7/nix-darwin"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + inputs.home-manager.nixosModules.home-manager + { + home-manager.users.swarsel.imports = outputs.mixedModules ++ [ + "${profilesPath}/optional/home/gaming.nix" + ] ++ (builtins.attrValues outputs.homeManagerModules); + } + ] ++ (builtins.attrValues outputs.nixosModules); - pre-commit-hooks = { - url = "github:cachix/git-hooks.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nix-secrets = { - url = "git+ssh://git@github.com/Swarsel/nix-secrets.git?ref=main&shallow=1"; - flake = false; - inputs = { }; + nixpkgs = { + overlays = [ outputs.overlays.default ]; + config = { + allowUnfree = true; }; - - nix-topology.url = "github:oddlama/nix-topology"; - }; - outputs = - inputs@{ self - , nixpkgs - , home-manager - , nix-darwin - , systems - , ... - }: - let + boot = { + kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + }; - inherit (self) outputs; - lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; }); + networking = { + hostName = "TEMPLATE"; + firewall.enable = true; + }; + swarselsystems = lib.recursiveUpdate + { + wallpaper = self + /wallpaper/lenovowp.png; + hasBluetooth = true; + hasFingerprint = true; + isImpermanence = true; + isSecureBoot = true; + isCrypted = true; + isSwap = true; + swapSize = "32G"; + rootDisk = "TEMPLATE"; + } + sharedOptions; - # NixOS modules that can only be used on NixOS systems - nixModules = [ - inputs.stylix.nixosModules.stylix - inputs.lanzaboote.nixosModules.lanzaboote - inputs.disko.nixosModules.disko - inputs.impermanence.nixosModules.impermanence - inputs.sops-nix.nixosModules.sops - inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm - inputs.nix-topology.nixosModules.default - ./profiles/common/nixos + home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate + { + isLaptop = true; + isNixos = true; + flakePath = "/home/swarsel/.dotfiles"; + cpuCount = 16; + startup = [ + { command = "nextcloud --background"; } + { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } + { 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"; } + { command = "feishin"; } ]; + } + sharedOptions; +} ++
+Acceptance of arbitraty argumments is here needed because disko
passes diskoFile
to this file.
+
{ lib, pkgs, config, rootDisk, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" ]; - - # Home-Manager modules wanted on both NixOS and non-NixOS systems - mixedModules = [ - inputs.sops-nix.homeManagerModules.sops - inputs.nix-index-database.hmModules.nix-index - ./profiles/common/home + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" ]; - - in - { - - inherit lib; - inherit mixedModules; - inherit nixModules; - - nixosModules = import ./modules/nixos; - homeManagerModules = import ./modules/home; - - packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib; }); - - apps = lib.swarselsystems.forAllSystems (system: let - appNames = [ - "swarsel-bootstrap" - "swarsel-install" - "swarsel-rebuild" - "swarsel-postinstall" - ]; - appSet = lib.swarselsystems.mkApps system appNames self; - in { - inherit appSet; - default = appSet.bootstrap; - }); - - devShells = lib.swarselsystems.forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - NIX_CONFIG = "experimental-features = nix-command flakes"; - inherit (checks.pre-commit-check) shellHook; - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; }; - }); - - formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); - checks = lib.swarselsystems.forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - import ./checks { inherit self inputs system pkgs; } - ); - overlays = import ./overlays { inherit pkgs; }; - - - nixosConfigurations = - lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") true; - - homeConfigurations = { - - "swarsel@home-manager" = inputs.home-manager.lib.homeManagerConfiguration { - pkgs = lib.swarselsystems.pkgsFor.x86_64-linux; - extraSpecialArgs = { inherit inputs outputs; }; - modules = homeModules ++ mixedModules ++ [ - ./hosts/home-manager - ]; - }; - - }; - - darwinConfigurations = - lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "darwin") false; - - nixOnDroidConfigurations = { - - magicant = inputs.nix-on-droid.lib.nixOnDroidConfiguration { - pkgs = lib.swarselsystems.pkgsFor.aarch64-linux; - modules = [ - ./hosts/magicant - ]; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; }; - }; - - topology = - - lib.swarselsystems.forEachSystem (pkgs: import inputs.nix-topology { - inherit pkgs; - modules = [ - # Your own file to define global topology. Works in principle like a nixos module but uses different options. - # ./topology.nix - { inherit (self) nixosConfigurations; } - ]; - }); - - }; -} - + }; + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + environment.systemPackages = [ + pkgs.yubikey-manager + ]; +}
-This file defines a number of checks that can either be run by calling nix flake check
or while in a nix-shell
or nix develop
. This helps me make sure that my flake confirms to my self-imposed standards. The GitHub actions perform less checks than are being done here (they are only checking the formatting, as well as statix
and deadnix
)
+This is a list of all physical machines that I maintain.
+My work machine. Built for more security, this is the gold standard of my configurations at the moment. +
+{ self, inputs, pkgs, system, ... }: -{ - pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { - src = "${self}"; - hooks = { - check-added-large-files.enable = true; - check-case-conflicts.enable = true; - check-executables-have-shebangs.enable = true; - check-shebang-scripts-are-executable.enable = false; - check-merge-conflicts.enable = true; - deadnix.enable = true; - detect-private-keys.enable = true; - end-of-file-fixer.enable = true; - fix-byte-order-marker.enable = true; - flake-checker.enable = true; - forbid-new-submodules.enable = true; - mixed-line-endings.enable = true; - nixpkgs-fmt.enable = true; - statix.enable = true; - trim-trailing-whitespace.enable = true; - - destroyed-symlinks = { - enable = true; - entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; - }; - - shellcheck = { - enable = true; - entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; - }; - - shfmt = { - enable = true; - entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; - }; - - }; +{ self, inputs, outputs, config, pkgs, lib, ... }: +let + profilesPath = "${self}/profiles"; + sharedOptions = { + isBtrfs = true; }; -} --
-Here we define inputs and outputs of the flake. First, the following list is for the outputs of the flake. -
- --Format: <name>, -
- -
-Mind the comma at the end. You need this because the ...
is being passed as the last argument in the template at flake.nix template.
-
-Here, just add the input names, urls and other options that are needed, like nixpkgs.follows
. By using the latter option, you tell the package to not provide it's own package repository, but instead 'nest' itself into another, which is very useful.
-A short overview over each input and what it does:
-
~/.config/
.steam-run
. However, I have not yet gotten this to work.nix-index
that is updated weekly. This allows for declarative management, without needing to run the nix-index
command for database assembly.secretsFile
(or similar) option. An example is the LastFM.ApiKey
option in navidrome:
-LastFM.ApiKey = builtins.readFile "${secretsDirectory}/navidrome/lastfm-secret";
-When setting this option normally, the password would normally be written world-readable not only in the nix store, but also in the configuration. Hence, I put such passwords into a private repository. This allows me to keep purity of the flake while keeping a level of security on these secrets. -
--nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - -nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05"; - -systems.url = "github:nix-systems/default-linux"; - -# user-level configuration -home-manager = { - url = "github:nix-community/home-manager"; - inputs.nixpkgs.follows = "nixpkgs"; -}; - -# overlay to access bleeding edge emacs -emacs-overlay = { - url = "github:nix-community/emacs-overlay"; - inputs.nixpkgs.follows = "nixpkgs"; -}; - -# nix user repository -# i use this mainly to not have to build all firefox extensions -# myself as well as for the emacs-init package (tbd) -nur.url = "github:nix-community/NUR"; - -# provides GL to non-NixOS hosts -nixgl.url = "github:guibou/nixGL"; - -# manages all theming using Home-Manager -stylix.url = "github:danth/stylix"; +in +{ -# nix secrets management -sops-nix.url = "github:Mic92/sops-nix"; + imports = outputs.nixModules ++ [ + inputs.nixos-hardware.nixosModules.framework-16-7040-amd + inputs.fw-fanctrl.nixosModules.default -# enable secure boot on NixOS -lanzaboote.url = "github:nix-community/lanzaboote"; + ./hardware-configuration.nix + ./disk-config.nix -# nix for android -nix-on-droid = { - url = "github:nix-community/nix-on-droid/release-24.05"; - inputs.nixpkgs.follows = "nixpkgs"; -}; + "${profilesPath}/optional/nixos/virtualbox.nix" + # "${profilesPath}/optional/nixos/vmware.nix" + "${profilesPath}/optional/nixos/autologin.nix" + "${profilesPath}/optional/nixos/nswitch-rcm.nix" + "${profilesPath}/optional/nixos/gaming.nix" + "${profilesPath}/optional/nixos/work.nix" -# generate NixOS images -nixos-generators = { - url = "github:nix-community/nixos-generators"; - inputs.nixpkgs.follows = "nixpkgs"; -}; + inputs.home-manager.nixosModules.home-manager + { + home-manager.users.swarsel.imports = outputs.mixedModules ++ [ + "${profilesPath}/optional/home/gaming.nix" + "${profilesPath}/optional/home/work.nix" + ] ++ (builtins.attrValues outputs.homeManagerModules); + } + ] ++ (builtins.attrValues outputs.nixosModules); -# hardware quirks on nix -nixos-hardware = { - url = "github:NixOS/nixos-hardware/master"; -}; -# dynamic library loading -nix-alien = { - url = "github:thiagokokada/nix-alien"; -}; + nixpkgs = { + overlays = [ outputs.overlays.default ]; + config = { + allowUnfree = true; + }; + }; -# automatic nintendo switch payload injection -nswitch-rcm-nix = { - url = "github:Swarsel/nswitch-rcm-nix"; -}; + networking.networkmanager.wifi.scanRandMacAddress = false; -# weekly updated nix-index database -nix-index-database = { - url = "github:nix-community/nix-index-database"; - inputs.nixpkgs.follows = "nixpkgs"; -}; + boot = { + supportedFilesystems = [ "btrfs" ]; + kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + kernelParams = [ + "resume_offset=533760" + ]; + resumeDevice = "/dev/disk/by-label/nixos"; + }; -disko = { - url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; -}; + hardware = { + amdgpu = { + opencl.enable = true; + amdvlk = { + enable = true; + support32Bit.enable = true; + }; + }; + }; -impermanence.url = "github:nix-community/impermanence"; + programs.fw-fanctrl.enable = true; -zjstatus = { - url = "github:dj95/zjstatus"; -}; + networking = { + hostName = "nbl-imba-2"; + fqdn = "nbl-imba-2.imp.univie.ac.at"; + firewall.enable = true; + }; -fw-fanctrl = { - url = "github:TamtamHero/fw-fanctrl/packaging/nix"; - inputs.nixpkgs.follows = "nixpkgs"; -}; -nix-darwin = { - url = "github:lnl7/nix-darwin"; - inputs.nixpkgs.follows = "nixpkgs"; -}; + services = { + fwupd.enable = true; + udev.extraRules = '' + ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0bda", ATTR{idProduct}=="8156", ATTR{power/autosuspend}="20" + ''; + }; -pre-commit-hooks = { - url = "github:cachix/git-hooks.nix"; - inputs.nixpkgs.follows = "nixpkgs"; -}; + swarselsystems = lib.recursiveUpdate { + wallpaper = self + /wallpaper/lenovowp.png; + hasBluetooth = true; + hasFingerprint = true; + isImpermanence = false; + isSecureBoot = true; + isCrypted = true; + } sharedOptions; -nix-secrets = { - url = "git+ssh://git@github.com/Swarsel/nix-secrets.git?ref=main&shallow=1"; - flake = false; - inputs = { }; -}; + home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate { + isLaptop = true; + isNixos = true; + flakePath = "/home/swarsel/.dotfiles"; + cpuCount = 16; + # temperatureHwmon = { + # isAbsolutePath = true; + # path = "/sys/devices/platform/thinkpad_hwmon/hwmon/"; + # input-filename = "temp1_input"; + # }; + # ------ ----- + # | DP-4 | |eDP-1| + # ------ ----- + startup = [ + { command = "nextcloud --background"; } + { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } + { 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"; } + { command = "teams-for-linux"; } + { command = "1password"; } + { command = "feishin"; } + ]; + sharescreen = "eDP-2"; + lowResolution = "1280x800"; + highResolution = "2560x1600"; + monitors = { + main = { + name = "BOE 0x0BC9 Unknown"; + mode = "2560x1600"; # TEMPLATE + scale = "1"; + position = "2560,0"; + workspace = "15:L"; + output = "eDP-2"; + }; + homedesktop = { + name = "Philips Consumer Electronics Company PHL BDM3270 AU11806002320"; + mode = "2560x1440"; + scale = "1"; + position = "0,0"; + workspace = "1:一"; + output = "DP-11"; + }; + work_back_middle = { + name = "LG Electronics LG Ultra HD 0x000305A6"; + mode = "2560x1440"; + scale = "1"; + position = "5120,0"; + workspace = "1:一"; + output = "DP-10"; + }; + work_front_left = { + name = "LG Electronics LG Ultra HD 0x0007AB45"; + mode = "3840x2160"; + scale = "1"; + position = "5120,0"; + workspace = "1:一"; + output = "DP-7"; + }; + work_back_right = { + name = "HP Inc. HP Z32 CN41212T55"; + mode = "3840x2160"; + scale = "1"; + position = "5120,0"; + workspace = "1:一"; + output = "DP-3"; + }; + work_middle_middle_main = { + name = "HP Inc. HP 732pk CNC4080YL5"; + mode = "3840x2160"; + scale = "1"; + position = "-1280,0"; + workspace = "11:M"; + output = "DP-8"; + }; + work_middle_middle_side = { + name = "Hewlett Packard HP Z24i CN44250RDT"; + mode = "1920x1200"; + transform = "270"; + scale = "1"; + position = "-2480,0"; + workspace = "12:S"; + output = "DP-9"; + }; + work_seminary = { + name = "Applied Creative Technology Transmitter QUATTRO201811"; + mode = "1280x720"; + scale = "1"; + position = "10000,10000"; # i.e. this screen is inaccessible by moving the mouse + workspace = "12:S"; + output = "DP-4"; + }; + }; + inputs = { + "12972:18:Framework_Laptop_16_Keyboard_Module_-_ANSI_Keyboard" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + "1133:45081:MX_Master_2S_Keyboard" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + "2362:628:PIXA3854:00_093A:0274_Touchpad" = { + dwt = "enabled"; + tap = "enabled"; + natural_scroll = "enabled"; + middle_emulation = "enabled"; + }; + "1133:50504:Logitech_USB_Receiver" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + "1133:45944:MX_KEYS_S" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + }; + keybindings = { + "Mod4+Ctrl+Shift+p" = "exec screenshare"; + }; + shellAliases = { + ans2-15_3-9 = ". ~/.venvs/ansible39_2_15_0/bin/activate"; + ans3-9 = ". ~/.venvs/ansible39/bin/activate"; + ans = ". ~/.venvs/ansible/bin/activate"; + ans2-15 = ". ~/.venvs/ansible2.15.0/bin/activate"; + }; + } sharedOptions; +} -nix-topology.url = "github:oddlama/nix-topology";
-Here I define a few variables that I need for my system specifications. First and foremost, pkgs
, which gets passed the emacs-overlay, nur, and nixgl modules to it. With this, I can grab all these packages by referencing pkgs.<name>
instead of having to put e.g. nixgl.auto.nixGLDefault
.
-
-I also define some common module lists that I can simply load depending on the fundamental system (NixOS vs. non-NixOS) - nixModules
, homeModules
, and mixedModules
.
-
-The interesting part is in the start: -
-pkgsFor
. This function reads all available systems from nixpkgs and generates pkgs for them.forEachSystem
is a function that can be called to declare an output for each such defined system.forAllSystems
is a crude function that I use for expressions that depend on system
, as the prior two attributes already consumed it at that stage. This is only really used to generate the checks in their own file.mkFullHost
is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching nixosSystem
or darwinSystem
. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options).mkFullHostConfigs
is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in hosts/
under either the nixos/
or darwin/
directory. These directories are being read by readHosts
and delivered to this funtion in the later call in nixosConfigurations or darwinConfigurations.-inherit (self) outputs; -lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; }); +{ config, lib, modulesPath, ... }: +{ + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "cryptd" "usbhid" "sd_mod" "r8152" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + + # Fix screen flickering issue at the cost of battery life (disable PSR and PSR-SU, keep PR enabled) + # TODO: figure out if this is worth it + # test PSR/PR state with 'sudo grep '' /sys/kernel/debug/dri/0000*/eDP-2/*_capability' + # ref: + # https://old.reddit.com/r/framework/comments/1goh7hc/anyone_else_get_this_screen_flickering_issue/ + # https://www.reddit.com/r/NixOS/comments/1hjruq1/graphics_corruption_on_kernel_6125_and_up/ + # https://gitlab.freedesktop.org/drm/amd/-/issues/3797 + boot.kernelParams = [ "amdgpu.dcdebugmask=0x410" ]; + + boot.extraModulePackages = [ ]; + boot.initrd.luks.devices."cryptroot" = { + # improve performance on ssds + bypassWorkqueues = true; + preLVM = true; + }; -# NixOS modules that can only be used on NixOS systems -nixModules = [ - inputs.stylix.nixosModules.stylix - inputs.lanzaboote.nixosModules.lanzaboote - inputs.disko.nixosModules.disko - inputs.impermanence.nixosModules.impermanence - inputs.sops-nix.nixosModules.sops - inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm - inputs.nix-topology.nixosModules.default - ./profiles/common/nixos -]; + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp196s0f3u1c2.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp4s0.useDHCP = lib.mkDefault true; -# Home-Manager modules wanted on non-NixOS systems -homeModules = [ - inputs.stylix.homeManagerModules.stylix -]; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} -# Home-Manager modules wanted on both NixOS and non-NixOS systems -mixedModules = [ - inputs.sops-nix.homeManagerModules.sops - inputs.nix-index-database.hmModules.nix-index - ./profiles/common/home -];
-In this section I am creating some attributes that define general concepts of my configuration: -
- -nixosModules
imports self-defined options that I only want to use on NixOS systems. All modules are held as separately as possible, to allow for easier sharing with other people mostly.homeManagerModules
imports modules that are to be used on NixOS and non-NixOS systems. These are mostly used to define outputs (monitors), keyboards and special commands for machines.packages
holds packages that I am building myself. These are mostly shell scripts, but also a few others such as AppImages and firefox addons.devShells
provides a development shell that can be used as a bootstrap for new installs using nix develop
while inside the flake directory. It received an overhaul in 0a6cf0e feat: add checks to devShell
, since when it is handled using forAllSystems
and now including pre-commit-hook checks.formatter
provides the formatter that is to be used on .nix
files. It can be called by using nix fmt
.check
provides the pre-commit-hook checks that I have explained in Pre-commit-hooks (Checks).
-overlays
imports a few community overlays (such as the emacs-overlay) and also three overlays of my own:
-
additions
holds derivations that I am adding myself to nixpkgs - i.e. this is where the packages defined in /pkgs
get added to nixpkgs.modifications
holds derivations that I have performed overrides on. The list of interesting attribute overrides can be found by looking at the source code of a derivation and looking at the start of the file for lines of the form <name> ? <val>
. But this can also be used to, for example, fetch a different version of a package instead.nixpkgs-stable
holds the newest version of stable nixpkgs. I only use this on packages that seem broken on unstable, which are not many.zjstatus
holds some options for zellij
, but I have stopped using it since I prefer tmux
.
-They are defined in Overlays (additions, overrides, nixpkgs-stable). The way this is handled was simplified in 647a2ae feat: simplify overlay structure
; however, the old structure might be easier to understand as a reference.
-
-inherit lib; -inherit mixedModules; -inherit nixModules; - -nixosModules = import ./modules/nixos; -homeManagerModules = import ./modules/home; - -packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib; }); - -apps = lib.swarselsystems.forAllSystems (system: let - appNames = [ - "swarsel-bootstrap" - "swarsel-install" - "swarsel-rebuild" - "swarsel-postinstall" - ]; - appSet = lib.swarselsystems.mkApps system appNames self; -in { - inherit appSet; - default = appSet.bootstrap; -}); - -devShells = lib.swarselsystems.forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - NIX_CONFIG = "experimental-features = nix-command flakes"; - inherit (checks.pre-commit-check) shellHook; - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - ]; +{ + disko.devices = { + disk = { + nvme0n1 = { + type = "disk"; + device = "/dev/nvme0n1"; + content = { + type = "gpt"; + partitions = { + ESP = { + label = "boot"; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ + "defaults" + ]; + }; + }; + luks = { + size = "100%"; + label = "luks"; + content = { + type = "luks"; + name = "cryptroot"; + extraOpenArgs = [ + "--allow-discards" + "--perf-no_read_workqueue" + "--perf-no_write_workqueue" + ]; + # https://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html + settings = { crypttabExtraOpts = [ "fido2-device=auto" "token-timeout=10" ]; }; + content = { + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ "subvol=root" "compress=zstd" "noatime" ]; + }; + "/home" = { + mountpoint = "/home"; + mountOptions = [ "subvol=home" "compress=zstd" "noatime" ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ "subvol=nix" "compress=zstd" "noatime" ]; + }; + "/persist" = { + mountpoint = "/persist"; + mountOptions = [ "subvol=persist" "compress=zstd" "noatime" ]; + }; + "/log" = { + mountpoint = "/var/log"; + mountOptions = [ "subvol=log" "compress=zstd" "noatime" ]; + }; + "/swap" = { + mountpoint = "/swap"; + swap.swapfile.size = "64G"; + }; + }; + }; + }; + }; + }; + }; }; - }); + }; + }; -formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); -checks = lib.swarselsystems.forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - import ./checks { inherit self inputs system pkgs; } -); -overlays = import ./overlays { inherit pkgs; }; + fileSystems."/persist".neededForBoot = true; + fileSystems."/var/log".neededForBoot = true; +}
-This section used to be much longer, since I performed all of my imports right here in the past. Since then, I have however refactored and now my important hosts can be defined in little space. Once I have fully transitioned my server to NixOS too this section will become even smaller once more. +This is my main server that I run at home. It handles most tasks that require bigger amounts of storage than I can receive for free at OCI. Also it houses some data that I find too sensitive to hand over to Oracle.
+{ self, inputs, outputs, config, ... }: +let + profilesPath = "${self}/profiles"; +in +{ --Note: The preceding
+ imports = [ + inputs.sops-nix.nixosModules.sops + + ./hardware-configuration.nix + + "${profilesPath}/optional/nixos/autologin.nix" + "${profilesPath}/server/nixos" + + inputs.home-manager.nixosModules.home-manager + { + home-manager.users.swarsel.imports = [ + "${profilesPath}/server/home" + ] ++ (builtins.attrValues outputs.homeManagerModules); + } + + ] ++ (builtins.attrValues outputs.nixosModules); + + + nixpkgs = { + overlays = [ outputs.overlays.default ]; + config = { + allowUnfree = true; + }; + }; + + boot = { + loader.systemd-boot.enable = true; + loader.efi.canTouchEfiVariables = true; + }; + + networking = { + hostName = "winters"; + hostId = "b7778a4a"; + firewall.enable = true; + enableIPv6 = false; + firewall.allowedTCPPorts = [ 80 443 ]; + }; + + + swarselsystems = { + hasBluetooth = false; + hasFingerprint = false; + isImpermanence = false; + isBtrfs = false; + flakePath = "/home/swarsel/.dotfiles"; + server = { + enable = true; + kavita = true; + navidrome = true; + jellyfin = true; + spotifyd = true; + mpd = false; + matrix = true; + nextcloud = true; + immich = true; + paperless = true; + transmission = true; + syncthing = true; + monitoring = true; + freshrss = true; + }; + }; + +} -nixosConfigurations
is found in flake.nix template. Also, the method of generating the hosts was changed in commit -3a272b1 feat!: dynamically create hosts
, and the deprecated system definitions removed in7457109 main chore: remove deprecated static host config
. See those commits for a state with a simpler config. --lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") true;
-And this defines darwin systems (MacOS), which I only have one of, that serves as a template mostly. -
+{ config, lib, modulesPath, ... }: --Note: The preceding
+{ + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; -darwinConfigurations
is found in flake.nix template. Also, the method of generating the hosts was changed in commit -3a272b1 feat!: dynamically create hosts
, and the deprecated system definitions removed in7457109 main chore: remove deprecated static host config
. See those commits for a state with a simpler config. --lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "darwin") false; + boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + boot.supportedFilesystems = [ "zfs" ]; + boot.zfs.extraPools = [ "Vault" ]; + + fileSystems."/" = + { + device = "/dev/disk/by-uuid/30e2f96a-b01d-4c27-9ebb-d5d7e9f0031f"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { + device = "/dev/disk/by-uuid/F0D8-8BD1"; + fsType = "vfat"; + }; + + swapDevices = + [{ device = "/dev/disk/by-uuid/a8eb6f3b-69bf-4160-90aa-9247abc108e0"; }]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +}
-In contrast, this defines home-manager systems, which I only have one of, that serves as a template mostly. +A Mac notebook that I have received from work. I use this machine for getting accustomed to the Apple ecosystem as well as as a sandbox for nix-darwin configurations.
-"swarsel@home-manager" = inputs.home-manager.lib.homeManagerConfiguration { - pkgs = lib.swarselsystems.pkgsFor.x86_64-linux; - extraSpecialArgs = { inherit inputs outputs; }; - modules = homeModules ++ mixedModules ++ [ - ./hosts/home-manager - ]; -}; +{ self, inputs, outputs, ... }: +let + profilesPath = "${self}/profiles"; +in +{ + imports = [ + "${profilesPath}/darwin/common/nixos" + + inputs.home-manager.darwinModules.home-manager + { + home-manager.users."leon.schwarzaeugl".imports = [ + "${profilesPath}/darwin/common/home" + ] ++ (builtins.attrValues outputs.homeManagerModules); + } + ] ++ (builtins.attrValues outputs.nixosModules); + + + # Auto upgrade nix package and the daemon service. + services.nix-daemon.enable = true; + services.karabiner-elements.enable = true; + home-manager.users."leon.schwarzaeugl".home = { + username = lib.mkForce "leon.schwarzaeugl"; + swarselsystems = { + isDarwin = true; + isLaptop = true; + isNixos = false; + isBtrfs = false; + }; + }; +}
-Nix on Android also demands an own flake output, which is provided here. +My phone. I use only a minimal config for remote debugging here.
-magicant = inputs.nix-on-droid.lib.nixOnDroidConfiguration { - pkgs = lib.swarselsystems.pkgsFor.aarch64-linux; - modules = [ - ./hosts/magicant - ]; -}; +{ pkgs, ... }: { + environment = { + packages = with pkgs; [ + vim + git + openssh + # toybox + dig + man + gnupg + curl + deadnix + statix + nixpgks-fmt + nvd + ]; + + etcBackupExtension = ".bak"; + extraOutputsToInstall = [ + "doc" + "info" + "devdoc" + ]; + motd = null; + }; + + android-integration = { + termux-open.enable = true; + xdg-open.enable = true; + termux-open-url.enable = true; + termux-reload-settings.enable = true; + termux-setup-storage.enable = true; + }; + + # Backup etc files instead of failing to activate generation if a file already exists in /etc + + # Read the changelog before changing this value + system.stateVersion = "23.05"; + + # Set up nix for flakes + nix.extraOptions = '' + experimental-features = nix-command flakes + ''; +} --
-lib.swarselsystems.forEachSystem (pkgs: import inputs.nix-topology { - inherit pkgs; - modules = [ - # Your own file to define global topology. Works in principle like a nixos module but uses different options. - # ./topology.nix - { inherit (self) nixosConfigurations; } - ]; -});
-This holds most of the NixOS side of configuration. +My server setup was originally 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 was for a long time rewriting all machines on there to use NixOS instead; this process is now finished.
-
-This section mainly exists house different `default.nix` files to define some modules that should be loaded on respective systems.
-Every host is housed in the hosts/
directory, which is then subdivided by each respective system (nixos/
, home-manager/
, nix-on-droid/
, darwin/
). As described earlier, some of these configurations (nixos and darwin) can be defined automatically in this flake. For home-manager and nix-on-droid, the system architecture must be defined manually.
+I have removed most of the machines from this section. What remains are some hosts that I have deployed on OCI (mostly sync for medium-important data) and one other machine that I left for now as a reference.
-This is a list of all physical machines that I maintain. +This machine mainly acts as an external sync helper. It manages the following things:
--My work machine. Built for more security, this is the gold standard of my configurations at the moment. +
+Syncthing backup of replaceable data
++All of these are processes that use little cpu but can take a lot of storage. For this I use a free Ampere instance from OCI with 50G of space. In case my account gets terminated, all of this data is easily replaceable or backed up regularly anyways. +
{ self, inputs, outputs, config, pkgs, lib, ... }: +{ self, inputs, outputs, lib, ... }: let profilesPath = "${self}/profiles"; - sharedOptions = { - isBtrfs = true; - }; in { + imports = [ - imports = outputs.nixModules ++ [ - inputs.nixos-hardware.nixosModules.framework-16-7040-amd - inputs.fw-fanctrl.nixosModules.default - + inputs.sops-nix.nixosModules.sops + "${profilesPath}/server/nixos" ./hardware-configuration.nix - ./disk-config.nix - - "${profilesPath}/optional/nixos/virtualbox.nix" - # "${profilesPath}/optional/nixos/vmware.nix" - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/optional/nixos/nswitch-rcm.nix" - "${profilesPath}/optional/nixos/gaming.nix" - "${profilesPath}/optional/nixos/work.nix" inputs.home-manager.nixosModules.home-manager { - home-manager.users.swarsel.imports = outputs.mixedModules ++ [ - "${profilesPath}/optional/home/gaming.nix" - "${profilesPath}/optional/home/work.nix" + home-manager.users.swarsel.imports = [ + "${profilesPath}/server/home" ] ++ (builtins.attrValues outputs.homeManagerModules); } + ] ++ (builtins.attrValues outputs.nixosModules); + sops = { + defaultSopsFile = lib.mkForce "/root/.dotfiles/secrets/sync/secrets.yaml"; + }; - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; + + services.nginx = { + virtualHosts = { + "sync.swarsel.win" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://localhost:8384/"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; }; }; - networking.networkmanager.wifi.scanRandMacAddress = false; - boot = { - supportedFilesystems = [ "btrfs" ]; - kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; - kernelParams = [ - "resume_offset=533760" - ]; - resumeDevice = "/dev/disk/by-label/nixos"; + tmp.cleanOnBoot = true; + loader.grub.device = "nodev"; }; - - hardware = { - amdgpu = { - opencl.enable = true; - amdvlk = { - enable = true; - support32Bit.enable = true; - }; - }; - }; - - programs.fw-fanctrl.enable = true; + zramSwap.enable = false; networking = { - hostName = "nbl-imba-2"; - fqdn = "nbl-imba-2.imp.univie.ac.at"; - firewall.enable = true; + firewall.allowedTCPPorts = [ 8384 22000 ]; + firewall.allowedUDPPorts = [ 21027 22000 ]; + hostName = "sync"; + enableIPv6 = false; + domain = "subnet03112148.vcn03112148.oraclevcn.com"; + 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 + iptables -I INPUT -m state --state NEW -p tcp --dport 9812 -j ACCEPT + ''; }; + # system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change - services = { - fwupd.enable = true; - udev.extraRules = '' - ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0bda", ATTR{idProduct}=="8156", ATTR{power/autosuspend}="20" - ''; + # do not manage OCI syncthing through nix config + services.syncthing = { + enable = true; + guiAddress = "0.0.0.0:8384"; + openDefaultPorts = true; }; - swarselsystems = lib.recursiveUpdate { - wallpaper = self + /wallpaper/lenovowp.png; - hasBluetooth = true; - hasFingerprint = true; - isImpermanence = false; - isSecureBoot = true; - isCrypted = true; - } sharedOptions; - home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate { - isLaptop = true; - isNixos = true; - flakePath = "/home/swarsel/.dotfiles"; - cpuCount = 16; - # temperatureHwmon = { - # isAbsolutePath = true; - # path = "/sys/devices/platform/thinkpad_hwmon/hwmon/"; - # input-filename = "temp1_input"; - # }; - # ------ ----- - # | DP-4 | |eDP-1| - # ------ ----- - startup = [ - { command = "nextcloud --background"; } - { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } - { 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"; } - { command = "teams-for-linux"; } - { command = "1password"; } - { command = "feishin"; } - ]; - sharescreen = "eDP-2"; - lowResolution = "1280x800"; - highResolution = "2560x1600"; - monitors = { - main = { - name = "BOE 0x0BC9 Unknown"; - mode = "2560x1600"; # TEMPLATE - scale = "1"; - position = "2560,0"; - workspace = "15:L"; - output = "eDP-2"; - }; - homedesktop = { - name = "Philips Consumer Electronics Company PHL BDM3270 AU11806002320"; - mode = "2560x1440"; - scale = "1"; - position = "0,0"; - workspace = "1:一"; - output = "DP-11"; - }; - work_back_middle = { - name = "LG Electronics LG Ultra HD 0x000305A6"; - mode = "2560x1440"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-10"; - }; - work_front_left = { - name = "LG Electronics LG Ultra HD 0x0007AB45"; - mode = "3840x2160"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-7"; - }; - work_back_right = { - name = "HP Inc. HP Z32 CN41212T55"; - mode = "3840x2160"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-3"; - }; - work_middle_middle_main = { - name = "HP Inc. HP 732pk CNC4080YL5"; - mode = "3840x2160"; - scale = "1"; - position = "-1280,0"; - workspace = "11:M"; - output = "DP-8"; - }; - work_middle_middle_side = { - name = "Hewlett Packard HP Z24i CN44250RDT"; - mode = "1920x1200"; - transform = "270"; - scale = "1"; - position = "-2480,0"; - workspace = "12:S"; - output = "DP-9"; - }; - work_seminary = { - name = "Applied Creative Technology Transmitter QUATTRO201811"; - mode = "1280x720"; - scale = "1"; - position = "10000,10000"; # i.e. this screen is inaccessible by moving the mouse - workspace = "12:S"; - output = "DP-4"; - }; - }; - inputs = { - "12972:18:Framework_Laptop_16_Keyboard_Module_-_ANSI_Keyboard" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "1133:45081:MX_Master_2S_Keyboard" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "2362:628:PIXA3854:00_093A:0274_Touchpad" = { - dwt = "enabled"; - tap = "enabled"; - natural_scroll = "enabled"; - middle_emulation = "enabled"; - }; - "1133:50504:Logitech_USB_Receiver" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "1133:45944:MX_KEYS_S" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - }; - keybindings = { - "Mod4+Ctrl+Shift+p" = "exec screenshare"; - }; - shellAliases = { - ans2-15_3-9 = ". ~/.venvs/ansible39_2_15_0/bin/activate"; - ans3-9 = ". ~/.venvs/ansible39/bin/activate"; - ans = ". ~/.venvs/ansible/bin/activate"; - ans2-15 = ". ~/.venvs/ansible2.15.0/bin/activate"; + swarselsystems = { + hasBluetooth = false; + hasFingerprint = false; + isImpermanence = false; + isBtrfs = false; + flakePath = "/root/.dotfiles"; + server = { + enable = true; + forgejo = true; + ankisync = true; }; - } sharedOptions; -} + }; +}
-This is my main server that I run at home. It handles most tasks that require bigger amounts of storage than I can receive for free at OCI. Also it houses some data that I find too sensitive to hand over to Oracle. +This is a slim setup for developing base configuration. I do not track the hardware-configuration for this host here because I often switch this configuration between running on a QEMU VM and a physical laptop and do not want to constantly adapt the config here to reflect the current state.
- +{ self, inputs, outputs, config, ... }: +{ self, inputs, outputs, config, pkgs, lib, ... }: let profilesPath = "${self}/profiles"; + sharedOptions = { + isBtrfs = true; + }; in { - imports = [ - inputs.sops-nix.nixosModules.sops - + imports = [ + inputs.disko.nixosModules.disko + "${self}/hosts/nixos/toto/disk-config.nix" ./hardware-configuration.nix - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/server/nixos" + inputs.sops-nix.nixosModules.sops + inputs.impermanence.nixosModules.impermanence + inputs.lanzaboote.nixosModules.lanzaboote - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - "${profilesPath}/server/home" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } + "${profilesPath}/optional/nixos/autologin.nix" + "${profilesPath}/common/nixos/settings.nix" + "${profilesPath}/common/nixos/home-manager.nix" + "${profilesPath}/common/nixos/xserver.nix" + "${profilesPath}/common/nixos/users.nix" + "${profilesPath}/common/nixos/impermanence.nix" + "${profilesPath}/common/nixos/lanzaboote.nix" + "${profilesPath}/common/nixos/sops.nix" + "${profilesPath}/server/nixos/ssh.nix" + + inputs.home-manager.nixosModules.home-manager + { + home-manager.users.swarsel.imports = [ + inputs.sops-nix.homeManagerModules.sops + "${profilesPath}/common/home/settings.nix" + "${profilesPath}/common/home/sops.nix" + "${profilesPath}/common/home/ssh.nix" + ] ++ (builtins.attrValues outputs.homeManagerModules); + } ] ++ (builtins.attrValues outputs.nixosModules); @@ -2451,43 +2672,47 @@4 }; }; + environment.systemPackages = with pkgs; [ + curl + git + gnupg + rsync + ssh-to-age + sops + vim + just + sbctl + ]; + + system.stateVersion = lib.mkForce "23.05"; + boot = { - loader.systemd-boot.enable = true; - loader.efi.canTouchEfiVariables = true; + supportedFilesystems = [ "btrfs" ]; + kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; }; + networking = { - hostName = "winters"; - hostId = "b7778a4a"; - firewall.enable = true; - enableIPv6 = false; - firewall.allowedTCPPorts = [ 80 443 ]; + hostName = "toto"; + firewall.enable = false; }; + swarselsystems = lib.recursiveUpdate { + wallpaper = self + /wallpaper/lenovowp.png; + isImpermanence = true; + isCrypted = true; + isSecureBoot = false; + isSwap = true; + swapSize = "8G"; + # rootDisk = "/dev/nvme0n1"; + rootDisk = "/dev/vda"; + } sharedOptions; - swarselsystems = { - hasBluetooth = false; - hasFingerprint = false; - isImpermanence = false; - isBtrfs = false; + home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate { + isLaptop = false; + isNixos = true; flakePath = "/home/swarsel/.dotfiles"; - server = { - enable = true; - kavita = true; - navidrome = true; - jellyfin = true; - spotifyd = true; - mpd = false; - matrix = true; - nextcloud = true; - immich = true; - paperless = true; - transmission = true; - syncthing = true; - monitoring = true; - freshrss = true; - }; - }; + } sharedOptions; } @@ -2496,103 +2721,137 @@
4
-A Mac notebook that I have received from work. I use this machine for getting accustomed to the Apple ecosystem as well as as a sandbox for nix-darwin configurations. -
- +{ self, inputs, outputs, ... }: +# NOTE: ... is needed because dikso passes diskoFile +{ lib +, pkgs +, config +, rootDisk +, ... +}: let - profilesPath = "${self}/profiles"; + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; in { - imports = [ - "${profilesPath}/darwin/common/nixos" - - inputs.home-manager.darwinModules.home-manager - { - home-manager.users."leon.schwarzaeugl".imports = [ - "${profilesPath}/darwin/common/home" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - - - # Auto upgrade nix package and the daemon service. - services.nix-daemon.enable = true; - services.karabiner-elements.enable = true; - - home-manager.users."leon.schwarzaeugl".home = { - username = lib.mkForce "leon.schwarzaeugl"; - swarselsystems = { - isDarwin = true; - isLaptop = true; - isNixos = false; - isBtrfs = false; + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; }; }; + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; -} --
-My phone. I use only a minimal config for remote debugging here. -
- --{ pkgs, ... }: { - environment = { - packages = with pkgs; [ - vim - git - openssh - # toybox - dig - man - gnupg - curl - deadnix - statix - nixpgks-fmt - nvd - ]; - - etcBackupExtension = ".bak"; - extraOutputsToInstall = [ - "doc" - "info" - "devdoc" - ]; - motd = null; - }; - - android-integration = { - termux-open.enable = true; - xdg-open.enable = true; - termux-open-url.enable = true; - termux-reload-settings.enable = true; - termux-setup-storage.enable = true; - }; - - # Backup etc files instead of failing to activate generation if a file already exists in /etc - - # Read the changelog before changing this value - system.stateVersion = "23.05"; - - # Set up nix for flakes - nix.extraOptions = '' - experimental-features = nix-command flakes - ''; + environment.systemPackages = [ + pkgs.yubikey-manager + ]; } @@ -2601,304 +2860,62 @@4
-My server setup was originally 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 was for a long time rewriting all machines on there to use NixOS instead; this process is now finished.
+This is a live environment ISO that I use to bootstrap new systems. It only loads a minimal configuration and no graphical interface. After booting this image on a host, find out its IP and bootstrap the system using the bootstrap
utility.
-I have removed most of the machines from this section. What remains are some hosts that I have deployed on OCI (mostly sync for medium-important data) and one other machine that I left for now as a reference.
+For added convenience, the live environment displays a helpful text on login, we define it here (will be put into /etc/issue
):
[32m~SwarselSystems~[0m +IP of primary interface: [31m\4[0m +The Password for all users & root is '[31msetup[0m'. +Install the system remotely by running '[33mbootstrap -n <CONFIGURATION_NAME> -d <IP_FROM_ABOVE> [0m' on a machine with deployed secrets. +Alternatively, run '[33mswarsel-install -n <CONFIGURATION_NAME>[0m' for a local install. For your convenience, an example call is in the bash history (press up on the keyboard to access). + +
-This machine mainly acts as an external sync helper. It manages the following things: -
--Syncthing backup of replaceable data +Also, an initial bash history is provided to allow for a very quick local deployment:
--All of these are processes that use little cpu but can take a lot of storage. For this I use a free Ampere instance from OCI with 50G of space. In case my account gets terminated, all of this data is easily replaceable or backed up regularly anyways. -
swarsel-install -n chaostheatre +
{ self, inputs, outputs, lib, ... }: +{ self, pkgs, inputs, outputs, config, lib, modulesPath, ... }: let - profilesPath = "${self}/profiles"; + pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh"; in { + imports = [ + inputs.lanzaboote.nixosModules.lanzaboote + inputs.disko.nixosModules.disko + inputs.impermanence.nixosModules.impermanence inputs.sops-nix.nixosModules.sops - "${profilesPath}/server/nixos" - ./hardware-configuration.nix + "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" + "${modulesPath}/installer/cd-dvd/channel.nix" + + "${self}/profiles/iso/minimal.nix" inputs.home-manager.nixosModules.home-manager { home-manager.users.swarsel.imports = [ - "${profilesPath}/server/home" + "${self}/profiles/common/home/settings.nix" ] ++ (builtins.attrValues outputs.homeManagerModules); } - - ] ++ (builtins.attrValues outputs.nixosModules); - - sops = { - defaultSopsFile = lib.mkForce "/root/.dotfiles/secrets/sync/secrets.yaml"; - }; - - - services.nginx = { - virtualHosts = { - "sync.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:8384/"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - - boot = { - tmp.cleanOnBoot = true; - loader.grub.device = "nodev"; - }; - zramSwap.enable = false; - - networking = { - firewall.allowedTCPPorts = [ 8384 22000 ]; - firewall.allowedUDPPorts = [ 21027 22000 ]; - hostName = "sync"; - enableIPv6 = false; - domain = "subnet03112148.vcn03112148.oraclevcn.com"; - 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 - iptables -I INPUT -m state --state NEW -p tcp --dport 9812 -j ACCEPT - ''; - }; - - # system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change - - # do not manage OCI syncthing through nix config - services.syncthing = { - enable = true; - guiAddress = "0.0.0.0:8384"; - openDefaultPorts = true; - }; - - - swarselsystems = { - hasBluetooth = false; - hasFingerprint = false; - isImpermanence = false; - isBtrfs = false; - flakePath = "/root/.dotfiles"; - server = { - enable = true; - forgejo = true; - ankisync = true; - }; - }; - -} - --
-This is a slim setup for developing base configuration. -
- -{ self, inputs, outputs, config, pkgs, lib, ... }: -let - profilesPath = "${self}/profiles"; - sharedOptions = { - isBtrfs = true; - }; -in -{ - - imports = [ - inputs.disko.nixosModules.disko - "${self}/hosts/nixos/toto/disk-config.nix" - ./hardware-configuration.nix - - inputs.sops-nix.nixosModules.sops - inputs.impermanence.nixosModules.impermanence - inputs.lanzaboote.nixosModules.lanzaboote - - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/common/nixos/settings.nix" - "${profilesPath}/common/nixos/home-manager.nix" - "${profilesPath}/common/nixos/xserver.nix" - "${profilesPath}/common/nixos/users.nix" - "${profilesPath}/common/nixos/impermanence.nix" - "${profilesPath}/common/nixos/lanzaboote.nix" - "${profilesPath}/common/nixos/sops.nix" - "${profilesPath}/server/nixos/ssh.nix" - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - inputs.sops-nix.homeManagerModules.sops - "${profilesPath}/common/home/settings.nix" - "${profilesPath}/common/home/sops.nix" - "${profilesPath}/common/home/ssh.nix" - - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - environment.systemPackages = with pkgs; [ - curl - git - gnupg - rsync - ssh-to-age - sops - vim - just - sbctl - ]; - - system.stateVersion = lib.mkForce "23.05"; - - boot = { - supportedFilesystems = [ "btrfs" ]; - kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; - }; - - - networking = { - hostName = "toto"; - firewall.enable = false; - }; - - swarselsystems = lib.recursiveUpdate { - wallpaper = self + /wallpaper/lenovowp.png; - isImpermanence = true; - isCrypted = true; - isSecureBoot = false; - isSwap = true; - swapSize = "8G"; - # rootDisk = "/dev/nvme0n1"; - rootDisk = "/dev/vda"; - } sharedOptions; - - home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate { - isLaptop = false; - isNixos = true; - flakePath = "/home/swarsel/.dotfiles"; - } sharedOptions; - -} - - --
-This is a live environment ISO that I use to bootstrap new systems. It only loads a minimal configuration and no graphical interface. After booting this image on a host, find out its IP and bootstrap the system using the bootstrap
utility.
-
-For added convenience, the live environment displays a helpful text on login, we define it here (will be put into /etc/issue
):
-
[32m~SwarselSystems~[0m -IP of primary interface: [31m\4[0m -The Password for all users & root is '[31msetup[0m'. -Install the system remotely by running '[33mbootstrap -n <CONFIGURATION_NAME> -d <IP_FROM_ABOVE> [0m' on a machine with deployed secrets. -Alternatively, run '[33mswarsel-install -n <CONFIGURATION_NAME>[0m' for a local install. For your convenience, an example call is in the bash history (press up on the keyboard to access). - --
-Also, an initial bash history is provided to allow for a very quick local deployment: -
- -swarsel-install -n chaostheatre --
{ self, pkgs, inputs, outputs, config, lib, modulesPath, ... }: -let - pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh"; -in -{ - - imports = [ - - inputs.lanzaboote.nixosModules.lanzaboote - inputs.disko.nixosModules.disko - inputs.impermanence.nixosModules.impermanence - inputs.sops-nix.nixosModules.sops - "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" - "${modulesPath}/installer/cd-dvd/channel.nix" - - "${self}/profiles/iso/minimal.nix" - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - "${self}/profiles/common/home/settings.nix" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ]; + ]; home-manager.users.swarsel.home = { file = { @@ -2958,7 +2975,7 @@4 }; programs.bash.shellAliases = { - "swarsel-install" = "nix run github:Swarsel/.dotfiles#install --"; + "swarsel-install" = "nix run github:Swarsel/.dotfiles#swarsel-install --"; }; system.activationScripts.cache = { @@ -2996,7 +3013,7 @@
4
This is the "reference implementation" of a setup that runs without NixOS, only relying on home-manager. I try to test this every now and then and keep it supported. However, manual steps are needed to get the system to work fully, depending on what distribution you are running on. @@ -3006,7 +3023,7 @@
{ self, inputs, outputs, config, ... }: { - imports = builtins.attrValues outputs.homeManagerModules; + imports = outputs.homeModules ++ outputs.mixedModules ++ (builtins.attrValues outputs.homeManagerModules); nixpkgs = { overlays = [ outputs.overlays.default ]; @@ -3032,29 +3049,6 @@4 isLaptop = true; isNixos = false; wallpaper = self + /wallpaper/surfacewp.png; - temperatureHwmon = { - isAbsolutePath = true; - path = "/sys/devices/platform/thinkpad_hwmon/hwmon/"; - input-filename = "temp1_input"; - }; - monitors = { - main = { - name = "California Institute of Technology 0x1407 Unknown"; - mode = "1920x1080"; # TEMPLATE - scale = "1"; - position = "2560,0"; - workspace = "2:二"; - output = "eDP-1"; - }; - }; - inputs = { - "1:1:AT_Translated_Set_2_keyboard" = { - xkb_layout = "us"; - xkb_options = "grp:win_space_toggle"; - xkb_variant = "altgr-intl"; - }; - }; - keybindings = { }; }; } @@ -3064,9 +3058,9 @@
4
This is just a demo host. It applies all the configuration found in the common parts of the flake, but disables all secrets-related features (as they would not work without the proper SSH keys).
@@ -3142,7 +3136,7 @@In this section I define packages that I manually want to nixpkgs. This can be useful for packages that are currently awaiting a PR or public packages that I do not want to maintain. @@ -3160,9 +3154,17 @@
nixpkgs-stable
This is simply a mirror of the most recent stable branch of nixpkgs. Useful for packages that are broken on nixpkgs, but do not need to be on bleeding edge anyways.+Also, this is where I define all of my own modules. These are mostly used for setting some host-specifics directly than opposed to through multiple options. +
+ +
+Lastly, I add some of my own library functions to be used alongside the functions provided by nixpkgs
and home-manager
.
+
This is the central station for self-defined packages. These are all referenced in default.nix
. Wherever possible, I am keeping the shell version of these scripts in this file as well and then read it using builtin.readFile
in the NixOS configurations. This lets me keep full control in this one file but also keep the separate files uncluttered.
@@ -3173,7 +3175,7 @@
{ lib, ... }: +{ lib, pkgs, ... }: let packageNames = [ "pass-fuzzel" @@ -3201,14 +3203,14 @@4 "eontimer" ]; in - lib.swarselsystems.mkPackages packageNames + lib.swarselsystems.mkPackages packageNames pkgs
This app allows me, in conjunction with my Yubikey, to quickly enter passwords when the need arises. Normal and TOTP passwords are supported, and they can either be printed directly or copied to the clipboard. @@ -3270,12 +3272,11 @@
{ writeShellApplication, libnotify, pass, fuzzel, wtype }: - +{ self, name, writeShellApplication, libnotify, pass, fuzzel, wtype }: writeShellApplication { - name = "pass-fuzzel"; + inherit name; runtimeInputs = [ libnotify (pass.withExtensions (exts: [ exts.pass-otp ])) fuzzel wtype ]; - text = builtins.readFile ../../scripts/pass-fuzzel.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }@@ -3283,7 +3284,7 @@4
The version of cura
used to be quite outdated in nixpkgs. I am fetching a newer AppImage here and use that instead.
@@ -3292,7 +3293,7 @@
# taken from https://github.com/NixOS/nixpkgs/issues/186570#issuecomment-1627797219 -{ appimageTools, fetchurl, writeScriptBin, pkgs }: +{ appimageTools, fetchurl, writeScriptBin, pkgs, ... }: let @@ -3326,7 +3327,7 @@4
This script allows for quick git home-manager specialisation switching. @@ -3334,10 +3335,10 @@
{ writeShellApplication, fzf, findutils, home-manager }: +{ name, writeShellApplication, fzf, findutils, home-manager, ... }: writeShellApplication { - name = "hm-specialisation"; + inherit name; runtimeInputs = [ fzf findutils home-manager ]; text = '' genpath=$(home-manager generations | head -1 | awk '{print $7}') @@ -3352,7 +3353,7 @@4
This script allows for quick git worktree switching. @@ -3360,10 +3361,10 @@
{ writeShellApplication, fzf }: +{ name, writeShellApplication, fzf, ... }: writeShellApplication { - name = "cdw"; + inherit name; runtimeInputs = [ fzf ]; text = '' cd "$(git worktree list | fzf | awk '{print $1}')" @@ -3376,17 +3377,17 @@4
This script allows for quick git branch switching.
{ writeShellApplication, fzf }: +{ name, writeShellApplication, fzf, ... }: writeShellApplication { - name = "cdb"; + inherit name; runtimeInputs = [ fzf ]; text = '' git checkout "$(git branch --list | grep -v "^\*" | fzf | awk '{print $1}')" @@ -3398,7 +3399,7 @@4
This script lets me quickly backup files by appending .bak
to the filename.
@@ -3406,12 +3407,12 @@
{ writeShellApplication }: +{ name, writeShellApplication, ... }: writeShellApplication { - name = "bak"; + inherit name; text = '' - cp "$1"{,.bak} + cp -r "$1"{,.bak} ''; } @@ -3421,7 +3422,7 @@4
This app starts a configuratble timer and uses TTS to say something once the timer runs out. @@ -3429,10 +3430,10 @@
{ writeShellApplication, speechd }: +{ name, writeShellApplication, speechd, ... }: writeShellApplication { - name = "timer"; + inherit name; runtimeInputs = [ speechd ]; text = '' sleep "$1"; while true; do spd-say "$2"; sleep 0.5; done; @@ -3444,7 +3445,7 @@4
This is a shorthand for calling emacsclient mostly. Also, it hides the kittyterm scratchpad window that I sometimes use for calling a command quickly, in case it is on the screen. After emacs closes, the kittyterm window is then shown again if it was visible earlier. @@ -3478,12 +3479,11 @@
{ writeShellApplication, emacs30-pgtk, sway, jq }: - +{ self, name, writeShellApplication, emacs30-pgtk, sway, jq }: writeShellApplication { - name = "e"; + inherit name; runtimeInputs = [ emacs30-pgtk sway jq ]; - text = builtins.readFile ../../scripts/e.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }@@ -3491,7 +3491,7 @@4
The normal command-not-found.sh
uses the outdated nix-shell
commands as suggestions. This version supplies me with the more modern nixpkgs#<name>
version.
@@ -3537,7 +3537,7 @@
This app checks for different apps that I keep around in the scratchpad for quick viewing and hiding (messengers and music players mostly) and then behaves like the kittyterm hider that I described in e. @@ -3610,12 +3610,11 @@
{ writeShellApplication, kitty, element-desktop-wayland, vesktop, spotify-player, jq }: - +{ self, name, writeShellApplication, kitty, element-desktop-wayland, vesktop, spotify-player, jq }: writeShellApplication { - name = "swarselcheck"; + inherit name; runtimeInputs = [ kitty element-desktop-wayland vesktop spotify-player jq ]; - text = builtins.readFile ../../scripts/swarselcheck.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }@@ -3623,7 +3622,7 @@4
This scripts checks if there are uncommited changes in either my dotfile repo, my university repo, or my passfile repo. In that case a warning will be shown in waybar. @@ -3658,12 +3657,11 @@
{ writeShellApplication, git }: - +{ self, name, writeShellApplication, git }: writeShellApplication { - name = "waybarupdate"; + inherit name; runtimeInputs = [ git ]; - text = builtins.readFile ../../scripts/waybarupdate.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }@@ -3671,7 +3669,7 @@4
This app quickly toggles between 5% and 0% transparency. @@ -3687,19 +3685,18 @@
{ writeShellApplication, sway }: - +{ self, name, writeShellApplication, sway }: writeShellApplication { - name = "opacitytoggle"; + inherit name; runtimeInputs = [ sway ]; - text = builtins.readFile ../../scripts/opacitytoggle.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }
This utility is used to compare the current state of the root directory with the blanket state that is stored in /root-blank (the snapshot that is restored on each reboot of an impermanence machine). Using this, I can find files that I will lose once I reboot - if there are important files in that list, I can then easily add them to the persist options. @@ -3730,18 +3727,17 @@
{ writeShellApplication }: - +{ self, name, writeShellApplication }: writeShellApplication { - name = "fs-diff"; - text = builtins.readFile ../../scripts/fs-diff.sh; + inherit name; + text = builtins.readFile "${self}/scripts/${name}.sh"; }
This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. @@ -3766,19 +3762,18 @@
{ writeShellApplication, nvd }: - +{ self, name, writeShellApplication, nvd }: writeShellApplication { - name = "update-checker"; + inherit name; runtimeInputs = [ nvd ]; - text = builtins.readFile ../../scripts/update-checker.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }
This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. @@ -3786,10 +3781,10 @@
{ writeShellApplication, jq }: +{ name, writeShellApplication, jq, ... }: writeShellApplication { - name = "github-notifications"; + inherit name; runtimeInputs = [ jq ]; text = '' count=$(curl -u Swarsel:"$(cat /run/user/1000/secrets/github_notif)" https://api.github.com/notifications | jq '. | length') @@ -3804,7 +3799,7 @@4
SHARESCREEN="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$(hostname)".config.home-manager.users."$(whoami)".swarselsystems.sharescreen)" @@ -3829,19 +3824,18 @@4
-{ writeShellApplication, sway }: - +{ self, name, writeShellApplication, sway }: writeShellApplication { - name = "screenshare"; + inherit name; runtimeInputs = [ sway ]; - text = builtins.readFile ../../scripts/screenshare.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }
This program sets up a new NixOS host remotely. It also takes care of secret management on the new host. @@ -4192,20 +4186,19 @@
{ writeShellApplication, openssh }: - +{ self, name, writeShellApplication, openssh }: writeShellApplication { - name = "swarsel-bootstrap"; + inherit name; runtimeInputs = [ openssh ]; - text = builtins.readFile ../../scripts/swarsel-bootstrap.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }
This program builds a configuration locally.
@@ -4304,20 +4297,19 @@{ writeShellApplication, git }: - +{ self, name, writeShellApplication, git }: writeShellApplication { - name = "swarsel-rebuild"; + inherit name; runtimeInputs = [ git ]; - text = builtins.readFile ../../scripts/swarsel-rebuild.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }
This program sets up a new NixOS host locally.
@@ -4492,20 +4484,19 @@{ writeShellApplication, git }: - +{ self, name, writeShellApplication, git }: writeShellApplication { - name = "swarsel-install"; + inherit name; runtimeInputs = [ git ]; - text = builtins.readFile ../../scripts/swarsel-install.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }
This program sets up a new NixOS host locally.
@@ -4592,29 +4583,28 @@{ writeShellApplication, git }: - +{ self, name, writeShellApplication, git }: writeShellApplication { - name = "swarsel-postinstall"; + inherit name; runtimeInputs = [ git ]; - text = builtins.readFile ../../scripts/swarsel-postinstall.sh; + text = builtins.readFile "${self}/scripts/${name}.sh"; }
This script allows for quick git branch switching.
{ writeShellApplication }: +{ name, writeShellApplication, ... }: writeShellApplication { - name = "t2ts"; + inherit name; runtimeInputs = [ ]; text = '' date -d"$1" +%s @@ -4626,17 +4616,17 @@4
This script allows for quick git branch switching.
{ writeShellApplication }: +{ name, writeShellApplication, ... }: writeShellApplication { - name = "ts2t"; + inherit name; runtimeInputs = [ ]; text = '' date -d @"$1" 2>/dev/null || date -r "$1" @@ -4647,18 +4637,18 @@4
This script allows for quick git branch switching.
{ writeShellApplication }: +{ name, writeShellApplication, ... }: writeShellApplication { - name = "vershell"; + inherit name; runtimeInputs = [ ]; text = '' nix shell github:nixos/nixpkgs/"$1"#"$2"; @@ -4669,15 +4659,15 @@4.2.1.23. vershell
This script allows for quick git branch switching.
{ pkgs, python3Packages }: +{ pkgs, python3Packages, ... }: python3Packages.buildPythonApplication rec { pname = "eontimer"; @@ -4733,7 +4723,7 @@4.2.1.24. eontimer
This file now holds all of the "nixpkgs-changes" that I am using across the configurations. Most notable here are the modifications
, where I am editing derivations according to my needs.
@@ -4744,24 +4734,25 @@
{ inputs, lib, ... }: +{ self, inputs, lib, ... }: let - additions = final: _prev: import ../pkgs { pkgs = final; inherit lib }; - modifications = _: _prev: { - vesktop = _prev.vesktop.override { + additions = final: _: import "${self}/pkgs" { pkgs = final; inherit lib; }; + + modifications = _: prev: { + vesktop = prev.vesktop.override { withSystemVencord = true; }; - firefox = _prev.firefox.override { + firefox = prev.firefox.override { nativeMessagingHosts = [ - _prev.tridactyl-native - _prev.browserpass - _prev.plasma5Packages.plasma-browser-integration + prev.tridactyl-native + prev.browserpass + prev.plasma5Packages.plasma-browser-integration ]; }; - retroarch = _prev.retroarch.withCores (cores: with cores; [ + retroarch = prev.retroarch.withCores (cores: with cores; [ snes9x # snes nestopia # nes dosbox # dos @@ -4772,10 +4763,6 @@4 dolphin # gc/wii ]); - # prismlauncher = _prev.prismlauncher.override { - # glfw = _prev.glfw-wayland-minecraft; - # }; - # #river = prev.river.overrideAttrs (oldAttrs: rec { # pname = "river"; # version = "git"; @@ -4789,15 +4776,15 @@
4 # }); }; - nixpkgs-stable = final: _prev: { + nixpkgs-stable = final: _: { stable = import inputs.nixpkgs-stable { inherit (final) system; config.allowUnfree = true; }; }; - zjstatus = _: _prev: { - zjstatus = inputs.zjstatus.packages.${_prev.system}.default; + zjstatus = _: prev: { + zjstatus = inputs.zjstatus.packages.${prev.system}.default; }; in @@ -4821,7 +4808,7 @@
4
In this section I define custom modules under the swarsel
attribute. These are mostly used to define settings specific to a host. I keep these settings confined to either home-manager or nixos to maintain compatibility with non-NixOS machines.
@@ -4832,14 +4819,15 @@
Modules that need to be loaded on the NixOS level. Note that these will not be available on systems that are not running NixOS.
let +{ lib, ... }: +let moduleNames = [ "wallpaper" "hardware" @@ -4847,20 +4835,14 @@4 "server" "input" ]; - - mkImports = names: builtins.listToAttrs (map (name: { - inherit name; - value = import ./${name}.nix; - }) names); - in - mkImports moduleNames +lib.swarselsystems.mkModules moduleNames "nixos"
This lets me set the wallpaper that I want to use. Duplicated with home-manager options because mixing system and user level configuration is not a good idea. @@ -4881,7 +4863,7 @@
This lets me set some basic flags about the hardware of the configured systems. @@ -4904,7 +4886,7 @@
I usually use mutableUsers = false
in my NixOS configuration. However, on a new system where sops-keys have not been deployed, this would immediately lock me out of the system. Hence this flag can be used until sops-keys are created.
@@ -4949,9 +4931,9 @@
{ lib, ... }: { @@ -4980,7 +4962,7 @@4.2.3.1.4. Server
This section is for everything input-related on the NixOS side. At the moment, this is only used to define shell aliases for servers. @@ -4988,12 +4970,9 @@
{ lib, ... }: -let - inherit (lib) mkOption types; -in { - options.swarselsystems.shellAliases = mkOption { - type = types.attrsOf types.str; + options.swarselsystems.shellAliases = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = { }; }; } @@ -5003,14 +4982,15 @@4
This holds modules that are to be used on most hosts. These are also the most important options to configure, as these allow me easy access to monitor, keyboard, and other setups.
let +{ lib, ... }: +let moduleNames = [ "laptop" "hardware" @@ -5024,19 +5004,13 @@4 "filesystem" "firefox" ]; - - mkImports = names: builtins.listToAttrs (map (name: { - inherit name; - value = import ./${name}.nix; - }) names); - in - mkImports moduleNames +lib.swarselsystems.mkModules moduleNames "home"
Laptops are not always plugged in, so they should show a battery icon in Waybar. Also, most laptops have a touchpad which usually needs to be configured. @@ -5077,7 +5051,7 @@
This section is mostly used to deliver the correct information to Waybar. AMD systems have changing hwmon paths that can be specifically set here. Also the cpu count can be set here for Waybars cpu module, but 8 is usually a good setting to show @@ -5085,7 +5059,6 @@
{ lib, ... }: - { options.swarselsystems.cpuCount = lib.mkOption { type = lib.types.int; @@ -5106,7 +5079,7 @@4
These are explicit waybar options. Laptops do not need the battery module. However, this leads to a slight problem with theming: my waybar modules alternate their background-color between black and grey. The battery module is usually on grey background. If I were to simply delete that, I would now have two modules on black background. To avoid this, I define a pseudo-module custom/pseudobat
that simply shows a static image and calls wlogout
on right click. This wastes a little bit of screen space, but that is a price I am willing to pay for consistency.
@@ -5118,7 +5091,6 @@
{ lib, config, ... }: - let generateIcons = n: lib.concatStringsSep " " (builtins.map (x: "{icon" + toString x + "}") (lib.range 0 (n - 1))); in @@ -5156,7 +5128,7 @@4
This allows me to define my monitors in the machine's default.nix
.
@@ -5164,24 +5136,21 @@
{ lib, ... }: -let - inherit (lib) mkOption types; -in { - options.swarselsystems.monitors = mkOption { - type = types.attrsOf (types.attrsOf types.str); + options.swarselsystems.monitors = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); default = { }; }; - options.swarselsystems.sharescreen = mkOption { - type = types.str; + options.swarselsystems.sharescreen = lib.mkOption { + type = lib.types.str; default = ""; }; - options.swarselsystems.lowResolution = mkOption { - type = types.str; + options.swarselsystems.lowResolution = lib.mkOption { + type = lib.types.str; default = ""; }; - options.swarselsystems.highResolution = mkOption { - type = types.str; + options.swarselsystems.highResolution = lib.mkOption { + type = lib.types.str; default = ""; }; } @@ -5190,7 +5159,7 @@4
This allows me to configure input options. Here, I am globally defining my split keyboards. Then, I am joining some attribute sets so that they can be easier used in the rest of the configurations. @@ -5198,16 +5167,13 @@
{ lib, config, ... }: -let - inherit (lib) mkOption types; -in { - options.swarselsystems.inputs = mkOption { - type = types.attrsOf (types.attrsOf types.str); + options.swarselsystems.inputs = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); default = { }; }; - options.swarselsystems.kyria = mkOption { - type = types.attrsOf (types.attrsOf types.str); + options.swarselsystems.kyria = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); default = { "36125:53060:splitkb.com_splitkb.com_Kyria_rev3" = { xkb_layout = "us"; @@ -5219,21 +5185,21 @@4 }; }; }; - options.swarselsystems.touchpad = mkOption { - type = types.attrsOf (types.attrsOf types.str); + options.swarselsystems.touchpad = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); default = { }; }; - options.swarselsystems.standardinputs = mkOption { - type = types.attrsOf (types.attrsOf types.str); + options.swarselsystems.standardinputs = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); default = lib.recursiveUpdate (lib.recursiveUpdate config.swarselsystems.touchpad config.swarselsystems.kyria) config.swarselsystems.inputs; internal = true; }; - options.swarselsystems.keybindings = mkOption { - type = types.attrsOf types.str; + options.swarselsystems.keybindings = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = { }; }; - options.swarselsystems.shellAliases = mkOption { - type = types.attrsOf types.str; + options.swarselsystems.shellAliases = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = { }; }; } @@ -5242,7 +5208,7 @@
4
These are some extra options that will be used if the machine also runs NixOS. For example, non-NixOS hosts need nixGL
prepended to most graphic commands, and swayfx
works less nicely on these machines.
@@ -5258,9 +5224,7 @@
Provides settings related to nix-darwin systems. At the moment, I am only making use of a isDarwin
flag.
@@ -5305,7 +5270,7 @@
This defines programs I want to have starting when I start the system @@ -5329,13 +5294,9 @@
{ lib, ... }: -let - inherit (lib) mkOption types; -in { - - options.swarselsystems.startup = mkOption { - type = types.listOf (types.attrsOf types.str); + options.swarselsystems.startup = lib.mkOption { + type = lib.types.listOf (lib.types.attrsOf lib.types.str); default = [ { command = "nextcloud --background"; } { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } @@ -5352,7 +5313,7 @@4
Again, I set the wallpaper here for stylix
.
@@ -5360,7 +5321,6 @@
{ lib, ... }: - { options.swarselsystems.wallpaper = lib.mkOption { type = lib.types.path; @@ -5373,7 +5333,7 @@4
Another duplicated option for the filesystem. @@ -5381,7 +5341,6 @@
{ lib, ... }: - { options.swarselsystems.isBtrfs = lib.mkEnableOption "use btrfs filesystem"; } @@ -5390,7 +5349,7 @@4
At work I am using several services that are using SSO login - however, as I am using four different accounts at work, this becomes a chore here. Hence, I have defined multiple profiles in Work that are all practically using the same configuration. To save screen space, I template that profile here. @@ -5398,7 +5357,7 @@
{ lib, pkgs, ... }: +{ self, lib, pkgs, ... }: let lock-false = { Value = false; @@ -5414,7 +5373,7 @@4 type = lib.types.attrs; default = { isDefault = false; - userChrome = builtins.readFile ../../programs/firefox/chrome/userChrome.css; + userChrome = builtins.readFile "${self}/programs/firefox/chrome/userChrome.css"; extensions = with pkgs.nur.repos.rycee.firefox-addons; [ tridactyl tampermonkey @@ -5557,23 +5516,130 @@
4
+This section defines all functions of my own that I add to lib
. These are used in all places over the config, with many of them being used in flake.nix
.
+
+A breakdown of each function: +
+ +{ self, lib, systems, inputs, outputs, ... }: +{ + + mkIfElseList = p: yes: no: lib.mkMerge [ + (lib.mkIf p yes) + (lib.mkIf (!p) no) + ]; + + mkIfElse = p: yes: no: if p then yes else no; + + forAllSystems = lib.genAttrs [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + + pkgsFor = lib.genAttrs (import systems) (system: + import inputs.nixpkgs { + inherit system; + config.allowUnfree = true; + } + ); + + forEachSystem = f: lib.genAttrs (import systems) (system: f lib.swarselsystems.pkgsFor.${system}); + + mkFullHost = host: type: { + ${host} = + let + systemFunc = if (type == "nixos") then lib.nixosSystem else inputs.nix-darwin.lib.darwinSystem; + in + systemFunc { + specialArgs = { inherit inputs outputs lib self; }; + modules = [ "${self}/hosts/${type}/${host}" ]; + }; + }; + + mkHalfHost = host: type: pkgs: { + ${host} = + let + systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; + in + systemFunc { + inherit pkgs; + extraSpecialArgs = { inherit inputs outputs; }; + modules = [ "${self}/hosts/${type}/${host}" ]; + }; + }; + + mkFullHostConfigs = hosts: type: lib.foldl (acc: set: acc // set) { } (lib.map (host: lib.swarselsystems.mkFullHost host type) hosts); + + mkHalfHostConfigs = hosts: type: pkgs: lib.foldl (acc: set: acc // set) { } (lib.map (host: lib.swarselsystems.mkFullHost host type pkgs) hosts); + + readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); + + mkApps = system: names: self: builtins.listToAttrs (map + (name: { + inherit name; + value = { + type = "app"; + program = "${self.packages.${system}.${name}}/bin/${name}"; + }; + }) + names); + + mkPackages = names: pkgs: builtins.listToAttrs (map + (name: { + inherit name; + value = pkgs.callPackage "${self}/pkgs/${name}" { inherit self name; }; + }) + names); + + + mkModules = names: type: builtins.listToAttrs (map + (name: { + inherit name; + value = import "${self}/modules/${type}/${name}.nix"; + }) + names); + + eachMonitor = _: monitor: { + inherit (monitor) name; + value = builtins.removeAttrs monitor [ "workspace" "name" "output" ]; + }; + + eachOutput = _: monitor: { + inherit (monitor) name; + value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ]; + }; + +} ++
Here we have NixOS options. All options are split into smaller files that are loaded by the general default.nix
. Common files are used by all user hosts equally, optionals need to be added to the machine's default.nix
on a case-by-case basis.
These are system-level settings specific to NixOS machines. All settings that are required on all machines go here.
This section is for setting things that should be used on hosts that are using the default NixOS configuration. This means that servers should NOT import this, as much of these imported modules are user-configured. @@ -5636,7 +5702,7 @@
Also, we disable the warnings that trigger when rebuilding with a dirty flake. At this point, I am also disabling channels and pinning the flake registry - the latter lets me use the local version of nixpkgs for commands like nix shell
(without it, we will always download the newest version of nixpkgs for these commands).
@@ -5679,7 +5745,7 @@
Mostly used to install some compilers and lsp's that I want to have available when not using a devShell flake. Most other packages should go in Installed packages. @@ -5806,7 +5872,7 @@
We enable the use of home-manager
as a NixoS module. A nice trick here is the extraSpecialArgs = inputs
line, which enables the use of seflf
in most parts of the configuration. This is useful to refer to the root of the flake (which is otherwise quite hard while maintaining flake purity).
@@ -5826,7 +5892,7 @@
Next, we setup the keymap in case we are not in a graphical session. At this point, I always resort to us/altgr-intl, as it is comfortable to use and I do not write too much German anyways. @@ -5847,7 +5913,7 @@
This ensures that all user-configuration happens here in the config file. @@ -5880,7 +5946,7 @@
Next, we will setup some environment variables that need to be set on the system-side. We apply some compatibility options for chromium apps on wayland, enable the wordlist and make metadata reading possible for my file explorer (nautilus). @@ -5908,7 +5974,7 @@
Needed for control over system-wide privileges etc. Also I make sure that the root user has access to SSH_AUTH_SOCK
(without this, root will not be able to read my nix-secrets
repository).
@@ -5936,7 +6002,7 @@
The nix store fills up over time, until /boot/efi
is filled. This snippet cleans it automatically on a weekly basis.
@@ -5957,7 +6023,7 @@
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. @@ -5977,7 +6043,7 @@
There is a persistent bug over Linux kernels that makes the user wait 1m30s on system shutdown due to the reason a stop job is running for session 1 of user ...
. I do not want to wait that long and am confident no important data is lost by doing this.
@@ -5997,7 +6063,7 @@
Enable OpenGL, Sound, Bluetooth and various drivers. @@ -6049,7 +6115,7 @@
Pipewire handles communication on Wayland. This enables several sound tools as well as screen sharing in combinaton with xdg-desktop-portal-wlr
.
@@ -6076,7 +6142,7 @@
Here I only enable networkmanager
and a few default networks. The rest of the network config is done separately in System specific configuration.
@@ -6279,13 +6345,12 @@
Setup timezone and locale. I want to use the US layout, but have the rest adapted to my country and timezone. Also, there is an issue with running Windows/Linux dualboot on the same machine where the hardware clock desyncs between the two OS'es. We fix that bug here as well. @@ -6368,7 +6433,7 @@
I use sops-nix to handle secrets that I want to have available on my machines at all times. Procedure to add a new machine: @@ -6382,18 +6447,15 @@
{ config, lib, ... }: +{ self, config, lib, ... }: let - mkIfElse = p: yes: no: lib.mkMerge [ - (lib.mkIf p yes) - (lib.mkIf (!p) no) - ]; + certsSopsFile = self + /secrets/certs/secrets.yaml; in { sops = lib.mkIf (!config.swarselsystems.isPublic) { - age.sshKeyPaths = mkIfElse config.swarselsystems.isBtrfs [ "/persist/.ssh/sops" "/persist/.ssh/ssh_host_ed25519_key" ] [ "${config.users.users.swarsel.home}/.ssh/sops" "/etc/ssh/ssh_host_ed25519_key" ]; - defaultSopsFile = mkIfElse config.swarselsystems.isBtrfs "/persist/.dotfiles/secrets/general/secrets.yaml" "${config.users.users.swarsel.home}/.dotfiles/secrets/general/secrets.yaml"; + age.sshKeyPaths = lib.swarselsystems.mkIfElseList config.swarselsystems.isBtrfs [ "/persist/.ssh/sops" "/persist/.ssh/ssh_host_ed25519_key" ] [ "${config.users.users.swarsel.home}/.ssh/sops" "/etc/ssh/ssh_host_ed25519_key" ]; + defaultSopsFile = lib.swarselsystems.mkIfElseList config.swarselsystems.isBtrfs "/persist/.dotfiles/secrets/general/secrets.yaml" "${config.users.users.swarsel.home}/.dotfiles/secrets/general/secrets.yaml"; validateSopsFiles = false; @@ -6415,6 +6477,8 @@4 githubforgepass = { }; gitlabforgeuser = { }; gitlabforgepass = { }; + "sweden-aes-128-cbc-udp-dns-crl-verify.pem" = { sopsFile = certsSopsFile; owner = "swarsel"; }; + "sweden-aes-128-cbc-udp-dns-ca.pem" = { sopsFile = certsSopsFile; owner = "swarsel"; }; }; templates = { "network-manager.env".content = '' @@ -6447,7 +6511,7 @@
4
By default, stylix wants to style GRUB as well. However, I think that looks horrible. @@ -6521,7 +6585,7 @@
Some programs profit from being installed through dedicated NixOS settings on system-level; these go here. Notably the zsh setup goes here and cannot be deleted under any circumstances. @@ -6540,7 +6604,7 @@
Do not touch this. @@ -6559,7 +6623,7 @@
_: @@ -6618,14 +6682,14 @@4
Setting up some hardware services as well as keyboard related settings. Here we make sure that we can use the CAPS key as a ESC/CTRL double key, which is a lifesaver.
Enables the blueman service including the nice system tray icon. @@ -6642,14 +6706,14 @@
In this section we enable compatibility with several network devices I have at home, mainly printers and scanners.
This allows me to use my big scanner/printer's scanning function over the network. @@ -6669,7 +6733,7 @@
This allows me to use my big scanner/printer's printing function over the network. Most of the settings are driver related. @@ -6698,7 +6762,7 @@
Avahi is the service used for the network discovery. @@ -6718,7 +6782,7 @@
This is being set to allow myself to use all functions of nautilus in NixOS @@ -6734,7 +6798,7 @@
This is a super-convenient package that lets my remap my CAPS
key to ESC
if pressed shortly, and CTRL
if being held.
@@ -6775,7 +6839,7 @@
This enables power profile management. The available modes are: @@ -6802,7 +6866,7 @@
It makes sense to house these settings in their own section, since they are all needed really. Note that the starting of the gpg-agent is done in the sway settings, to also perform this step of the setup for non NixOS-machines at the same time. @@ -6842,7 +6906,7 @@
This section houses the greetd related settings. I do not really want to use a display manager, but it is useful to have setup in some ways - in my case for starting sway on system startup. Notably the default user login setting that is commented out here goes into the system specific settings, make sure to update it there @@ -6875,7 +6939,7 @@
This provides libraries for binaries that are not patched for use on NixOS. This really makes the biggest gripe with NixOS go away, that being having to run a binary that is only found in a single spot. It is most of the times possible to patch such a file, but this makes such a situation take much less time to resolve. @@ -7005,7 +7069,7 @@
This is where the impermanence magic happens. When this is enabled, the root directory is rolled back to a blanket state on each reboot. @@ -7018,10 +7082,8 @@
{ config, lib, ... }: let - mkIfElse = p: yes: no: if p then yes else no; - mapperTarget = mkIfElse config.swarselsystems.isCrypted "/dev/mapper/cryptroot" "/dev/disk/by-label/nixos"; + mapperTarget = lib.swarselsystems.mkIfElse config.swarselsystems.isCrypted "/dev/mapper/cryptroot" "/dev/disk/by-label/nixos"; in - { security.sudo.extraConfig = lib.mkIf config.swarselsystems.isImpermanence '' @@ -7113,7 +7175,7 @@4
This snipped is added to the activation script that is run after every rebuild and shows what packages have been added and removed. This is actually not the optimal place to add that snipped, but the correct spot is in some perl file that I have not had the leisure to take a look at yet. @@ -7135,7 +7197,7 @@
Used for storing sessions in e.g. Nextcloud. Using this on a system level keeps the login information when logging out of the session as well. @@ -7155,7 +7217,7 @@
This is used to better integrate Sway into the system on NixOS hosts. On the home-manager side, the package
attribute will be null
for such an host, using the systems derivation instead.
@@ -7190,7 +7252,7 @@
This allows me to use screen sharing on Wayland. The implementation is a bit crude and only the whole screen can be shared. However, most of the time that is all I need to do anyways. @@ -7221,7 +7283,7 @@
A friend of mine used this service and I used to make fun of him. But I have to admit this is actually a nice program. It forces you to look away from the screen from time to time, reducing eye strain. @@ -7237,7 +7299,7 @@
I am using distrobox to quickly circumvent isses that I cannot immediately solve on NixOS. It is always the goal to quickly get things working on NixOS, but this prevents me from getting completely stuck. @@ -7261,7 +7323,7 @@
This turns off the display when the lid is closed. @@ -7299,7 +7361,7 @@
Since I hide the waybar completely during normal operation, I run the risk of not noticing when my battery is about to run out. This module sends a notification when the battery level falls below 10%. Written by cafkafk. @@ -7336,9 +7398,9 @@
This dynamically uses systemd boot or Lanzaboote depending on `config.swarselsystems.initialSetup` and `config.swarselsystems.isSecureBoot`.
@@ -7363,11 +7425,11 @@
First, we enable the use of home-manager
as a NixoS module.
@@ -7428,7 +7490,7 @@
Here we just define some aliases for rebuilding the system, and we allow some insecure packages that are needed by some server derivations. It would be more elegant to define these in the respective module, but nixpkgs needs to be defined before we can evaluate modules within it, so this must be a top-level configuration. @@ -7463,7 +7525,7 @@
{ pkgs, ... }: @@ -7482,7 +7544,7 @@4
{ config, lib, ... }: @@ -7499,7 +7561,7 @@4
{ pkgs, ... }: @@ -7556,7 +7618,7 @@4
{ pkgs, config, ... }: @@ -7599,7 +7661,7 @@4
{ self, ... }: @@ -7625,7 +7687,7 @@4
{ pkgs, lib, config, ... }: @@ -7675,7 +7737,7 @@4
{ pkgs, lib, config, ... }: @@ -7727,7 +7789,7 @@4
{ pkgs, lib, inputs, config, ... }: @@ -7831,7 +7893,7 @@4
{ lib, config, ... }: @@ -7873,7 +7935,7 @@4
{ pkgs, lib, config, ... }: @@ -7932,7 +7994,7 @@4
{ lib, config, ... }: @@ -7960,7 +8022,7 @@4
{ config, lib, pkgs, sops, ... }: @@ -8286,7 +8348,7 @@4
{ pkgs, lib, config, ... }: @@ -8337,7 +8399,7 @@4
{ lib, config, ... }: @@ -8394,7 +8456,7 @@4
{ lib, config, ... }: @@ -8452,7 +8514,7 @@4
{ pkgs, lib, config, ... }: @@ -8593,7 +8655,7 @@4
{ lib, config, ... }: @@ -8711,7 +8773,7 @@4
Once this is finished, it will house a restic client that manages automatic backups of my image library. Before I get to this however, I first need to organice my pictures in the first place. @@ -8731,7 +8793,7 @@
This section exposes several metrics that I use to check the health of my server. I need to expand on the exporters section at some point, but for now I have everything I need. @@ -8903,7 +8965,7 @@
This is a WIP Jenkins instance. It is used to automatically build a new system when pushes to the main repository are detected. I have turned this service off for now however, as I actually prefer to start my builds manually. @@ -8950,7 +9012,7 @@
This was an approach of hosting an RSS server from within emacs. That would have been useful as it would have allowed me to allow my feeds from any device. However, it proved impossible to do bidirectional syncing, so I abandoned this configuration in favor of FreshRSS. @@ -8977,7 +9039,7 @@
FreshRSS is a more 'classical' RSS aggregator that I can just host as a distinct service. This also has its upsides because I jave more control over the state this way. @@ -9029,7 +9091,7 @@
{ lib, config, ... }: @@ -9083,7 +9145,7 @@4
{ lib, config, ... }: @@ -9133,11 +9195,11 @@4
This section sets up all the imports that are used in the home-manager section. @@ -9170,7 +9232,7 @@
These sets of configuration do not need to be deployed on every host, for a multitude of reasons. @@ -9185,7 +9247,7 @@
This opens a few gaming ports and installs the steam configuration suite for gaming. There are more options in Gaming (home-manager side). @@ -9234,7 +9296,7 @@
This sets the VirtualBox configuration. Guest should not be enabled if not direly needed, it will make rebuilds unbearably slow. I only use this privately to run an old editor that does not run well under wine, so I put it into it's own specialisation. @@ -9267,7 +9329,7 @@
This sets the VirtualBox configuration. Guest should not be enabled if not direly needed, it will make rebuilds unbearably slow. @@ -9285,7 +9347,7 @@
Auto login for the initial session. @@ -9304,7 +9366,7 @@
This smashes Atmosphere 1.3.2 on the switch, which is what I am currenty using. @@ -9326,7 +9388,7 @@
Options that I need specifically at work. There are more options at Work (home-manager side). @@ -9465,7 +9527,7 @@
These options are really only to be used on the iso image in order to run nixos-anywhere. @@ -9547,18 +9609,18 @@
The general structure is the same as in the NixOS section.
This section sets up all the imports that are used in the home-manager section. @@ -9608,7 +9670,7 @@
Again, we adapt nix
to our needs, enable the home-manager command for non-NixOS machines (NixOS machines are using it as a module) and setting user information that I always keep the same.
@@ -9646,7 +9708,7 @@
Here are defined some packages that I would like to use across all my machines. Most of these should not require further setup. Notably the cura package is severely outdated on nixpkgs, so I just fetch a more recent AppImage and run that instead. @@ -9661,7 +9723,7 @@
This holds packages that I can use as provided, or with small modifications (as in the texlive
package that needs special configuration).
@@ -9837,7 +9899,7 @@
This is just a separate container for derivations defined in Packages. This is a good idea so that I do not lose track of package names I have defined myself, as this was once a problem in the past already. @@ -9911,7 +9973,7 @@
I use sops-nix to handle secrets that I want to have available on my machines at all times. Procedure to add a new machine: @@ -9932,16 +9994,10 @@
{ config, lib, ... }: -let - mkIfElse = p: yes: no: lib.mkMerge [ - (lib.mkIf p yes) - (lib.mkIf (!p) no) - ]; -in { sops = lib.mkIf (!config.swarselsystems.isPublic) { age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" "${config.home.homeDirectory}/.ssh/ssh_host_ed25519_key" ]; - defaultSopsFile = mkIfElse config.swarselsystems.isBtrfs "/persist/.dotfiles/secrets/general/secrets.yaml" "${config.home.homeDirectory}/.dotfiles/secrets/general/secrets.yaml"; + defaultSopsFile = lib.swarselsystems.mkIfElseList config.swarselsystems.isBtrfs "/persist/.dotfiles/secrets/general/secrets.yaml" "${config.home.homeDirectory}/.dotfiles/secrets/general/secrets.yaml"; validateSopsFiles = false; secrets = { @@ -9959,7 +10015,7 @@4
It is very convenient to have SSH aliases in place for machines that I use. This is mainly used for some server machines and some university clusters. We also enable agent forwarding to have our Yubikey SSH key accessible on the remote host. @@ -10012,7 +10068,7 @@
These section allows home-manager to allow theme settings, and handles some other appearance-related settings like cursor styles. Interestingly, system icons (adwaita) still need to be setup on system-level, and will break if defined here. @@ -10088,7 +10144,7 @@
Some programs lack a dmenu launcher - I define them myself here. @@ -10189,7 +10245,7 @@
This section should be used in order to symlink already existing configuration files using `home.file` and setting session variables using `home.sessionVariables`. @@ -10245,7 +10301,7 @@
Sets environment variables. Here I am only setting the EDITOR variable, most variables are set in the Sway section. @@ -10265,7 +10321,7 @@
This section is for programs that require no further configuration. zsh Integration is enabled by default for these. @@ -10299,7 +10355,7 @@
nix-index provides a way to find out which packages are provided by which derivations. By default it also comes with a replacement for command-not-found.sh
, however, the implementation is based on a channel based setup. I like consistency, so I replace the command with one that provides a flakes-based output.
@@ -10332,7 +10388,7 @@
Enables password store with the pass-otp
extension which allows me to store and generate one-time-passwords.
@@ -10354,7 +10410,7 @@
Enables direnv, which I use for nearly all of my nix dev flakes. @@ -10373,7 +10429,7 @@
Eza provides me with a better ls
command and some other useful aliases.
@@ -10397,7 +10453,7 @@
Here I set up my git config, automatic signing of commits, useful aliases for my ost used commands (for when I am not using Magit) as well as a git template defined in Linking dotfiles. @@ -10448,7 +10504,7 @@
Here I only need to set basic layout options - the rest is being managed by stylix. @@ -10474,7 +10530,7 @@
Starship makes my zsh
look cooler! I have symbols for most programming languages and toolchains, also I build my own powerline.
@@ -10592,7 +10648,7 @@
Kitty is the terminal emulator of choice for me, it is nice to configure using nix, fast, and has a nice style. @@ -10620,7 +10676,7 @@
zsh is the most convenient shell for me and it happens to be super neat to configure within home manager. @@ -10760,7 +10816,7 @@
_: @@ -10969,7 +11025,7 @@4
@@ -11077,7 +11133,7 @@4
Normally I use 4 mail accounts - here I set them all up. Three of them are Google accounts (sadly), which are a chore to setup. The last is just a sender account that I setup SMTP for here. @@ -11219,7 +11275,7 @@
By using the emacs-overlay NixOS module, I can install all Emacs packages that I want to use right through NixOS. This is done by passing my init.el
file to the configuration which will then be parsed upon system rebuild, looking for use-package
sections in the Elisp code. Also I define here the style of Emacs that I want to run - I am going with native Wayland Emacs here (emacs-pgtk
). All of the nice options such as tree-sitter
support are enabled by default, so I do not need to adjust the build process.
@@ -11309,7 +11365,7 @@
Again I am just using the first bar option here that I was able to find good understandable documentation for. Of note is that the `cpu` section's `format` is not defined here, but in section 1 (since not every machine has the same number of cores) @@ -11595,7 +11651,7 @@
Setting up firefox along with some policies that are important to me (mostly disabling telemetry related stuff as well as Pocket). I also enable some integrations that enable super useful packages, namely tridactyl
and browserpass
.
@@ -11899,14 +11955,14 @@
Services that can be defined through home-manager should be defined here.
Used for storing sessions in e.g. Nextcloud @@ -11924,7 +11980,7 @@
This enables phone/computer communication, including sending clipboard, files etc. Sadly on Wayland many of the features are broken (like remote control). @@ -11944,7 +12000,7 @@
Desktop notifications! @@ -11991,7 +12047,7 @@
{ pkgs, ... }: @@ -12029,7 +12085,7 @@4
I am currently using SwayFX, which adds some nice effects to sway, like rounded corners and hiding the separator between title and content of a window. @@ -12043,15 +12099,7 @@
{ config, lib, ... }: let inherit (config.swarselsystems) monitors; - eachMonitor = _name: monitor: { - inherit (monitor) name; - value = builtins.removeAttrs monitor [ "workspace" "name" "output" ]; - }; - eachOutput = _name: monitor: { - inherit (monitor) name; - value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ]; - }; - workplaceSets = lib.mapAttrs' eachOutput monitors; + workplaceSets = lib.mapAttrs' lib.swarselsystems.eachOutput monitors; workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets); in { @@ -12177,7 +12225,7 @@+4 }; }; defaultWorkspace = "workspace 1:一"; - output = lib.mapAttrs' eachMonitor monitors; + output = lib.mapAttrs' lib.swarselsystems.eachMonitor monitors; input = config.swarselsystems.standardinputs; workspaceOutputAssign = workplaceOutputs; startup = config.swarselsystems.startup ++ [ @@ -12316,4501 +12364,5144 @@
4 set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\" mode $exit { - bindsym --to-code { - s exec \"systemctl suspend\", mode \"default\" - l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize && systemctl suspend \", mode \"default \" - p exec \"systemctl poweroff\" - r exec \"systemctl reboot\" - u exec \"swaymsg exit\" + bindsym --to-code { + s exec \"systemctl suspend\", mode \"default\" + l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize && systemctl suspend \", mode \"default \" + p exec \"systemctl poweroff\" + r exec \"systemctl reboot\" + u exec \"swaymsg exit\" + + Return mode \"default\" + Escape mode \"default\" + ${modifier}+Escape mode \"default\" + } + } + + exec systemctl --user import-environment + exec swayidle -w + + + ${swayfxSettings} + + "; + }; +} +
+Settinfs that are needed for the gpg-agent. Also we are enabling emacs support for unlocking my Yubikey here. +
+ +{ self, pkgs, ... }: +{ + services.gpg-agent = { + enable = true; + enableSshSupport = true; + enableExtraSocket = true; + pinentryPackage = pkgs.pinentry.gtk2; + defaultCacheTtl = 600; + maxCacheTtl = 7200; + extraConfig = '' + allow-loopback-pinentry + allow-emacs-pinentry + ''; + sshKeys = [ + "4BE7925262289B476DBBC17B76FD3810215AE097" + ]; + }; + + programs.gpg = { + enable = true; + publicKeys = [ + { + source = "${self}/secrets/keys/gpg/gpg-public-key-0x76FD3810215AE097.asc"; + trust = 5; + } + ]; + }; + + # assure correct permissions + systemd.user.tmpfiles.rules = [ + "d /home/swarsel/.gnupg 700 swarsel users" + ]; + +} ++
+This service changes the screen hue at night. I am not sure if that really does something, but I like the color anyways. +
+ +_: +{ + services.gammastep = { + enable = true; + provider = "manual"; + latitude = 48.210033; + longitude = 16.363449; + }; +} ++
+This section sets up all the imports that are used in the home-manager section. +
+ +{ self, ... }: +let + profilesPath = "${self}/profiles"; +in +{ + imports = [ + "${profilesPath}/common/home/settings.nix" + ./symlink.nix + ]; +} ++
+This section should be used in order to symlink already existing configuration files using `home.file` and setting session variables using `home.sessionVariables`. +
+ ++As for the `home.sessionVariables`, it should be noted that environment variables that are needed at system start should NOT be loaded here, but instead in `programs.zsh.config.extraSessionCommands` (in the home-manager programs section). This is also where all the wayland related variables are stored. +
+ +{ self, ... }: +{ + home.file = { + "init.el" = { + source = self + /programs/emacs/server.el; + target = ".emacs.d/init.el"; + }; + }; +} ++
+This section sets up all the imports that are used in the home-manager section. +
+ +{ self, ... }: +let + profilesPath = "${self}/profiles"; +in +{ + imports = [ + "${profilesPath}/common/home/settings.nix" + ]; +} ++
+Akin to the optional NixOS modules. +
++The rest of the settings is at gaming. +
+ +{ pkgs, ... }: +{ + # specialisation = { + # gaming.configuration = { + home.packages = with pkgs; [ + stable.lutris + wine + winetricks + libudev-zero + dwarfs + fuse-overlayfs + # steam + # steam-run + patchelf + gamescope + vulkan-tools + moonlight-qt + ns-usbloader + + quark-goldleaf + # gog games installing + heroic + + # minecraft + prismlauncher # has overrides + temurin-bin-17 + + pokefinder + retroarch + flips + ]; + # }; + # }; +} + ++
+The rest of the settings is at work. Here, I am setting up the different firefox profiles that I need for the SSO sites that I need to access at work as well as a few ssh shorthands. +
+ +{ config, pkgs, lib, ... }: +{ + home.packages = with pkgs; [ + stable.teams-for-linux + shellcheck + dig + docker + postman + rclone + awscli2 + libguestfs-with-appliance + ]; + + home.sessionVariables = { + DOCUMENT_DIR_PRIV = lib.mkForce "${config.home.homeDirectory}/Documents/Private"; + DOCUMENT_DIR_WORK = lib.mkForce "${config.home.homeDirectory}/Documents/Work"; + }; + programs = { + git.userEmail = "leon.schwarzaeugl@imba.oeaw.ac.at"; + + zsh = { + cdpath = [ + "~/Documents/Work" + ]; + dirHashes = { + d = "$HOME/.dotfiles"; + w = "$HOME/Documents/Work"; + s = "$HOME/.dotfiles/secrets"; + pr = "$HOME/Documents/Private"; + ac = "$HOME/.ansible/collections/ansible_collections/vbc/linux/roles"; + }; + }; + + + ssh = { + matchBlocks = { + "uc" = { + hostname = "uc.clip.vbc.ac.at"; + user = "stack"; + }; + "uc-stg" = { + hostname = "uc.staging.clip.vbc.ac.at"; + user = "stack"; + }; + "cbe" = { + hostname = "cbe.vbc.ac.at"; + user = "dc_adm_schwarzaeugl"; + }; + "cbe-stg" = { + hostname = "cbe.staging.vbc.ac.at"; + user = "dc_adm_schwarzaeugl"; + }; + "*.vbc.ac.at" = { + user = "dc_adm_schwarzaeugl"; + }; + }; + }; + + firefox = { + profiles = { + dc_adm = lib.recursiveUpdate { id = 1; } config.swarselsystems.firefox; + cl_adm = lib.recursiveUpdate { id = 2; } config.swarselsystems.firefox; + ws_adm = lib.recursiveUpdate { id = 3; } config.swarselsystems.firefox; + }; + }; + + chromium = { + enable = true; + package = pkgs.chromium; + + extensions = [ + # 1password + "gejiddohjgogedgjnonbofjigllpkmbf" + # dark reader + "eimadpbcbfnmbkopoojfekhnkhdbieeh" + # ublock origin + "cjpalhdlnbpafiamejdnhcphjbkeiagm" + # i still dont care about cookies + "edibdbjcniadpccecjdfdjjppcpchdlm" + # browserpass + "naepdomgkenhinolocfifgehidddafch" + ]; + }; + }; + + xdg = { + mimeApps = { + defaultApplications = { + "x-scheme-handler/msteams" = [ "teams-for-linux.desktop"] ; + }; + }; + desktopEntries = + let + terminal = false; + categories = [ "Application" ]; + icon = "firefox"; + in + { + firefox_dc = { + name = "Firefox (dc_adm)"; + genericName = "Firefox dc"; + exec = "firefox -p dc_adm"; + inherit terminal categories icon; + }; + + firefox_ws = { + name = "Firefox (ws_adm)"; + genericName = "Firefox ws"; + exec = "firefox -p ws_adm"; + inherit terminal categories icon; + }; + + firefox_cl = { + name = "Firefox (cl_adm)"; + genericName = "Firefox cl"; + exec = "firefox -p cl_adm"; + inherit terminal categories icon; + }; + + }; + }; + +} + ++
+In this section I handle my early init file; it takes care of frame-setup for emacsclient buffers. +
++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) + ;; (setq gc-cons-threshold #x40000000 + (setq gc-cons-threshold (* 32 1024 1024) + gc-cons-percentage 0.1 + jit-lock-defer-time 0.05 + read-process-output-max (* 1024 1024) + file-name-handler-alist swarsel-file-name-handler-alist + vc-handled-backends swarsel-vc-handled-backends) + (fset 'epg-wait-for-status 'ignore) + ))) + ++
+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)))) + ++
+By default, emacs binds +
+C-i
to the TAB
keyC-m
to the RET
keyC-[
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. +
+ +
+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]) + )))) + + + + ++
+This section is used to define my own functions, own variables, and own keybindings. +
++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. +
+
+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))) + ++
+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)) + ++
+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")) + + ++
+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) + ++
+When programming, I like to be able to duplicate a line. There are easier functions than the one below, but they either +
+ +
+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
+
+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)))) + ++
+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.
+
+(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))) + +(declare-function org-map-entries "org") + +(defun prot-org-id-headlines () + "Add missing CUSTOM_ID to all headlines in current file." + (interactive) + (org-map-entries + (lambda () (prot-org--id-get)))) - Return mode \"default\" - Escape mode \"default\" - ${modifier}+Escape mode \"default\" - } - } +(defun prot-org-id-headline () + "Add missing CUSTOM_ID to headline at point." + (interactive) + (prot-org--id-get)) - exec systemctl --user import-environment - exec swayidle -w ++
+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. +
+
+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:
+
+(advice-add 'message :around #'who-called-me?) - "; - }; -}
+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:
+
+(advice-remove 'message #'who-called-me?) + +
-Settinfs that are needed for the gpg-agent. Also we are enabling emacs support for unlocking my Yubikey here.
+Lastly, individual messages can be reenabled using the (advice-remove '<FUNCTION-NAME> #'suppress-messages)
approach. Use this when you accidentally disabled a helpful message.
{ self, pkgs, ... }: -{ - services.gpg-agent = { - enable = true; - enableSshSupport = true; - enableExtraSocket = true; - pinentryPackage = pkgs.pinentry.gtk2; - defaultCacheTtl = 600; - maxCacheTtl = 7200; - extraConfig = '' - allow-loopback-pinentry - allow-emacs-pinentry - ''; - sshKeys = [ - "4BE7925262289B476DBBC17B76FD3810215AE097" - ]; - }; ++(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)))) - programs.gpg = { - enable = true; - publicKeys = [ - { - source = "${self}/secrets/keys/gpg/gpg-public-key-0x76FD3810215AE097.asc"; - trust = 5; - } - ]; - }; +(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) +(advice-add 'evil-insert :around #'suppress-messages) +(advice-add 'evil-visual-char :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?) - # assure correct permissions - systemd.user.tmpfiles.rules = [ - "d /home/swarsel/.gnupg 700 swarsel users" - ]; -}
-This service changes the screen hue at night. I am not sure if that really does something, but I like the color anyways. +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. +
+ ++This function was found here: https://www.reddit.com/r/emacs/comments/re31i6/how_to_go_up_one_directory_when_using_findfile_cx/
_: -{ - services.gammastep = { - enable = true; - provider = "manual"; - latitude = 48.210033; - longitude = 16.363449; - }; -} ++(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) +
-This section sets up all the imports that are used in the home-manager section. +Sets up the basic settings that I want to have active in org-mode buffers. +
+ ++Used here: General org-mode
{ self, ... }: -let - profilesPath = "${self}/profiles"; -in -{ - imports = [ - "${profilesPath}/common/home/settings.nix" - ./symlink.nix - ]; -} ++(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)) +
-This section should be used in order to symlink already existing configuration files using `home.file` and setting session variables using `home.sessionVariables`. +This function sets the width of buffers in org-mode.
-As for the `home.sessionVariables`, it should be noted that environment variables that are needed at system start should NOT be loaded here, but instead in `programs.zsh.config.extraSessionCommands` (in the home-manager programs section). This is also where all the wayland related variables are stored. +Used in: Centered org-mode Buffers
{ self, ... }: -{ - home.file = { - "init.el" = { - source = self + /programs/emacs/server.el; - target = ".emacs.d/init.el"; - }; - }; -} ++(defun swarsel/org-mode-visual-fill () + (setq visual-fill-column-width 150 + visual-fill-column-center-text t) + (visual-fill-column-mode 1)) +
+This section handles everything that shoudld happen when I save SwarselSystems.org
. It:
+
.nix
files in accordance to the Alejandra
-style.+We set a hook that runs everytime we save the file. It would be a bit more efficient to only export and format when we enter a magit window for instance (since especially the html export takes times), however, since I cannot be sure to only ever commit from magit (I do indeed sometimes use git from the command line), I prefer this approach. +
+ +(defun swarsel/run-formatting () + (interactive) + (let ((default-directory (expand-file-name "~/.dotfiles"))) + (shell-command "nixpkgs-fmt . > /dev/null"))) + + (defun swarsel/org-babel-tangle-config () + (interactive) + (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) + (swarsel/run-formatting) + ))) + + (setq org-html-htmlize-output-type nil) + + ;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config))) + ++
-This section sets up all the imports that are used in the home-manager section. +Normally emacs cycles between three states: +
+ ++However, I want to be able to fold a single heading consistently.
{ self, ... }: -let - profilesPath = "${self}/profiles"; -in -{ - imports = [ - "${profilesPath}/common/home/settings.nix" - ]; -} ++(defun org-fold-outer () + (interactive) + (org-beginning-of-line) + (if (string-match "^*+" (thing-at-point 'line t)) + (outline-up-heading 1)) + (outline-hide-subtree) + ) +
-Akin to the optional NixOS modules. +These three functions allow me to keep using the normal navigation keys even when a corfu completion pops up.
--The rest of the settings is at gaming. +These functions are used here: Corfu
{ pkgs, ... }: -{ - # specialisation = { - # gaming.configuration = { - home.packages = with pkgs; [ - stable.lutris - wine - winetricks - libudev-zero - dwarfs - fuse-overlayfs - # steam - # steam-run - patchelf - gamescope - vulkan-tools - moonlight-qt - ns-usbloader - - quark-goldleaf - # gog games installing - heroic ++(defun swarsel/corfu-normal-return (&optional arg) + (interactive) + (corfu-quit) + (newline) + ) - # minecraft - prismlauncher # has overrides - temurin-bin-17 +(defun swarsel/corfu-quit-and-up (&optional arg) + (interactive) + (corfu-quit) + (evil-previous-visual-line)) - pokefinder - retroarch - flips - ]; - # }; - # }; -} +(defun swarsel/corfu-quit-and-down (&optional arg) + (interactive) + (corfu-quit) + (evil-next-visual-line))
-The rest of the settings is at work. Here, I am setting up the different firefox profiles that I need for the SSO sites that I need to access at work as well as a few ssh shorthands. +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.
{ config, pkgs, lib, ... }: -{ - home.packages = with pkgs; [ - stable.teams-for-linux - shellcheck - dig - docker - postman - rclone - awscli2 - libguestfs-with-appliance - ]; - - home.sessionVariables = { - DOCUMENT_DIR_PRIV = lib.mkForce "${config.home.homeDirectory}/Documents/Private"; - DOCUMENT_DIR_WORK = lib.mkForce "${config.home.homeDirectory}/Documents/Work"; - }; - programs = { - git.userEmail = "leon.schwarzaeugl@imba.oeaw.ac.at"; - - zsh = { - cdpath = [ - "~/Documents/Work" - ]; - dirHashes = { - d = "$HOME/.dotfiles"; - w = "$HOME/Documents/Work"; - s = "$HOME/.dotfiles/secrets"; - pr = "$HOME/Documents/Private"; - ac = "$HOME/.ansible/collections/ansible_collections/vbc/linux/roles"; - }; - }; - - - ssh = { - matchBlocks = { - "uc" = { - hostname = "uc.clip.vbc.ac.at"; - user = "stack"; - }; - "uc-stg" = { - hostname = "uc.staging.clip.vbc.ac.at"; - user = "stack"; - }; - "cbe" = { - hostname = "cbe.vbc.ac.at"; - user = "dc_adm_schwarzaeugl"; - }; - "cbe-stg" = { - hostname = "cbe.staging.vbc.ac.at"; - user = "dc_adm_schwarzaeugl"; - }; - "*.vbc.ac.at" = { - user = "dc_adm_schwarzaeugl"; - }; - }; - }; - - firefox = { - profiles = { - dc_adm = lib.recursiveUpdate { id = 1; } config.swarselsystems.firefox; - cl_adm = lib.recursiveUpdate { id = 2; } config.swarselsystems.firefox; - ws_adm = lib.recursiveUpdate { id = 3; } config.swarselsystems.firefox; - }; - }; - - chromium = { - enable = true; - package = pkgs.chromium; - - extensions = [ - # 1password - "gejiddohjgogedgjnonbofjigllpkmbf" - # dark reader - "eimadpbcbfnmbkopoojfekhnkhdbieeh" - # ublock origin - "cjpalhdlnbpafiamejdnhcphjbkeiagm" - # i still dont care about cookies - "edibdbjcniadpccecjdfdjjppcpchdlm" - # browserpass - "naepdomgkenhinolocfifgehidddafch" - ]; - }; - }; ++;; run the python inferior shell immediately upon entering a python buffer +;; (add-hook 'python-mode-hook 'swarsel/run-python) - xdg = { - mimeApps = { - defaultApplications = { - "x-scheme-handler/msteams" = [ "teams-for-linux.desktop"] ; - }; - }; - desktopEntries = - let - terminal = false; - categories = [ "Application" ]; - icon = "firefox"; - in - { - firefox_dc = { - name = "Firefox (dc_adm)"; - genericName = "Firefox dc"; - exec = "firefox -p dc_adm"; - inherit terminal categories icon; - }; +;; (defun swarsel/run-python () +;; (save-selected-window +;; (switch-to-buffer-other-window (process-buffer (python-shell-get-or-create-process (python-shell-parse-command)))))) - firefox_ws = { - name = "Firefox (ws_adm)"; - genericName = "Firefox ws"; - exec = "firefox -p ws_adm"; - inherit terminal categories icon; - }; +;; 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))) - firefox_cl = { - name = "Firefox (cl_adm)"; - genericName = "Firefox cl"; - exec = "firefox -p cl_adm"; - inherit terminal categories icon; - }; +(defun my-python-shell-run-region () + (interactive) + (python-shell-send-region (region-beginning) (region-end)) + (python-shell-switch-to-shell)) - }; - }; ++
+This function searches for common delimiters in region and removes them, summarizing all captured lines by it. +
-} ++(defun swarsel/prefix-block (start end) + (interactive "r") + (save-excursion + (goto-char start) + (setq start (line-beginning-position)) + (goto-char end) + (setq end (line-end-position)) + (let ((common-prefix (save-excursion + (goto-char start) + (if (re-search-forward "^\\([^.\n]+\\)\\." end t) + (match-string 1) + (error "No common prefix found"))))) + (save-excursion + (goto-char start) + (insert common-prefix " = {\n") + (goto-char (+ end (length common-prefix) 6)) + (insert "};\n") + (goto-char start) + (while (re-search-forward (concat "^" (regexp-quote common-prefix) "\\.") end t) + (replace-match ""))))))
-In this section I handle my early init file; it takes care of frame-setup for emacsclient buffers. -
--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
.
+This formats the org code block at point
in accordance to the nixpkgs-fmt
formatter
-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. -
++(defun swarsel/org-nixpkgs-fmt-block-lite () + (interactive) + (org-babel-mark-block) + (call-interactively 'nixpkgs-fmt-region)) -+-Also packed into the hook function is the line
+ (defun swarsel/org-nixpkgs-fmt-block () + (interactive) + (save-excursion + (let* ((element (org-element-at-point)) + (begin (org-element-property :begin element)) + (end (org-element-property :end element)) + (lang (org-element-property :language element))) + (when lang + (goto-char begin) + (forward-line) + (insert "{") + (goto-char end) + (forward-line -1) + (beginning-of-line) + (forward-char -1) + (insert "}") + (org-babel-mark-block) + (call-interactively 'nixpkgs-fmt-region))))) +(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) ++(defun swarsel/minibuffer-setup-hook () + (setq gc-cons-threshold most-positive-fixnum)) -(setq gc-cons-threshold most-positive-fixnum - gc-cons-percentage 0.6 - file-name-handler-alist nil - vc-handled-backends nil) +(defun swarsel/minibuffer-exit-hook () + (setq gc-cons-threshold (* 32 1024 1024))) + +(add-hook 'minibuffer-setup-hook #'swarsel/minibuffer-setup-hook) +(add-hook 'minibuffer-exit-hook #'swarsel/minibuffer-exit-hook) -(add-hook 'emacs-startup-hook - (lambda () - (progn - ;; (setq gc-cons-threshold (* 1000 1000 8) - ;; (setq gc-cons-threshold #x40000000 - (setq gc-cons-threshold (* 32 1024 1024) - gc-cons-percentage 0.1 - jit-lock-defer-time 0.05 - read-process-output-max (* 1024 1024) - file-name-handler-alist swarsel-file-name-handler-alist - vc-handled-backends swarsel-vc-handled-backends) - (fset 'epg-wait-for-status 'ignore) - )))
-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.
+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.
-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.
+I also define some keybinds to some combinations directly. Those are used mostly for custom functions that I call often enough to warrant this.
(tool-bar-mode 0) -(menu-bar-mode 0) -(scroll-bar-mode 0) ++ ;; Make ESC quit prompts + (global-set-key (kbd "<escape>") 'keyboard-escape-quit) -(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 - ) + ;; 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") -(setq-default left-margin-width 1 - right-margin-width 1) + (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") + "mr" '(bjm/elfeed-load-db-and-open :which-key "elfeed") + "o" '(:ignore o :which-key "org") + "op" '((lambda () (interactive) (org-present)) :which-key "org-present") + "oa" '((lambda () (interactive) (org-agenda)) :which-key "org-agenda") + "oa" '((lambda () (interactive) (org-refile)) :which-key "org-refile") + "ob" '((lambda () (interactive) (org-babel-mark-block)) :which-key "Mark whole src-block") + "ol" '((lambda () (interactive) (org-insert-link)) :which-key "insert link") + "oc" '((lambda () (interactive) (org-store-link)) :which-key "copy (=store) link") + "os" '(shfmt-region :which-key "format sh-block") + "od" '((lambda () (interactive) (org-babel-demarcate-block)) :which-key "demarcate (split) src-block") + "on" '(nixpkgs-fmt-region :which-key "format nix-block") + "ot" '(swarsel/org-babel-tangle-config :which-key "tangle file") + "oe" '(org-html-export-to-html :which-key "export to html") + "c" '(:ignore c :which-key "capture") + "ct" '((lambda () (interactive) (org-capture nil "tt")) :which-key "task") + ;; "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@winters:")) :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 + "w <right>" 'windmove-right + "wh" 'windmove-left + "w <left>" 'windmove-left + "wk" 'windmove-up + "w <up>" 'windmove-up + "wj" 'windmove-down + "w <down>" '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-vsplit + "w-" 'evil-window-split + "wm" '(delete-other-windows :wk "maximize") + "<right>" 'up-list + "<left>" '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 + "<DUMMY-m>" 'swarsel/last-buffer + "M-\\" 'indent-region + "C-<f9>" 'my-python-shell-run + "<Paste>" 'yank + "<Cut>" 'kill-region + "<Copy>" 'kill-ring-save + "<undo>" 'evil-undo + "<redo>" 'evil-redo + "C-S-c C-S-c" 'mc/edit-lines + "C->" 'mc/mark-next-like-this + "C-<" 'mc/mark-previous-like-this + "C-c C-<" 'mc/mark-all-like-this + ) -(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))))
-By default, emacs binds -
-C-i
to the TAB
keyC-m
to the RET
keyC-[
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. -
- +
-NOTE: To use these keybinds, you need to enclose the binding in angled brackets (<>
). Then they can be used normally
+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.
-(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]) - )))) +;; 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") --
-This section is used to define my own functions, own variables, and own keybindings. -
--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. -
-
-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))) +;; 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)) --
-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))
-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
.
+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.
-Used here: mu4e
+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 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")) +;; 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)
-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.
+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/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)))) +(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)) -(add-to-list 'find-file-not-found-functions #'swarsel/with-buffer-name-prompt-and-make-subdirs) +(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
-When programming, I like to be able to duplicate a line. There are easier functions than the one below, but they either -
- -
-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 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.
-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. +Here I set up some things that are too minor to put under other categories.
+-(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))) +;; use UTF-8 everywhere +(set-language-environment "UTF-8") +(profiler-start 'cpu) +;; 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-default bidi-paragraph-direction 'left-to-right + bidi-display-reordering 'left-to-right + bidi-inhibit-bpa t) +(global-so-long-mode) +(setq process-adaptive-read-buffering nil) ;; not sure if this is a good idea +(setq fast-but-imprecise-scrolling t + redisplay-skip-fontification-on-input t + inhibit-compacting-font-caches t) +(setq idle-update-delay 1.0 + which-func-update-delay 1.0) +(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')"))) -(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)))) +(setq visible-bell nil) +(setq initial-major-mode 'fundamental-mode + initial-scratch-message nil) -(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)))) +(add-hook 'prog-mode-hook 'display-line-numbers-mode) +;; (add-hook 'text-mode-hook 'display-line-numbers-mode) +;; (global-visual-line-mode 1)
-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.
+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.
-(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))) - -(declare-function org-map-entries "org") - -(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)) +(setq custom-safe-themes t)
-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. -
- +
-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:
+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).
-(advice-add 'message :around #'who-called-me?) +(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
-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:
+This sets up automatic garbage collection when the frame is unused.
-(advice-remove 'message #'who-called-me?) +(setq garbage-collection-messages nil) +(defmacro k-time (&rest body) + "Measure and return the time it takes evaluating BODY." + `(let ((time (current-time))) + ,@body + (float-time (time-since time)))) + + +;; When idle for 15sec run the GC no matter what. +(defvar k-gc-timer + (run-with-idle-timer 15 t + (lambda () + ;; (message "Garbage Collector has run for %.06fsec" + (k-time (garbage-collect))))) + ;; )
+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. +
-Lastly, individual messages can be reenabled using the (advice-remove '<FUNCTION-NAME> #'suppress-messages)
approach. Use this when you accidentally disabled a helpful message.
+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 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) -(advice-add 'evil-insert :around #'suppress-messages) -(advice-add 'evil-visual-char :around #'suppress-messages) - -;; to reenable -;; (advice-remove 'timer-event-handler #'suppress-messages) +(setq-default indent-tabs-mode nil + tab-width 2) -(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)))) +(setq tab-always-indent 'complete) +(setq python-indent-guess-indent-offset-verbose nil) -;; enable to get message backtrace, the first function shown in backtrace calls the other functions -;; (advice-add 'message :around #'who-called-me?) +(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) + ) -;; disable to stop receiving backtrace -(advice-remove 'message #'who-called-me?) +(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")) +(use-package aggressive-indent) +(global-aggressive-indent-mode 1)
-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. -
- +-This function was found here: https://www.reddit.com/r/emacs/comments/re31i6/how_to_go_up_one_directory_when_using_findfile_cx/ +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.
-(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)))) +(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) -(define-key minibuffer-local-filename-completion-map - [C-backspace] #'up-directory) +(setq-default scroll-preserve-screen-position t + scroll-conservatively 1 + scroll-margin 0 + next-screen-context-lines 0) + +(pixel-scroll-precision-mode 1)
-Sets up the basic settings that I want to have active in org-mode buffers.
+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.
+
+Also, I setup initial modes for several major-modes depending on what I deem fit.
++;; 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 nil) ; i am torn on this one + (setq evil-split-window-below t) + (setq evil-vsplit-window-right t) + :config + (evil-mode 1) + + ;; make normal mode respect wrapped lines + (define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line) + (define-key evil-normal-state-map (kbd "<down>") 'evil-next-visual-line) + (define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line) + (define-key evil-normal-state-map (kbd "<up>") 'evil-previous-visual-line) + + (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))) + ++
-Used here: General org-mode +This gives support for many different modes, and works beautifully out of the box.
-(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)) - +(use-package evil-collection + :after evil + :config + (evil-collection-init) + (setq forge-add-default-bindings nil))
-This function sets the width of buffers in org-mode. -
- +
-Used in: Centered org-mode Buffers
+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
.
-(defun swarsel/org-mode-visual-fill () - (setq visual-fill-column-width 150 - visual-fill-column-center-text t) - (visual-fill-column-mode 1)) - +;; 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))
-This section handles everything that shoudld happen when I save SwarselSystems.org
. It:
-
.nix
files in accordance to the Alejandra
-style.-We set a hook that runs everytime we save the file. It would be a bit more efficient to only export and format when we enter a magit window for instance (since especially the html export takes times), however, since I cannot be sure to only ever commit from magit (I do indeed sometimes use git from the command line), I prefer this approach. +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.
(defun swarsel/run-formatting () - (interactive) - (let ((default-directory (expand-file-name "~/.dotfiles"))) - (shell-command "nixpkgs-fmt . > /dev/null"))) - - (defun swarsel/org-babel-tangle-config () - (interactive) - (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) - (swarsel/run-formatting) - ))) - - (setq org-html-htmlize-output-type nil) - - ;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config))) +;; for parentheses-heavy languades modify evil commands to keep balance of parantheses +(use-package evil-cleverparens)
-Normally emacs cycles between three states: -
- -
-However, I want to be able to fold a single heading consistently.
+This minor-mode adds functionality for doing better surround-commands; for example ci[
will let you change the word within square brackets.
-(defun org-fold-outer () - (interactive) - (org-beginning-of-line) - (if (string-match "^*+" (thing-at-point 'line t)) - (outline-up-heading 1)) - (outline-hide-subtree) - ) +;; enables surrounding text with S +(use-package evil-surround + :config + (global-evil-surround-mode 1))
-These three functions allow me to keep using the normal navigation keys even when a corfu completion pops up. -
- +-These functions are used here: Corfu +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.
-(defun swarsel/corfu-normal-return (&optional arg) - (interactive) - (corfu-quit) - (newline) - ) - -(defun swarsel/corfu-quit-and-up (&optional arg) - (interactive) - (corfu-quit) - (evil-previous-visual-line)) - -(defun swarsel/corfu-quit-and-down (&optional arg) - (interactive) - (corfu-quit) - (evil-next-visual-line)) +;; set the NixOS wordlist by hand +(setq ispell-alternate-dictionary (getenv "WORDLIST"))
-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. +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.
-;; run the python inferior shell immediately upon entering a python buffer -;; (add-hook 'python-mode-hook 'swarsel/run-python) +(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")) -;; (defun swarsel/run-python () -;; (save-selected-window -;; (switch-to-buffer-other-window (process-buffer (python-shell-get-or-create-process (python-shell-parse-command)))))) +(set-face-attribute 'default nil :height 100) +(set-face-attribute 'fixed-pitch nil :height 1.0) -;; 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))) +(set-face-attribute 'variable-pitch nil + :family "IBM Plex Sans" + :weight 'regular + :height 1.06) -(defun my-python-shell-run-region () - (interactive) - (python-shell-send-region (region-beginning) (region-end)) - (python-shell-switch-to-shell)) +;; these settings used to be in custom.el
-This function searches for common delimiters in region and removes them, summarizing all captured lines by 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).
-(defun swarsel/prefix-block (start end) - (interactive "r") - (save-excursion - (goto-char start) - (setq start (line-beginning-position)) - (goto-char end) - (setq end (line-end-position)) - (let ((common-prefix (save-excursion - (goto-char start) - (if (re-search-forward "^\\([^.\n]+\\)\\." end t) - (match-string 1) - (error "No common prefix found"))))) - (save-excursion - (goto-char start) - (insert common-prefix " = {\n") - (goto-char (+ end (length common-prefix) 6)) - (insert "};\n") - (goto-char start) - (while (re-search-forward (concat "^" (regexp-quote common-prefix) "\\.") end t) - (replace-match "")))))) +(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))
-This formats the org code block at point
in accordance to the nixpkgs-fmt
formatter
-
-(defun swarsel/org-nixpkgs-fmt-block-lite () - (interactive) - (org-babel-mark-block) - (call-interactively 'nixpkgs-fmt-region)) - - - (defun swarsel/org-nixpkgs-fmt-block () - (interactive) - (save-excursion - (let* ((element (org-element-at-point)) - (begin (org-element-property :begin element)) - (end (org-element-property :end element)) - (lang (org-element-property :language element))) - (when lang - (goto-char begin) - (forward-line) - (insert "{") - (goto-char end) - (forward-line -1) - (beginning-of-line) - (forward-char -1) - (insert "}") - (org-babel-mark-block) - (call-interactively 'nixpkgs-fmt-region))))) ++-4.3.11. Icons
+++This section loads the base icons used in my configuration. I am using
+ +nerd-icons
overall-the-icons
since the former seems to have more integrations with different packages than the latter. ++Used in: +
+ + +++(use-package nerd-icons) +-5.2.1.17. Disable garbace collection while minibuffer is active
-+-+-4.3.12. Variable Pitch Mode
+++This minor mode allows mixing fixed and variable pitch fonts within the same buffer. +
+-(defun swarsel/minibuffer-setup-hook () - (setq gc-cons-threshold most-positive-fixnum)) - -(defun swarsel/minibuffer-exit-hook () - (setq gc-cons-threshold (* 32 1024 1024))) - -(add-hook 'minibuffer-setup-hook #'swarsel/minibuffer-setup-hook) -(add-hook 'minibuffer-exit-hook #'swarsel/minibuffer-exit-hook) +(use-package mixed-pitch + :custom + (mixed-pitch-set-height nil) + (mixed-pitch-variable-pitch-cursor nil) + :hook + (text-mode . mixed-pitch-mode))-5.2.2. Custom Keybindings
-++-4.3.13. Modeline
+-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. +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 formu4e
and git information.-I also define some keybinds to some combinations directly. Those are used mostly for custom functions that I call often enough to warrant this. +I have currently disabled this in favor of mini-modeline.
- ;; 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") - - (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") - "mr" '(bjm/elfeed-load-db-and-open :which-key "elfeed") - "o" '(:ignore o :which-key "org") - "op" '((lambda () (interactive) (org-present)) :which-key "org-present") - "oa" '((lambda () (interactive) (org-agenda)) :which-key "org-agenda") - "oa" '((lambda () (interactive) (org-refile)) :which-key "org-refile") - "ob" '((lambda () (interactive) (org-babel-mark-block)) :which-key "Mark whole src-block") - "ol" '((lambda () (interactive) (org-insert-link)) :which-key "insert link") - "oc" '((lambda () (interactive) (org-store-link)) :which-key "copy (=store) link") - "os" '(shfmt-region :which-key "format sh-block") - "od" '((lambda () (interactive) (org-babel-demarcate-block)) :which-key "demarcate (split) src-block") - "on" '(nixpkgs-fmt-region :which-key "format nix-block") - "ot" '(swarsel/org-babel-tangle-config :which-key "tangle file") - "oe" '(org-html-export-to-html :which-key "export to html") - "c" '(:ignore c :which-key "capture") - "ct" '((lambda () (interactive) (org-capture nil "tt")) :which-key "task") - ;; "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@winters:")) :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 - "w <right>" 'windmove-right - "wh" 'windmove-left - "w <left>" 'windmove-left - "wk" 'windmove-up - "w <up>" 'windmove-up - "wj" 'windmove-down - "w <down>" '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-vsplit - "w-" 'evil-window-split - "wm" '(delete-other-windows :wk "maximize") - "<right>" 'up-list - "<left>" '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 - "<DUMMY-m>" 'swarsel/last-buffer - "M-\\" 'indent-region - "C-<f9>" 'my-python-shell-run - "<Paste>" 'yank - "<Cut>" 'kill-region - "<Copy>" 'kill-ring-save - "<undo>" 'evil-undo - "<redo>" 'evil-redo - "C-S-c C-S-c" 'mc/edit-lines - "C->" 'mc/mark-next-like-this - "C-<" 'mc/mark-previous-like-this - "C-c C-<" 'mc/mark-all-like-this - ) +(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)))-5.2.3. Directory setup / File structure
-++-4.3.14. mini-modeline
+-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. +I have found that the doom-modeline, while very useful, consumes too much screen space for my liking. This modeline takes a more minimalistic approach.
-;; 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)) +(use-package mini-modeline + :after smart-mode-line + :config + (mini-modeline-mode t) + (setq mini-modeline-display-gui-line nil) + (setq mini-modeline-enhance-visual nil) + (setq mini-modeline-truncate-p nil) + (setq mini-modeline-l-format nil) + (setq mini-modeline-right-padding 5) + (setq window-divider-mode t) + (setq window-divider-default-places t) + (setq window-divider-default-bottom-width 1) + (setq window-divider-default-right-width 1) + (setq mini-modeline-r-format '("%e" mode-line-front-space mode-line-mule-info mode-line-client + mode-line-modified mode-line-remote mode-line-frame-identification + mode-line-buffer-identification " " mode-line-position " " mode-name evil-mode-line-tag )) + ) +(use-package smart-mode-line + :config + (sml/setup) + (add-to-list 'sml/replacer-regexp-list '("^~/Documents/Work/" ":WK:")) + (add-to-list 'sml/replacer-regexp-list '("^~/Documents/Private/" ":PR:")) + (add-to-list 'sml/replacer-regexp-list '("^~/.dotfiles/" ":D:") t) + )-5.2.4. Unclutter .emacs.d
-++4.3.15. Helper Modes
++++4.3.15.1. Vertico, Orderless, Marginalia, Consult, Embark
++-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 (throughmake-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 set of packages uses the default emacs completion framework and works together to provide a very nice user 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
orconsult-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.
+-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
. +Nerd icons is originally enabled here: Icons+-4.3.15.1.1. vertico
+-;; 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) +(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))-5.2.5. Move backup files to another location
-+-+-4.3.15.1.2. vertico-directory
+-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 package allows forIdo
-like directory navigation.--(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 +(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))-5.3. General init.el setup + UI
----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. -
--5.3.1. General setup
-++-4.3.15.1.3. orderless
+-Here I set up some things that are too minor to put under other categories. +When first installing orderless, I often times faced the problem, that when editing long files and calling
-consult-line
, Emacs would hang when changing a search term in the middle (e.g. fromservicse.xserver
toservic.xserver
in order to fix the typo). The below orderless rules have a more strict matching that has a positive impact on performance.-
- 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.
--;; use UTF-8 everywhere -(set-language-environment "UTF-8") -(profiler-start 'cpu) -;; 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-default bidi-paragraph-direction 'left-to-right - bidi-display-reordering 'left-to-right - bidi-inhibit-bpa t) -(global-so-long-mode) -(setq process-adaptive-read-buffering nil) ;; not sure if this is a good idea -(setq fast-but-imprecise-scrolling t - redisplay-skip-fontification-on-input t - inhibit-compacting-font-caches t) -(setq idle-update-delay 1.0 - which-func-update-delay 1.0) -(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) +(use-package orderless + :config + (orderless-define-completion-style orderless+initialism + (orderless-matching-styles '(orderless-initialism orderless-literal orderless-regexp))) + (setq completion-styles '(orderless) + completion-category-defaults nil + completion-category-overrides + '((file (styles partial-completion orderless+initialism)) + (buffer (styles orderless+initialism)) + (consult-multi (styles orderless+initialism)) + (command (styles orderless+initialism)) + (eglot (styles orderless+initialism)) + (variable (styles orderless+initialism)) + (symbol (styles orderless+initialism))) + orderless-matching-styles '(orderless-literal orderless-regexp))) -(add-hook 'prog-mode-hook 'display-line-numbers-mode) -;; (add-hook 'text-mode-hook 'display-line-numbers-mode) -;; (global-visual-line-mode 1)-5.3.2. Mark all themes as safe
-++-4.3.15.1.4. consult
+-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. +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 weirdC-M-j
command that I chose forivy-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.-(setq custom-safe-themes t) +(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)))-5.3.3. Show less compilation warnings
-++-4.3.15.1.5. embark
+-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). +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.-(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 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)))))-5.3.4. Better garbage collection
-++-4.3.15.1.6. embark-consult
+-This sets up automatic garbage collection when the frame is unused. +Provides previews for embark.
-(setq garbage-collection-messages nil) -(defmacro k-time (&rest body) - "Measure and return the time it takes evaluating BODY." - `(let ((time (current-time))) - ,@body - (float-time (time-since time)))) - - -;; When idle for 15sec run the GC no matter what. -(defvar k-gc-timer - (run-with-idle-timer 15 t - (lambda () - ;; (message "Garbage Collector has run for %.06fsec" - (k-time (garbage-collect))))) - ;; ) - ++(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))-5.3.5. Indentation
---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. -+-4.3.15.1.7. marginalia
+-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. +I set the annotation-mode of marginalia toheavy
. This gives even more information on the stuff that you are looking at. One thing I am missing from ivy is the highlighting onmode
-commands based on the current state of the mode. Also, I do not understand all the shorthands used by marginalia yet.--(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")) - -(use-package aggressive-indent) -(global-aggressive-indent-mode 1) +(use-package marginalia + :after vertico + :init + (marginalia-mode) + (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))-5.3.6. Scrolling
-++-4.3.15.1.8. nerd-icons-completion
+-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. +As stated above, this simply provides nerd-icons to the completion framework.
-(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) +(use-package nerd-icons-completion + :after (marginalia nerd-icons) + :hook (marginalia-mode . nerd-icons-completion-marginalia-setup) + :init + (nerd-icons-completion-mode)) -(pixel-scroll-precision-mode 1)-5.3.7. Evil
---5.3.7.1. 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. -+-4.3.15.2. Helpful + which-key: Better help defaults
+-Also, I setup initial modes for several major-modes depending on what I deem fit. +This pair of packages provides information on keybinds in addition to function names, which makes it easier to remember keybinds (
which-key
). Thehelpful
package provides a betterHelp
framework for Emacs. For some reason, the Help windows are always being focused by the cursor even though I have sethelp-window-select
to nil. I do not understand why.-;; 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 nil) ; i am torn on this one - (setq evil-split-window-below t) - (setq evil-vsplit-window-right t) +(use-package which-key + :init (which-key-mode) + :diminish which-key-mode :config - (evil-mode 1) - - ;; make normal mode respect wrapped lines - (define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line) - (define-key evil-normal-state-map (kbd "<down>") 'evil-next-visual-line) - (define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line) - (define-key evil-normal-state-map (kbd "<up>") 'evil-previous-visual-line) - - (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))) + (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))-5.3.7.2. evil-collection
-+++-4.3.16. Ligatures
+-This gives support for many different modes, and works beautifully out of the box. +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 evil-collection - :after evil +(use-package ligature + :init + (global-ligature-mode t) :config - (evil-collection-init) - (setq forge-add-default-bindings nil)) + (ligature-set-ligatures 'prog-mode + '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>" + ":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!==" + "!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<" + "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->" + "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<" + "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~=" + "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|" + "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:" + ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:" + "<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!" + "##" "#(" "#?" "#_" "%%" ".=" ".." ".?" "+>" "++" "?:" "?=" + "?." "??" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)" "\\\\" + "://" ";;"))) +-5.3.7.3. evil-snipe
-++-4.3.17. Popup (popper) + Shackle Buffers
+-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 usings
andS
. +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 usingpopper-toggle
and the resulting frame can be freely customized (withshackle
) 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.-;; enables 2-char inline search -(use-package evil-snipe - :after evil - :demand ++(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 - (evil-snipe-mode +1) - ;; replace 1-char searches (f&t) with this better UI - (evil-snipe-override-mode +1)) + (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)) +-5.3.7.4. evil-cleverparens
-++-4.3.18. Indicate first and last line of buffer
+-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. +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.
-;; for parentheses-heavy languades modify evil commands to keep balance of parantheses -(use-package evil-cleverparens) ++(setq-default indicate-buffer-boundaries t)-5.3.7.5. evil-surround
-+-+4.3.19. Authentication
+-This minor-mode adds functionality for doing better surround-commands; for example
ci[
will let you change the word within square brackets. +This defines the authentication sources used byorg-calfw
(Calendar) and Forge.-;; enables surrounding text with S -(use-package evil-surround - :config - (global-evil-surround-mode 1)) +;; (setq auth-sources '( "~/.emacs.d/.caldav" "~/.emacs.d/.authinfo.gpg") + ;; auth-source-cache-expiry nil) ; default is 2h +(setq auth-sources '( "~/.emacs.d/.authinfo") + auth-source-cache-expiry nil)-5.3.8. ispell
-++4.4. Modules
++-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. +This section houses all configuration bits that are related to a specific package that is not fundamental to my Emacs experience.
--+-;; set the NixOS wordlist by hand -(setq ispell-alternate-dictionary (getenv "WORDLIST")) - --+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. +
+ ++Note that nearly all headings within the
Org-mode
heading are coded within theuse-package
setup, so be very careful about moving stuff about here. +-5.3.9. Font Configuration
-++-4.4.1.1. General org-mode
+-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 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
-(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) +(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) -;; these settings used to be in custom.el + ;; (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-export-headline-levels 6) + (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" "$" "$$" "\\(" "\\[")))-5.3.10. Theme
-++-4.4.1.2. org-agenda
+-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). +Here I setup a plethora of keywords, keybinds and paths to give my org-agenda more power.-(use-package solaire-mode - :custom - (solaire-global-mode +1)) +(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))))))) -(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))-5.3.11. Icons
---This section loads the base icons used in my configuration. I am using
- +nerd-icons
overall-the-icons
since the former seems to have more integrations with different packages than the latter. -+-4.4.1.3. org capture templates
+-Used in: +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 nerd-icons) +(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) + )) +)-5.3.12. Variable Pitch Mode
-++-4.4.1.4. Font Faces
+-This minor mode allows mixing fixed and variable pitch fonts within the same buffer. +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 mixed-pitch - :custom - (mixed-pitch-set-height nil) - (mixed-pitch-variable-pitch-cursor nil) - :hook - (text-mode . mixed-pitch-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)) +-5.3.13. Modeline
---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. -+-4.4.1.5. org-appear
+-I have currently disabled this in favor of mini-modeline. +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 doom-modeline +(use-package org-appear + :hook (org-mode . org-appear-mode) :init - ;; (doom-modeline-mode) - ;; (column-number-mode) - :custom - ((doom-modeline-height 22) - (doom-modeline-indent-info nil) - (doom-modeline-buffer-encoding nil))) - + (setq org-appear-autolinks t) + (setq org-appear-autokeywords t) + (setq org-appear-autoentities t) + (setq org-appear-autosubmarkers t))-5.3.14. mini-modeline
-++-4.4.1.6. Centered org-mode Buffers
+-I have found that the doom-modeline, while very useful, consumes too much screen space for my liking. This modeline takes a more minimalistic approach. +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 mini-modeline - :after smart-mode-line - :config - (mini-modeline-mode t) - (setq mini-modeline-display-gui-line nil) - (setq mini-modeline-enhance-visual nil) - (setq mini-modeline-truncate-p nil) - (setq mini-modeline-l-format nil) - (setq mini-modeline-right-padding 5) - (setq window-divider-mode t) - (setq window-divider-default-places t) - (setq window-divider-default-bottom-width 1) - (setq window-divider-default-right-width 1) - (setq mini-modeline-r-format '("%e" mode-line-front-space mode-line-mule-info mode-line-client - mode-line-modified mode-line-remote mode-line-frame-identification - mode-line-buffer-identification " " mode-line-position " " mode-name evil-mode-line-tag )) - ) - -(use-package smart-mode-line - :config - (sml/setup) - (add-to-list 'sml/replacer-regexp-list '("^~/Documents/Work/" ":WK:")) - (add-to-list 'sml/replacer-regexp-list '("^~/Documents/Private/" ":PR:")) - (add-to-list 'sml/replacer-regexp-list '("^~/.dotfiles/" ":D:") t) - ) - +(use-package visual-fill-column + :hook (org-mode . swarsel/org-mode-visual-fill))-5.3.15. Helper Modes
----5.3.15.1. Vertico, Orderless, Marginalia, Consult, Embark
-++4.4.1.7. Fix headings not folding sometimes
+--This set of packages uses the default emacs completion framework and works together to provide a very nice user experience: +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.
--
- -- 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
orconsult-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 -
---5.3.15.1.1. vertico
--(setq read-buffer-completion-ignore-case t - read-file-name-completion-ignore-case t - completion-ignore-case t) +(setq org-fold-core-style 'overlays) -(use-package vertico - :custom - (vertico-scroll-margin 0) - (vertico-count 10) - (vertico-resize t) - (vertico-cycle t) - :init - (vertico-mode) - (vertico-mouse-mode))-5.3.15.1.2. vertico-directory
-++4.4.1.8. Babel
++-This package allows for
+ +Ido
-like directory navigation. +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.
++-4.4.1.8.1. Language Configuration
+++
- This configures the languages that babel recognizes.
+-(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 org-src-preserve-indentation nil) + + (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) + + (setq org-export-with-broken-links 'mark) + (setq org-confirm-babel-evaluate nil)-5.3.15.1.3. orderless
-+-+4.4.1.8.2. old easy structure templates
+++
- +
+org 9.2 changed the way structure templates work. This brings back the old way it worked. +
+-When first installing orderless, I often times faced the problem, that when editing long files and calling
consult-line
, Emacs would hang when changing a search term in the middle (e.g. fromservicse.xserver
toservic.xserver
in order to fix the typo). The below orderless rules have a more strict matching that has a positive impact on performance. +Usage: Type<
, followed by one of the below keywords and pressRET
. The corresponding source block should appear.-(use-package orderless - :config - (orderless-define-completion-style orderless+initialism - (orderless-matching-styles '(orderless-initialism orderless-literal orderless-regexp))) - (setq completion-styles '(orderless) - completion-category-defaults nil - completion-category-overrides - '((file (styles partial-completion orderless+initialism)) - (buffer (styles orderless+initialism)) - (consult-multi (styles orderless+initialism)) - (command (styles orderless+initialism)) - (eglot (styles orderless+initialism)) - (variable (styles orderless+initialism)) - (symbol (styles orderless+initialism))) - orderless-matching-styles '(orderless-literal orderless-regexp))) - +(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"))+-5.3.15.1.4. consult
-++-4.4.1.9. aucTex
+-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 weirdC-M-j
command that I chose forivy-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. +This provides several utilities for LaTeX in Emacs, including many completions and convenience functions for math-mode.-(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))) +(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)-5.3.15.1.5. embark
-++-4.4.1.10. org-download
+-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. +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.-(use-package embark - :bind - (("C-." . embark-act) - ("M-." . embark-dwim) - ("C-h B" . embark-bindings) - ("C-c c" . embark-collect)) +(use-package org-download + :after org + :defer nil :custom - (prefix-help-command #'embark-prefix-help-command) - (embark-quit-after-action '((t . nil))) + (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 - (add-to-list 'display-buffer-alist - '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" - nil - (window-parameters (mode-line-format . none))))) + (require 'org-download))-5.3.15.1.6. embark-consult
-++-4.4.1.11. org-fragtog
+-Provides previews for embark. +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.
-(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)) +(use-package org-fragtog) +(add-hook 'org-mode-hook 'org-fragtog-mode) +(add-hook 'markdown-mode-hook 'org-fragtog-mode) +-5.3.15.1.7. marginalia
-++-4.4.1.12. org-modern
+-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 onmode
-commands based on the current state of the mode. Also, I do not understand all the shorthands used by marginalia yet. +This just makes org-mode a little bit more beautiful, mostly by making thebegin_src
andend_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 marginalia - :after vertico - :init - (marginalia-mode) - (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))) ++(use-package org-modern + :config (setq org-modern-block-name + '((t . t) + ("src" "»" "∥"))) + :hook (org-mode . org-modern-mode))--5.3.15.1.8. nerd-icons-completion
-+-+-4.4.1.13. Presentations
+--As stated above, this simply provides nerd-icons to the completion framework. +Recently I have grown fond of holding presentations using Emacs :)
--(use-package nerd-icons-completion - :after (marginalia nerd-icons) - :hook (marginalia-mode . nerd-icons-completion-marginalia-setup) - :init - (nerd-icons-completion-mode)) +(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) + ) + +(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) + )) ---5.3.15.2. Helpful + which-key: Better help defaults
---This pair of packages provides information on keybinds in addition to function names, which makes it easier to remember keybinds (
+(defun clojure-leave-clojure-mode-function () + ) -which-key
). Thehelpful
package provides a betterHelp
framework for Emacs. For some reason, the Help windows are always being focused by the cursor even though I have sethelp-window-select
to nil. I do not understand why. ---(use-package which-key - :init (which-key-mode) - :diminish which-key-mode - :config - (setq which-key-idle-delay 0.3)) +(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 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))-5.3.16. Ligatures
-++-4.4.2. Nix Mode
+-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 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.
-(use-package ligature - :init - (global-ligature-mode t) - :config - (ligature-set-ligatures 'prog-mode - '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>" - ":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!==" - "!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<" - "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->" - "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<" - "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~=" - "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|" - "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:" - ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:" - "<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!" - "##" "#(" "#?" "#_" "%%" ".=" ".." ".?" "+>" "++" "?:" "?=" - "?." "??" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)" "\\\\" - "://" ";;"))) +(use-package nix-mode) +(use-package nix-ts-mode + :mode "\\.nix\\'")-5.3.17. 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 (withshackle
) 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. -+-4.4.3. HCL Mode
+-
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 adds support for Hashicorp Configuration Language. I need this at work.-(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 +(use-package hcl-mode + :mode "\\.hcl\\'" :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)) + (setq hcl-indent-level 2))-5.3.18. Indicate first and last line of buffer
-+-+-4.4.4. Jenkinsfile/Groovy
+--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 adds support for Groovy, which I specifically need to work with Jenkinsfiles. I need this at work.
--(setq-default indicate-buffer-boundaries t) - ----5.3.19. Authentication
---This defines the authentication sources used by
+(use-package groovy-mode) -org-calfw
(Calendar) and Forge. ---;; (setq auth-sources '( "~/.emacs.d/.caldav" "~/.emacs.d/.authinfo.gpg") - ;; auth-source-cache-expiry nil) ; default is 2h +(use-package jenkinsfile-mode + :mode "Jenkinsfile") -(setq auth-sources '( "~/.emacs.d/.authinfo") - auth-source-cache-expiry nil)-5.4. Modules
----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. -
--5.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. -
- --Note that nearly all headings within the
-Org-mode
heading are coded within theuse-package
setup, so be very careful about moving stuff about here. --5.4.1.1. General org-mode
-++-4.4.5. Dockerfile
+-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 adds support for Dockerfiles. I need this at work.
-(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-export-headline-levels 6) - (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 dockerfile-mode + :mode "Dockerfile")-5.4.1.2. org-agenda
---Here I setup a plethora of keywords, keybinds and paths to give my org-agenda more power. -
- ---(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))))))) ++-4.4.6. Terraform Mode
+++This adds support for Terraform configuration files. I need this at work. +
+ +++(use-package terraform-mode + :mode "\\.tf\\'" + :config + (setq terraform-indent-level 2) + (setq terraform-format-on-save t)) +(add-hook 'terraform-mode-hook #'outline-minor-mode)-5.4.1.3. org capture templates
-++-4.4.7. nixpkgs-fmt
+-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. +Adds functions for formatting nix code.
-(setq org-capture-templates - `( - ("a" "Anki basic" - entry - (file+headline swarsel-org-anki-filepath "Dispatch") - (function swarsel-anki-make-template-string)) +(use-package nixpkgs-fmt) - ("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) - )) -)-5.4.1.4. Font Faces
-+++4.4.8. shfmt
++-Again, my understanding of the font-faces in Emacs is limited. This is mostly just tuned so that my org-files look acceptable. +Adds functions for formatting shellscripts.
++(use-package shfmt + :config + (setq shfmt-command "shfmt") + (setq shfmt-arguments '("-i" "4" "-s" "-sr"))) +++4.4.9. Markdown Mode
+++++4.4.9.1. Mode
++++++(setq markdown-command "pandoc") -;; 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))) +(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))) - ;; 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)) +++-4.4.9.2. 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) + ))-5.4.1.5. org-appear
-+++-4.4.10. 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))-5.4.1.6. 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.11. elfeed
+++