aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2019-10-05 22:09:49 +0000
committerKatharina Fey <kookie@spacekookie.de>2019-10-05 22:09:49 +0000
commitc04d9504fa2ae8f447ef05a1e7ddb3b21ed06af9 (patch)
tree4dcadc971cabf2f96f5ef832a5664ae31c052051
parent0a6d1447db7d1f52517a4a4c47d4198451fd223e (diff)
Adding workstation module
-rw-r--r--modules/workstation/chat/default.nix15
-rw-r--r--modules/workstation/default.nix34
-rw-r--r--modules/workstation/devel/default.nix8
-rw-r--r--modules/workstation/devel/java/default.nix7
-rw-r--r--modules/workstation/devel/java/gdx.nix32
-rw-r--r--modules/workstation/devel/java/lwjgl.nix33
-rw-r--r--modules/workstation/devel/rust.nix5
-rw-r--r--modules/workstation/emacs/default.nix41
-rw-r--r--modules/workstation/emacs/init.el85
-rw-r--r--modules/workstation/git/default.nix9
-rw-r--r--modules/workstation/graphics/browser.nix5
-rw-r--r--modules/workstation/graphics/default.nix31
-rw-r--r--modules/workstation/graphics/fonts.nix10
-rw-r--r--modules/workstation/graphics/fun.nix8
-rw-r--r--modules/workstation/graphics/i3/compton.conf20
-rw-r--r--modules/workstation/graphics/i3/config.nix166
-rw-r--r--modules/workstation/graphics/i3/default.nix22
-rwxr-xr-xmodules/workstation/graphics/i3/dynamic-tags/move.sh13
-rwxr-xr-xmodules/workstation/graphics/i3/dynamic-tags/switch.sh9
-rw-r--r--modules/workstation/graphics/i3/i3status.conf47
-rw-r--r--modules/workstation/graphics/i3/locker25
-rw-r--r--modules/workstation/hardware/ckb/default.nix10
-rw-r--r--modules/workstation/hardware/default.nix16
-rw-r--r--modules/workstation/hardware/xkblayout/default.nix16
-rw-r--r--modules/workstation/hardware/yubikey/default.nix14
-rw-r--r--modules/workstation/input/trackpoint.nix17
-rw-r--r--modules/workstation/kitty/default.nix7
-rw-r--r--modules/workstation/kitty/kitty.conf52
-rw-r--r--modules/workstation/mail/default.nix9
-rw-r--r--modules/workstation/mail/pkgs.nix16
-rw-r--r--modules/workstation/mail/timer.nix41
-rw-r--r--modules/workstation/networking/default.nix14
-rw-r--r--modules/workstation/pass/default.nix1
-rw-r--r--modules/workstation/printing/default.nix9
-rw-r--r--modules/workstation/redshift/default.nix7
-rw-r--r--modules/workstation/sound/default.nix5
-rw-r--r--modules/workstation/syncthing/default.nix10
37 files changed, 869 insertions, 0 deletions
diff --git a/modules/workstation/chat/default.nix b/modules/workstation/chat/default.nix
new file mode 100644
index 00000000000..5d1a7214d1d
--- /dev/null
+++ b/modules/workstation/chat/default.nix
@@ -0,0 +1,15 @@
+/* REAL-TIME COMMUNICATION CLIENTS
+ *
+ * A bit of a mix of applications and no real configuration
+ */
+
+{ pkgs, ... }:
+
+{
+ home.packages = with pkgs; [
+ dino
+ quasselClient
+ signal-desktop
+ weechat
+ ];
+}
diff --git a/modules/workstation/default.nix b/modules/workstation/default.nix
new file mode 100644
index 00000000000..2b9543dc5f5
--- /dev/null
+++ b/modules/workstation/default.nix
@@ -0,0 +1,34 @@
+/* GENERAL WORKSTATION CONFIGURATION
+ *
+ * A workstation is a computer with it's own screen,
+ * keyboard and (sometimes) mouse. It can also sometimes
+ * play music or print (provided the correct satanic
+ * sacrifice was precured first).
+ *
+ * Some of the modules included by this file depend on
+ * root access on a system (nixos-rebuild), while some
+ * can be operated entirely in userspace.
+ */
+
+{ pkgs, home-manager, ... }:
+
+{
+ home-manager.users.spacekookie = { ... }: {
+ imports = [
+ ./chat
+ ./devel
+ ./emacs
+ ./git
+ ./pass
+ ];
+ };
+
+ imports = [
+ ./graphics
+ ./hardware
+ ./mail
+ ./networking
+ ./sound
+ ./syncthing
+ ];
+}
diff --git a/modules/workstation/devel/default.nix b/modules/workstation/devel/default.nix
new file mode 100644
index 00000000000..cfbdd05d421
--- /dev/null
+++ b/modules/workstation/devel/default.nix
@@ -0,0 +1,8 @@
+{ ... }:
+
+{
+ imports = [
+ ./java
+ ./rust.nix
+ ];
+}
diff --git a/modules/workstation/devel/java/default.nix b/modules/workstation/devel/java/default.nix
new file mode 100644
index 00000000000..aa2cf8d7264
--- /dev/null
+++ b/modules/workstation/devel/java/default.nix
@@ -0,0 +1,7 @@
+/* JAVA DEVELOPMENT MODE
+ *
+ * FIXME: Integrate building libgdx/ lwjgl with nix
+ */
+{ pkgs, ... }: {
+ home.packages = with pkgs; [ eclipses.eclipse-java lombok ];
+}
diff --git a/modules/workstation/devel/java/gdx.nix b/modules/workstation/devel/java/gdx.nix
new file mode 100644
index 00000000000..2e1649fb2a9
--- /dev/null
+++ b/modules/workstation/devel/java/gdx.nix
@@ -0,0 +1,32 @@
+{ stdenv, pkgs, ... }:
+
+with pkgs;
+stdenv.mkDerivation rec {
+ name = "libgdx-${version}";
+ version = "1.9.6";
+
+ src = fetchurl {
+ url = "https://github.com/libgdx/libgdx/archive/${version}.tar.gz";
+ sha256 = "1lxky0cz4qjpw4x06cf2kpa00cj0n0jp3vfsp67jy1d42dqyshgb";
+ };
+
+ buildInputs = [ ant openjdk gcc ];
+
+ buildPhase = "find . -name '*.so' -delete && cd gdx/jni && ant -f build-linux64.xml && cd ../../extensions/gdx-box2d/gdx-box2d/jni && ant -f build-linux64.xml && cd ../../../../";
+
+ installPhase = ''
+ mkdir -p $out/lib
+ cp gdx/libs/linux64/*.so $out/lib
+ cp extensions/gdx-box2d/gdx-box2d/libs/linux64/*.so $out/lib
+ '';
+
+ meta = with stdenv.lib; {
+ description = "Desktop/Android/BlackBerry/iOS/HTML5 Java game development framework";
+ longDescription = '''';
+ homepage = http://libgdx.badlogicgames.com/;
+ license = licenses.asl20;
+ maintainers = with maintainers; [ pmiddend ];
+ platforms = platforms.linux;
+ };
+}
+
diff --git a/modules/workstation/devel/java/lwjgl.nix b/modules/workstation/devel/java/lwjgl.nix
new file mode 100644
index 00000000000..77ab765f207
--- /dev/null
+++ b/modules/workstation/devel/java/lwjgl.nix
@@ -0,0 +1,33 @@
+{ stdenv, pkgs, ... }:
+
+with pkgs;
+stdenv.mkDerivation rec {
+ name = "lwjgl-${version}";
+ version = "2.9.2";
+
+ src = fetchurl {
+ url = "https://github.com/LWJGL/lwjgl/archive/lwjgl${version}.tar.gz";
+ sha256 = "1m396ply3kspym3r00s1rbk77irn2f9vgr76xsy7272k649y3wky";
+ };
+
+ buildInputs = with xorg; [ ant openjdk gcc libX11 libXt libXcursor
+ libXxf86vm libXrandr libXext ];
+
+ buildPhase = "mkdir -p bin && ant generate-all && ant compile && ant compile_native";
+
+ installPhase = ''
+ mkdir -p $out/lib
+ cp bin/lwjgl/*.so $out/lib
+ '';
+
+ meta = with stdenv.lib; {
+ description = "The Lightweight Java Game Library";
+ longDescription = ''
+ LWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL), audio (OpenAL) and parallel computing (OpenCL) applications. This access is direct and high-performance, yet also wrapped in a type-safe and user-friendly layer, appropriate for the Java ecosystem.
+ '';
+ homepage = http://legacy.lwjgl.org/;
+ license = licenses.bsd3;
+ maintainers = with maintainers; [ pmiddend ];
+ platforms = platforms.linux;
+ };
+}
diff --git a/modules/workstation/devel/rust.nix b/modules/workstation/devel/rust.nix
new file mode 100644
index 00000000000..99758059973
--- /dev/null
+++ b/modules/workstation/devel/rust.nix
@@ -0,0 +1,5 @@
+{ pkgs, ... }:
+
+{
+ home.packages = with pkgs; [ rustup ];
+}
diff --git a/modules/workstation/emacs/default.nix b/modules/workstation/emacs/default.nix
new file mode 100644
index 00000000000..edcf067ae76
--- /dev/null
+++ b/modules/workstation/emacs/default.nix
@@ -0,0 +1,41 @@
+{ pkgs, ... }:
+
+let
+ package = with pkgs; emacsWithPackages (epkgs:
+ (with epkgs; [
+ (runCommand "init.el" {} ''
+ mkdir -p $out/share/emacs/site-lisp
+ cp ${./init.el} $out/share/emacs/site-lisp/default.el
+ '')
+
+ # Custom patched mode
+ pkgs.emacs-ergoemacs-mode
+
+ # Language support
+ fish-mode
+ lsp-mode
+ markdown-mode
+ nim-mode
+ nix-mode
+ python-mode
+ rust-mode
+
+ # Some general improvements
+ company
+ company-lsp
+ color-theme-sanityinc-tomorrow
+ fzf
+ ledger-mode
+ lsp-ui
+ magit
+ notmuch
+ org
+ smex
+ sublimity
+ visual-fill-column
+ yasnippet
+ ]));
+in
+{
+ home.packages = [ package ];
+}
diff --git a/modules/workstation/emacs/init.el b/modules/workstation/emacs/init.el
new file mode 100644
index 00000000000..301ce00a0df
--- /dev/null
+++ b/modules/workstation/emacs/init.el
@@ -0,0 +1,85 @@
+;; Kookie's emacs config
+
+;; More sane line-number behaviour
+(setq display-line-numbers-grow-only 1)
+(setq display-line-numbers-width-start 1)
+(global-display-line-numbers-mode 1)
+
+;; I just need my personal space
+(setq tab-width 2)
+(setq-default indent-tabs-mode nil)
+(defvaralias 'c-basic-offset 'tab-width)
+(defvaralias 'cperl-indent-level 'tab-width)
+
+;;disable splash screen and startup message
+(setq inhibit-startup-message 1)
+(setq initial-scratch-message nil)
+
+;; Swap/Backup files are annoying AF
+(setq make-backup-files nil)
+(setq auto-save-default nil)
+
+;; Some editing niceties
+(delete-selection-mode 1)
+(show-paren-mode 1)
+
+;; Explicitly enable lsp-mode for certain languages
+(add-hook 'rust-mode-hook #'lsp)
+(add-hook 'c-mode-hook #'lsp)
+(add-hook 'c++-mode-hook #'lsp)
+
+(menu-bar-mode -1)
+(tool-bar-mode -1)
+(scroll-bar-mode -1)
+
+(add-hook 'java-mode-hook (local-unset-key "M-a"))
+;; (add-hook 'prog-mode-hook (local-unset-key "M-a"))
+
+(column-number-mode 1)
+(ido-mode 1)
+(add-hook 'find-file-hook (lambda () (ruler-mode 1)))
+
+(require 'color-theme-sanityinc-tomorrow)
+(load-theme 'sanityinc-tomorrow-eighties)
+
+;; More ergonomic keybindings
+(require 'ergoemacs-mode)
+(setq ergoemacs-theme nil)
+(setq ergoemacs-keyboard-layout "us")
+(ergoemacs-mode 1)
+
+;; VTerm integration
+(require 'vterm)
+
+;; Distraction free mode and minimap
+(require 'sublimity)
+(require 'sublimity-map)
+(require 'sublimity-attractive)
+
+(setq sublimity-map-size 10)
+(setq sublimity-map-fraction 0.5)
+(setq sublimity-map-text-scale -7)
+
+;; Display minimap without delay
+(sublimity-map-set-delay nil)
+
+;; This is require for lsp-mode
+(require 'yasnippet)
+
+;; Better completion handling with lsp-mode
+(require 'company-lsp)
+(push 'company-lsp company-backends)
+(setq lsp-ui-doc-max-width 45)
+(setq lsp-ui-doc-max-height 10)
+
+;; Turns out I'm a huge dork
+(setq emacs-anchor default-directory)
+(defun mitosis () (interactive) (make-frame))
+
+;; Setup RSS feeds
+(setq elfeed-feeds
+ '(("https://alyssa.is/feed.xml" girlfriend blog)
+ ("https://spacekookie.de/rss.xml" self blog)
+ ("https://xkcd.com/rss.xml" webcomic)
+ ("https://deterministic.space/feed.xml" rust blog)
+ ))
diff --git a/modules/workstation/git/default.nix b/modules/workstation/git/default.nix
new file mode 100644
index 00000000000..c5a6d854850
--- /dev/null
+++ b/modules/workstation/git/default.nix
@@ -0,0 +1,9 @@
+{ pkgs, ... }:
+
+let
+ git = (pkgs.git.override { svnSupport = true; sendEmailSupport = true; });
+in
+{
+ home.packages = [ git ]
+ ++ (with pkgs; [ gitAndTools.hub ]);
+}
diff --git a/modules/workstation/graphics/browser.nix b/modules/workstation/graphics/browser.nix
new file mode 100644
index 00000000000..8fc60dd03df
--- /dev/null
+++ b/modules/workstation/graphics/browser.nix
@@ -0,0 +1,5 @@
+{ pkgs, ... }:
+
+{
+ home.packages = [ pkgs.firefox ];
+}
diff --git a/modules/workstation/graphics/default.nix b/modules/workstation/graphics/default.nix
new file mode 100644
index 00000000000..5f902759d8f
--- /dev/null
+++ b/modules/workstation/graphics/default.nix
@@ -0,0 +1,31 @@
+{ pkgs, ... }:
+
+{
+ services.xserver = {
+ enable = true;
+ desktopManager = {
+ default = "xfce";
+ xfce = {
+ enable = true;
+ noDesktop = true;
+ enableXfwm = false;
+ };
+ };
+ windowManager.i3.enable = true;
+
+ videoDrivers = [ "intel" ];
+ deviceSection = ''
+ Option "DRI" "2"
+ Option "TearFree" "true"
+ '';
+ useGlamor = true;
+ };
+
+ home-manager.users.spacekookie = { ... }: {
+ imports = [
+ ./i3
+ ./browser.nix
+ ./fun.nix
+ ];
+ };
+}
diff --git a/modules/workstation/graphics/fonts.nix b/modules/workstation/graphics/fonts.nix
new file mode 100644
index 00000000000..a754da54b43
--- /dev/null
+++ b/modules/workstation/graphics/fonts.nix
@@ -0,0 +1,10 @@
+{ pkgs, ... }:
+
+{
+ fonts.fonts = with pkgs; [
+ google-fonts
+ inconsolata
+ iosevka
+ twemoji-color-font
+ ];
+}
diff --git a/modules/workstation/graphics/fun.nix b/modules/workstation/graphics/fun.nix
new file mode 100644
index 00000000000..56a6b4c0aef
--- /dev/null
+++ b/modules/workstation/graphics/fun.nix
@@ -0,0 +1,8 @@
+{ pkgs, ... }:
+
+{
+ home.packages = with pkgs; [
+ spotify
+ steam
+ ];
+}
diff --git a/modules/workstation/graphics/i3/compton.conf b/modules/workstation/graphics/i3/compton.conf
new file mode 100644
index 00000000000..a632c022593
--- /dev/null
+++ b/modules/workstation/graphics/i3/compton.conf
@@ -0,0 +1,20 @@
+unredir-if-possible = false;
+vsync = "opengl";
+
+### Opacity
+menu-opacity = 0.90;
+frame-opacity = 0.90; # i.e. titlebars, borders
+inactive-opacity-override = false;
+alpha-step = 0.06;
+
+### Blur options
+blur-background = true;
+blur-background-frame = true;
+# blur-kern = "3x3box"
+# blur-kern = "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"
+# blur-background-fixed = true;
+blur-background-exclude = [ "window_type = 'dock'", "window_type = 'desktop'" ];
+
+# # Detect rounded corners and treat them as rectangular when --shadow-ignore-shaped is on.
+detect-rounded-corners = true;
+detect-client-opacity = true
diff --git a/modules/workstation/graphics/i3/config.nix b/modules/workstation/graphics/i3/config.nix
new file mode 100644
index 00000000000..746c2a47698
--- /dev/null
+++ b/modules/workstation/graphics/i3/config.nix
@@ -0,0 +1,166 @@
+{ pkgs, wallpaper }:
+
+{
+ enable = true;
+ package = pkgs.i3;
+ config = rec {
+ modifier = "Mod4";
+
+ # Use iosevka as default font
+ fonts = [ "iosevka-term-ss09 10" ];
+
+ keybindings = {
+
+ # Start a terminal
+ "${modifier}+Return" = "exec kitty";
+
+ # Close individual windows
+ "${modifier}+Shift+q" = "kill";
+
+ # Full-screen window
+ "${modifier}+f" = "fullscreen";
+
+ # Start software on <this> or <other> workspace
+ "${modifier}+d" = "exec dmenu_run";
+ "${modifier}+Shift+d" = "exec ~/.config/i3/dynamic-tags/move.sh";
+
+ # Move focus around - vim style
+ "${modifier}+h" = "focus left";
+ "${modifier}+j" = "focus down";
+ "${modifier}+k" = "focus up";
+ "${modifier}+l" = "focus right";
+
+ # Move focus around - boring style
+ "${modifier}+Up" = "focus up";
+ "${modifier}+Down" = "focus down";
+ "${modifier}+Left" = "focus left";
+ "${modifier}+Right" = "focus right";
+
+ # Move windows - vim style
+ "${modifier}+Shift+k" = "move up";
+ "${modifier}+Shift+j" = "move down";
+ "${modifier}+Shift+h" = "move left";
+ "${modifier}+Shift+l" = "move right";
+
+ # Move windows - boring style
+ "${modifier}+Shift+Up" = "move up";
+ "${modifier}+Shift+Down" = "move down";
+ "${modifier}+Shift+Left" = "move left";
+ "${modifier}+Shift+Right" = "move right";
+
+ # Move workspaces between multi-monitor setups
+ "${modifier}+Ctrl+Shift+Up" = "move workspace to output up";
+ "${modifier}+Ctrl+Shift+Down" = "move workspace to output down";
+ "${modifier}+Ctrl+Shift+Left" = " move workspace to output left";
+ "${modifier}+Ctrl+Shift+Right" = "move workspace to output right";
+
+ # Define split behaviours
+ "${modifier}+2" = "split h";
+ "${modifier}+1" = "split v";
+
+ # A very fortunate lockscreen
+ "${modifier}+Ctrl+l" = "exec --no-startup-id i3lock -c 333333";
+ "${modifier}+Ctrl+Shift+l" = "exec --no-startup-id systemctl hibernate";
+
+ # Rename workspaces
+ "${modifier}+Ctrl+r" = "exec i3-input -F 'rename workspace to \"%s\"' -P 'New name: '";
+
+ # Switch to workspace (optionally dragging windows with)
+ "${modifier}+s" = "exec ~/.config/i3/dynamic-tags/switch.sh -fn '$dfont'";
+ "${modifier}+Shift+s" = "exec ~/.config/i3/dynamic-tags/move.sh -fn '$dfont'";
+
+ # Some layout modifiers
+ "${modifier}+e" = "layout default";
+ "${modifier}+w" = "layout tabbed";
+ "${modifier}+q" = "layout stacked";
+
+ # Do I even use this?!
+ "${modifier}+Shift+space" = "floating toggle";
+ "${modifier}+space" = "focus mode_toggle";
+
+ # Focus the parent containers
+ "${modifier}+a" = "focus parent";
+
+ # Audio is good actually
+ "XF86AudioRaiseVolume" = "exec --no-startup-id pactl set-sink-volume 0 +5%";
+ "XF86AudioLowerVolume" = "exec --no-startup-id pactl set-sink-volume 0 -5%";
+ "XF86AudioMute" = "exec --no-startup-id pactl set-sink-mute 0 toggle";
+
+ # Reload, restart and quit i3
+ "${modifier}+Shift+c" = "reload";
+ "${modifier}+Shift+r" = "restart";
+ "${modifier}+Shift+e" = ''
+ exec i3-nagbar -t warning -m "Workspaces are sentient, you know. \
+ We just have a lot of them" "i3-msg exit"
+ '';
+
+ # Switch to resize mode (defined below)
+ "${modifier}+r" = "mode \"resize\"";
+
+ # FIXME: What was this again?!
+ "button4" = "nop";
+ "button5" = "nop";
+ };
+
+ modes = {
+
+ # Explicitly handle the resize mode
+ resize = {
+ "h" = "resize shrink width 5 px or 5 ppt";
+ "j" = "resize grow height 5 px or 5 ppt";
+ "k" = "resize shrink height 5 px or 5 ppt";
+ "l" = "resize grow width 5 px or 5 ppt";
+
+ # same bindings, but for the arrow keys
+ "Left" = "resize shrink width 5 px or 5 ppt";
+ "Down" = "resize grow height 5 px or 5 ppt";
+ "Up" = "resize shrink height 5 px or 5 ppt";
+ "Right" = "resize grow width 5 px or 5 ppt";
+
+ # back to normal: Enter or Escape or $mod+r
+ "Return" = "mode \"default\"";
+ "Escape" = "mode \"default\"";
+ "${modifier}+r" = "mode \"default\"";
+ } ;
+ };
+
+ # The `bars` module does weird stuff so we init it ourselves
+ bars = [];
+ };
+
+ extraConfig = with pkgs; ''
+ # Compton
+ exec_always --no-startup-id "pkill compton; ${compton}/bin/compton \
+ --config ~/.config/i3/compton.conf"
+
+ # Make CAPSLOCK into ESC because it's 2018
+ #
+ # Okay actually this is slightly more complicated than that. Actually I'm
+ # binding CAPSLOCK to HYPER, so that I can use it as a modifier in emacs,
+ # but then using xcape(1) to also make short CAPSLOCK presses into ESCAPE.
+
+ exec_always --no-startup-id "${xorg.xmodmap}/bin/setxkbmap \
+ -layout us -variant altgr-intl -option caps:hyper"
+ exec ${xcape}/bin/xcape -e "#66=Escape" -t 150
+
+ # Always set a wallpaper
+ exec_always --no-startup-id ${feh}/bin/feh --bg-fill ${wallpaper}
+
+ bar {
+ status_command i3status -c ~/.config/i3/i3status.conf
+ position bottom
+ bindsym button4 nop
+ bindsym button5 nop
+ colors {
+ background #0F0F0F
+ statusline #D5D5D5
+ }k
+ }
+
+ focus_follows_mouse no
+
+ # Layout and design settings that should _really_ be in the module
+ default_border pixel 3
+ client.focused #4c7899 #285577 #ffffff #F73E5F #666666
+ '';
+}
diff --git a/modules/workstation/graphics/i3/default.nix b/modules/workstation/graphics/i3/default.nix
new file mode 100644
index 00000000000..251b04ec202
--- /dev/null
+++ b/modules/workstation/graphics/i3/default.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+let
+ wallpaper = "~/pictures/wallpaper/my-cyber-city-4k-28-2560x1440.jpg";
+in
+{
+ xsession.windowManager.i3 = import ./config.nix { inherit pkgs wallpaper; };
+
+ xdg.configFile."i3/dynamic-tags/" = {
+ recursive = true;
+ executable = true;
+ source = ./dynamic-tags;
+ };
+
+ xdg.configFile."i3/compton.conf" = {
+ source = ./compton.conf;
+ };
+
+ xdg.configFile."i3/i3status.conf" = {
+ source = ./i3status.conf;
+ };
+}
diff --git a/modules/workstation/graphics/i3/dynamic-tags/move.sh b/modules/workstation/graphics/i3/dynamic-tags/move.sh
new file mode 100755
index 00000000000..84f39fdc3ac
--- /dev/null
+++ b/modules/workstation/graphics/i3/dynamic-tags/move.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+### Move a window to a given workspace. If it doesn't exist it creates it.
+
+I3MSG=$(command -v i3-msg) || exit 1
+JQ=$(command -v jq) || exit 2
+
+WORKSPACE=$($I3MSG -t get_workspaces | $JQ -M '.[] | .name' | tr -d '"' | sort -u | dmenu -b -i "$@")
+
+# Move the window first
+$I3MSG -t command move workspace $WORKSPACE
+
+# Then move the user
+$I3MSG workspace $WORKSPACE
diff --git a/modules/workstation/graphics/i3/dynamic-tags/switch.sh b/modules/workstation/graphics/i3/dynamic-tags/switch.sh
new file mode 100755
index 00000000000..9c50eb48083
--- /dev/null
+++ b/modules/workstation/graphics/i3/dynamic-tags/switch.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+### Move the focus to a particular workspace using dmenu.
+
+set -u
+
+I3MSG=$(command -v i3-msg) || exit 1
+JQ=$(command -v jq) || exit 2
+
+$I3MSG workspace $($I3MSG -t get_workspaces | $JQ -M '.[] | .name' | tr -d '"' | sort -u | dmenu -b -i "$@")
diff --git a/modules/workstation/graphics/i3/i3status.conf b/modules/workstation/graphics/i3/i3status.conf
new file mode 100644
index 00000000000..fb36d20e7a0
--- /dev/null
+++ b/modules/workstation/graphics/i3/i3status.conf
@@ -0,0 +1,47 @@
+# i3status configuration file.
+# see "man i3status" for documentation.
+
+# It is important that this file is edited as UTF-8.
+# The following line should contain a sharp s:
+# ß
+# If the above line is not correctly displayed, fix your editor first!
+
+general {
+ colors = true
+ interval = 5
+}
+
+order += "ipv6"
+order += "disk /"
+order += "wireless _first_"
+order += "ethernet _first_"
+order += "battery all"
+order += "load"
+order += "tztime local"
+
+wireless _first_ {
+ format_up = "W: (%quality at %essid) %ip"
+ format_down = "W: <down>"
+}
+
+ethernet _first_ {
+ # if you use %speed, i3status requires root privileges
+ format_up = "E: %ip (%speed)"
+ format_down = "E: <down>"
+}
+
+battery all {
+ format = "%status %percentage"
+}
+
+tztime local {
+ format = "%Y-%m-%d %H:%M:%S"
+}
+
+load {
+ format = "%1min"
+}
+
+disk "/" {
+ format = "%avail"
+}
diff --git a/modules/workstation/graphics/i3/locker b/modules/workstation/graphics/i3/locker
new file mode 100644
index 00000000000..af64e74eb6b
--- /dev/null
+++ b/modules/workstation/graphics/i3/locker
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+BASEDIR="/tmp/i3lock"
+ICON="/usr/share/i3lock-fancy/icons/lock.png"
+IMAGE="$BASEDIR/lock.png"
+FORTUNE=$(fortune | sed -e 's/\t/ /g')
+TMP_RES=$(xrandr | grep \* | cut -d' ' -f4 | sed ':a;N;$!ba;s/\n/ /g')
+RESOLUTION=(`echo $TMP_RES | sed 's/ /\n/g'`)
+
+mkdir -p "$BASEDIR"
+convert -size 0x0 canvas:black "$IMAGE"
+
+for monitor in "${RESOLUTION[@]}"
+do
+ echo "Running for monitor $monitor"
+ TMPLOCK="/tmp/i3lock/tmplock.png"
+ convert -size "$monitor" canvas:black -font Inconsolata -pointsize 18 \
+ -fill white -gravity center -annotate +0+250 "$FORTUNE" \
+ "$ICON" -gravity center -composite "$TMPLOCK"
+ convert "$IMAGE" "$TMPLOCK" +append "$IMAGE"
+ rm "$TMPLOCK"
+done
+
+i3lock -i "$IMAGE"
+
diff --git a/modules/workstation/hardware/ckb/default.nix b/modules/workstation/hardware/ckb/default.nix
new file mode 100644
index 00000000000..88d8592d48a
--- /dev/null
+++ b/modules/workstation/hardware/ckb/default.nix
@@ -0,0 +1,10 @@
+/* CORSAIR KEYBOARD SUPPORT
+ *
+ * Setup the K65 corsair keyboard daemon
+ * with themes properly
+ */
+{ config, ... }:
+
+{
+ (builtins.abort "CKB module not implemented!")
+}
diff --git a/modules/workstation/hardware/default.nix b/modules/workstation/hardware/default.nix
new file mode 100644
index 00000000000..28f684b5906
--- /dev/null
+++ b/modules/workstation/hardware/default.nix
@@ -0,0 +1,16 @@
+/* HARDWARE SUPPORT MODULE
+ *
+ * This module doesn't include ALL submodules because
+ * some are only relevant for specific platforms. Still
+ * the general support should be provided by the
+ * WORKSTATION module, not be bound to be device specific
+ */
+
+{ ... }:
+
+{
+ imports = [
+ ./yubikey
+ ./xkblayout
+ ];
+}
diff --git a/modules/workstation/hardware/xkblayout/default.nix b/modules/workstation/hardware/xkblayout/default.nix
new file mode 100644
index 00000000000..1fa51cc0527
--- /dev/null
+++ b/modules/workstation/hardware/xkblayout/default.nix
@@ -0,0 +1,16 @@
+/* KEYBOARD LAYOUT MODULE
+ *
+ * (INCOMPLETE) Setup keyboard layout
+ * and overrides. Currently this is
+ * mostly handled by GRAPHICS/I3 but
+ * should maybe be moved here?
+ */
+{ pkgs, config, ... }:
+
+{
+ i18n.consoleUseXkbConfig = true;
+ services.xserver.layout = "us";
+
+ # environment.variables.XKB_DEFAULT_LAYOUT = xcfg.layout;
+ # environment.variables.XKB_DEFAULT_OPTIONS = xcfg.xkbOptions;
+}
diff --git a/modules/workstation/hardware/yubikey/default.nix b/modules/workstation/hardware/yubikey/default.nix
new file mode 100644
index 00000000000..851f9acea39
--- /dev/null
+++ b/modules/workstation/hardware/yubikey/default.nix
@@ -0,0 +1,14 @@
+{ pkgs, ... }:
+
+{
+ services.udev.packages = with pkgs; [ yubikey-personalization ];
+
+ # FIXME: Can I remove these?
+ # Previously these rules were required to make
+ # Yubikey support work on `uwu`, but maybe this
+ # is redundant with special udev rules?
+ environment.systemPackages = with pkgs; [
+ yubikey-manager
+ yubikey-personalization
+ ];
+}
diff --git a/modules/workstation/input/trackpoint.nix b/modules/workstation/input/trackpoint.nix
new file mode 100644
index 00000000000..e4019d6361d
--- /dev/null
+++ b/modules/workstation/input/trackpoint.nix
@@ -0,0 +1,17 @@
+/* TRACKPOINT INPUT CONFIGURATION
+ *
+ * This is a compatibility module for Thinkpad computers
+ */
+
+{ config, .... }: {
+ services.xserver.libinput = {
+ accelProfile = "flat";
+ accelSpeed = "-0.2";
+ scrollButton = 2;
+ };
+
+ hardware.trackpoint = {
+ enable = true;
+ emulateWheel = true;
+ };
+}
diff --git a/modules/workstation/kitty/default.nix b/modules/workstation/kitty/default.nix
new file mode 100644
index 00000000000..aa7f697b3f8
--- /dev/null
+++ b/modules/workstation/kitty/default.nix
@@ -0,0 +1,7 @@
+{ pkgs, ... }: {
+ home.packages = [ pkgs.kitty ];
+
+ xdg.configFile."kitty/kitty.conf" = {
+ source = ./kitty.conf;
+ };
+}
diff --git a/modules/workstation/kitty/kitty.conf b/modules/workstation/kitty/kitty.conf
new file mode 100644
index 00000000000..ab8c6a059f7
--- /dev/null
+++ b/modules/workstation/kitty/kitty.conf
@@ -0,0 +1,52 @@
+font_size 10
+font_familt twemoji-color-font
+
+open_url_modifiers ctrl+shift
+open_url_with default
+
+term xterm-256color
+
+background_opacity 0.85
+
+selection_foreground #93a1a1
+selection_background #073642
+active_border_color #00ff00
+inactive_border_color #cccccc
+cursor #ffffff
+cursor_shape block
+
+foreground #c5c8c6
+background #1d1f21
+
+# black
+color0 #1d1f21
+color8 #969896
+
+# red
+color1 #cc6666
+color9 #cc6666
+
+# green
+color2 #b5bd68
+color10 #b5bd68
+
+# yellow
+color3 #f0c674
+color11 #f0c674
+
+# blue
+color4 #81a2be
+color12 #81a2be
+
+# magenta
+color5 #b294bb
+color13 #b294bb
+
+# cyan
+color6 #8abeb7
+color14 #8abeb7
+
+# white
+color7 #c5c8c6
+color15 #ffffff
+
diff --git a/modules/workstation/mail/default.nix b/modules/workstation/mail/default.nix
new file mode 100644
index 00000000000..eda0ecf609c
--- /dev/null
+++ b/modules/workstation/mail/default.nix
@@ -0,0 +1,9 @@
+{ pkgs, ... }:
+
+{
+ home-manager.users.spacekookie = { ... }: {
+ imports = [ ./pkgs.nix ];
+ };
+
+ imports = [ ./timer.nix ];
+}
diff --git a/modules/workstation/mail/pkgs.nix b/modules/workstation/mail/pkgs.nix
new file mode 100644
index 00000000000..380e1b530a6
--- /dev/null
+++ b/modules/workstation/mail/pkgs.nix
@@ -0,0 +1,16 @@
+/* USERSPACE MAIL CONFIGURATION
+ *
+ * This module depends on the `ext` hook in the repo
+ * root, because it includes private config files
+ * that contain sensitive information.
+ */
+
+{ pkgs, ... }:
+
+{
+ home.packages = with pkgs; [ neomutt notmuch ];
+# imports = [
+# ../../../ext/mail/neomutt.nix
+# ../../../ext/mail/notmuch.nix
+# ];
+}
diff --git a/modules/workstation/mail/timer.nix b/modules/workstation/mail/timer.nix
new file mode 100644
index 00000000000..468ae263cd0
--- /dev/null
+++ b/modules/workstation/mail/timer.nix
@@ -0,0 +1,41 @@
+{ pkgs, config, ... }:
+
+{
+ environment.systemPackages = with pkgs; [ isync ];
+
+ systemd.services.isync =
+ let
+ maildir = "${config.users.users.spacekookie.home}/office/mail";
+ mbsyncrc = pkgs.writeText "mbsyncrc"
+ (import ../../../ext/mail/mbsyncrc.nix { inherit maildir; });
+ in with pkgs; {
+ serviceConfig.Type = "oneshot";
+ script = ''
+ ${sudo}/bin/sudo -u spacekookie-mail \
+ ${isync}/bin/mbsync -a -V -c ${mbsyncrc}
+ '';
+ postStart = ''
+ ${findutils}/bin/find \
+ "${maildir}" \
+ \! -name .mbsyncstate* \
+ \( \
+ \( \! -user spacekookie -o \! -group spacekookie \) \
+ -exec ${coreutils}/bin/chown spacekookie:spacekookie '{}' \; \
+ , \
+ -type f \! -perm 660 \
+ -exec ${coreutils}/bin/chmod 0660 '{}' \; \
+ , \
+ -type d \! -perm 770 \
+ -exec ${coreutils}/bin/chmod 0770 '{}' \; \
+ \)
+ '';
+ };
+
+ systemd.timers.isync = {
+ timerConfig.Unit = "isync.service";
+ timerConfig.OnCalendar = "*:0/5";
+ timerConfig.Persistent = "true";
+ after = [ "network-online.target" ];
+ wantedBy = [ "timers.target" ];
+ };
+}
diff --git a/modules/workstation/networking/default.nix b/modules/workstation/networking/default.nix
new file mode 100644
index 00000000000..c90ad9b81fc
--- /dev/null
+++ b/modules/workstation/networking/default.nix
@@ -0,0 +1,14 @@
+{ config, ... }:
+
+{
+ networking = {
+ networkmanager = {
+ enable = true;
+ extraConfig = ''
+ rc-manager="resolvconf";
+ '';
+ };
+
+ firewall.enable = true;
+ };
+}
diff --git a/modules/workstation/pass/default.nix b/modules/workstation/pass/default.nix
new file mode 100644
index 00000000000..c157af788ee
--- /dev/null
+++ b/modules/workstation/pass/default.nix
@@ -0,0 +1 @@
+{ ... }: {}
diff --git a/modules/workstation/printing/default.nix b/modules/workstation/printing/default.nix
new file mode 100644
index 00000000000..72a0c54e893
--- /dev/null
+++ b/modules/workstation/printing/default.nix
@@ -0,0 +1,9 @@
+{ pkgs, ... }:
+
+{
+ services.printing = {
+ enable = true;
+ drivers = [ pkgs.foo2zjs ];
+ };
+}
+
diff --git a/modules/workstation/redshift/default.nix b/modules/workstation/redshift/default.nix
new file mode 100644
index 00000000000..3649b2a38d7
--- /dev/null
+++ b/modules/workstation/redshift/default.nix
@@ -0,0 +1,7 @@
+{ ... }: {
+ services.redshift = {
+ enable = true;
+ temperatre.night = 3500;
+ provider = "geoclue2";
+ };
+}
diff --git a/modules/workstation/sound/default.nix b/modules/workstation/sound/default.nix
new file mode 100644
index 00000000000..5d10b71ffdc
--- /dev/null
+++ b/modules/workstation/sound/default.nix
@@ -0,0 +1,5 @@
+{ ... }: {
+ sound.enable = true;
+ hardware.pulseaudio.enable = true;
+ hardware.pulseaudio.zeroconf.discovery.enable = true;
+}
diff --git a/modules/workstation/syncthing/default.nix b/modules/workstation/syncthing/default.nix
new file mode 100644
index 00000000000..28aee522801
--- /dev/null
+++ b/modules/workstation/syncthing/default.nix
@@ -0,0 +1,10 @@
+{ pkgs, ... }: {
+ services.syncthing = {
+ enable = true;
+ dataDir = "/home/.local/syncthing/";
+ user = "spacekookie";
+ group = "spacekookie";
+ openDefaultPorts = false;
+ guiAddress = "localhost:1234";
+ };
+}