{ config, lib, pkgs, inputs, ... }: let # Compile your custom wvkbd build custom_wvkbd = pkgs.wvkbd.overrideAttrs (oldAttrs: { # Pin the package version to the exact commit from your flake input src = inputs.wvkbd-src; version = "custom-git"; # Choose your preferred layout layout (e.g., mobintl, standard, cyrillic) makeFlags = (oldAttrs.makeFlags or []) ++ [ "LAYOUT=mobintl" ]; # Optional: Swap out the layout with your own config.h file if you have one preBuild = '' cp ${./programs/layout.custom.h} layout.mobintl.h cp ${./programs/config.custom.h} config.mobintl.h cp ${./programs/keymap.custom.h} keymap.mobintl.h ''; }); in { imports = [ ./programs ./desktop ]; home.username = "jashton"; home.homeDirectory = "/home/jashton"; home.file.".zshrc".text = '' # Zsh is configured globally at the NixOS system level. # This file exists solely to prevent the zsh-newuser-install prompt. ''; home.sessionVariables = { EDITOR = "nvim"; NIXOS_OZONE_WL = "1"; # Forces Electron/Chromium apps to use Wayland natively GTK_IM_MODULE = "wayland"; # Forces GTK apps to use Wayland text-input protocols QT_IM_MODULE = "wayland"; # Forces Qt apps to use Wayland text-input protocols TEXT_INPUT_PRESENT = "1"; # Explicitly signals virtual keyboard capability to the shell JAVA_HOME = "${pkgs.jdk21}"; }; home.packages = with pkgs; [ android-tools antigravity asciinema claude-code discord eclipses.eclipse-java ffmpeg gemini-cli kicad libreoffice librewolf opencode pdftk picom prismlauncher scrot signal-desktop spotify thunderbird tor tor-browser vlc wtype xwayland-satellite yt-dlp zathura custom_wvkbd (pkgs.writeShellScriptBin "jroot" '' d="$PWD" while [ "$d" != "/" ]; do if [ -f "$d/.classpath" ]; then printf '%s\n' "$d"; exit 0; fi d="$(dirname "$d")" done echo "jroot: no .classpath found at or above $PWD" >&2 exit 1 '') (pkgs.writeShellScriptBin "jbuild" '' set -euo pipefail if [ $# -lt 1 ]; then echo "usage: jrun [args...]" >&2 exit 1 fi ROOT="$(jroot)" cd "$ROOT" mkdir -p bin # Set the target directory, defaulting to the current directory (.) if $1 is empty TARGET_DIR="$1" SOURCES_FILE="SOURCES" # Fix the find command to safely search the target directory find "$TARGET_DIR" -name '*.java' > "$SOURCES_FILE" if [ ! -s "$SOURCES_FILE" ]; then # Fix the error message to reference the directory, not the output text file echo "jbuild: no .java files found under $TARGET_DIR" >&2 exit 1 fi javac -g --release 21 -encoding UTF-8 -d bin -cp "lib/*" @"$SOURCES_FILE" '') (pkgs.writeShellScriptBin "jclean" '' set -euo pipefail ROOT="$(jroot)" rm -rf "$ROOT/bin" echo "cleaned $ROOT/bin" '') (pkgs.writeShellScriptBin "jrun" '' set -euo pipefail if [ $# -lt 2 ]; then echo "usage: jrun [args...]" >&2 exit 1 fi ROOT="$(jroot)" cd "$ROOT" jbuild $1 MAIN="./bin/$2/$3"; shift java -cp "bin:lib/*" "$MAIN" "$@" '') (pkgs.writeShellScriptBin "jtest" '' set -euo pipefail if [ "$#" -lt 1 ]; then echo "usage: jtest [args...]" exit 1 fi # sort -V so 1.10.2 beats 1.9.0; plain tail -n1 sorts those the wrong way. JUNIT="$(ls -1 "$HOME"/dev/jars/junit-platform-console-standalone-*.jar 2>/dev/null | sort -V | tail -n1 || true)" if [ -z "$JUNIT" ]; then echo "jtest: no junit-platform-console-standalone jar in ~/dev/jars" >&2 exit 1 fi # --debug suspends the test JVM on start and waits for nvim-dap to attach # on :5005 (see the "Attach to jtest" config in nvim.nix), so breakpoints # set before running jtest --debug are hit from the very first test. DEBUG_ARGS=() if [[ "$1" = "debug" ]]; then DEBUG_ARGS=(-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005) shift echo "jtest: waiting for debugger to attach on 127.0.0.1:5005..." >&2 fi ROOT="$(jroot)" cd "$ROOT" jbuild "$1" if [ $# -eq 0 ]; then exec java "''${DEBUG_ARGS[@]}" -jar "$JUNIT" execute --class-path "bin:lib/*" --scan-class-path --details=tree fi ARGS="" for pkg in "$@"; do ARGS="$ARGS --select-package $pkg" done exec java "''${DEBUG_ARGS[@]}" -jar "$JUNIT" execute --class-path "bin:lib/*" $ARGS --details=tree '') (pkgs.writeShellScriptBin "fkill" '' set -eu if [ $# -lt 1 ]; then echo "usage: fkill " >&2 echo "eg. fkill firefox" >&2 exit 1 fi PROGRAM="$1" if ! pgrep -x -- "$PROGRAM" >/dev/null 2>&1; then echo "fkill: no process named '$PROGRAM'" >&2 exit 1 fi pgrep -a -x -- "$PROGRAM" printf 'Kill these? [y/N] ' read -r reply case "$reply" in [yY]*) pkill -x -- "$PROGRAM" ;; *) echo "aborted" ;; esac '') (pkgs.writeShellScriptBin "find-open-port" '' set -u if [ $# -lt 1 ]; then echo "Please provide an application name, project directory, or other identifier." echo ' Usage: find-open-port $HOME/dev/some-project' echo " Usage: find-open-port some-app" exit 1 fi APP_NAME="$1" REGISTRY_FILE="$HOME/.dotfiles/ports.registry" MIN_PORT=8000 MAX_PORT=8999 MAX_RETRIES=50 mkdir -p "$(dirname "$REGISTRY_FILE")" if [ -f "$REGISTRY_FILE" ] && grep -q "^$APP_NAME : " "$REGISTRY_FILE"; then echo "Already registered:" grep "^$APP_NAME : " "$REGISTRY_FILE" exit 0 fi echo "Searching for available port between $MIN_PORT and $MAX_PORT for $APP_NAME..." for ((i=1; i<=MAX_RETRIES; i++)); do RANDOM_PORT=$(shuf -i $MIN_PORT-$MAX_PORT -n 1) if ! ss -tuln | grep -E -q ":$RANDOM_PORT\b"; then if [ -f "$REGISTRY_FILE" ] && grep -q "\b$RANDOM_PORT\b" "$REGISTRY_FILE"; then continue fi echo "$APP_NAME : $RANDOM_PORT" >> "$REGISTRY_FILE" echo -e "\nSuccessfully wrote '$APP_NAME : $RANDOM_PORT' to $REGISTRY_FILE" exit 0 fi done echo -e "\nError: Could not find an open port between $MIN_PORT and $MAX_PORT after $MAX_RETRIES attempts." exit 1 '') ]; home.activation = { # 1. Create the persistent directories createWorkspaceDirs = lib.hm.dag.entryAfter ["writeBoundary"] '' $DRY_RUN_CMD mkdir -p $HOME/dev $DRY_RUN_CMD mkdir -p $HOME/downloads $DRY_RUN_CMD mkdir -p $HOME/life $DRY_RUN_CMD mkdir -p $HOME/media/pics $DRY_RUN_CMD mkdir -p $HOME/media/videos $DRY_RUN_CMD mkdir -p $HOME/school ''; }; systemd.user.services.lan-mouse = { Unit = { Description = "Lan Mouse Daemon"; After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; Install = { WantedBy = [ "graphical-session.target" ]; }; Service = { # The --daemon flag ensures it runs silently in the background without opening the GUI ExecStart = "${pkgs.lan-mouse}/bin/lan-mouse --daemon"; }; }; programs.ssh = { enable = true; enableDefaultConfig = false; settings = { "*" = { forwardAgent = false; addKeysToAgent = "no"; compression = false; serverAliveInterval = 0; serverAliveCountMax = 3; hashKnownHosts = false; userKnownHostsFile = "~/.ssh/known_hosts"; controlMaster = "no"; controlPath = "~/.ssh/master-%r@%n:%p"; controlPersist = "no"; }; "heliotrope" = { hostname = "100.77.235.110"; }; "lavender" = { hostname = "100.99.189.49"; }; "violet" = { hostname = "100.101.100.84"; }; "lilac" = { hostname = "100.82.51.88"; }; }; }; home.stateVersion = "26.05"; # DO NOT CHANGE }