From 6b49ef4e191094a174b2b7d6fff8aad7f59f931f Mon Sep 17 00:00:00 2001 From: Frieder Schlesier Date: Mon, 26 Feb 2024 13:15:20 +0100 Subject: [PATCH] add first draft for guix-home on x230 --- .bin/activate-profiles | 39 + .bin/sync-dotfiles | 42 + .bin/update-channels | 3 + .bin/update-dotfiles | 13 + .bin/update-profiles | 22 + README-guix.org | 21 + Systems.org | 1081 +++++++++++++++++ fschl/base-channels.scm | 37 + fschl/files/bash-prompt | 76 ++ fschl/files/inputrc | 7 + fschl/home-services/desktop.scm | 133 ++ .../dotfiles/.config/dunst/dunstrc | 202 +++ .../dotfiles/.config/polybar/config | 233 ++++ .../dotfiles/.config/polybar/player-status.sh | 16 + .../dotfiles/.config/sway/config | 197 +++ .../dotfiles/.config/waybar/config | 97 ++ .../dotfiles/.config/waybar/style.css | 90 ++ .../dotfiles/.config/waybar/timer.sh | 3 + fschl/home-services/emacs.scm | 213 ++++ fschl/home-services/pipewire.scm | 99 ++ fschl/home-services/template-file.scm | 39 + fschl/home-services/udiskie.scm | 32 + fschl/home-services/xsession | 25 + fschl/home-services/xsettingsd.scm | 74 ++ fschl/packages/fonts.scm | 23 + fschl/packages/linux.scm | 47 + fschl/systems/base.scm | 264 ++++ fschl/systems/common.scm | 102 ++ fschl/systems/install.scm | 51 + fschl/systems/x230ding.scm | 45 + fschl/utils.scm | 52 + 31 files changed, 3378 insertions(+) create mode 100755 .bin/activate-profiles create mode 100755 .bin/sync-dotfiles create mode 100755 .bin/update-channels create mode 100755 .bin/update-dotfiles create mode 100755 .bin/update-profiles create mode 100644 README-guix.org create mode 100644 Systems.org create mode 100644 fschl/base-channels.scm create mode 100644 fschl/files/bash-prompt create mode 100644 fschl/files/inputrc create mode 100644 fschl/home-services/desktop.scm create mode 100755 fschl/home-services/dotfiles/.config/dunst/dunstrc create mode 100755 fschl/home-services/dotfiles/.config/polybar/config create mode 100755 fschl/home-services/dotfiles/.config/polybar/player-status.sh create mode 100644 fschl/home-services/dotfiles/.config/sway/config create mode 100644 fschl/home-services/dotfiles/.config/waybar/config create mode 100644 fschl/home-services/dotfiles/.config/waybar/style.css create mode 100755 fschl/home-services/dotfiles/.config/waybar/timer.sh create mode 100644 fschl/home-services/emacs.scm create mode 100644 fschl/home-services/pipewire.scm create mode 100644 fschl/home-services/template-file.scm create mode 100644 fschl/home-services/udiskie.scm create mode 100755 fschl/home-services/xsession create mode 100644 fschl/home-services/xsettingsd.scm create mode 100644 fschl/packages/fonts.scm create mode 100644 fschl/packages/linux.scm create mode 100644 fschl/systems/base.scm create mode 100644 fschl/systems/common.scm create mode 100644 fschl/systems/install.scm create mode 100644 fschl/systems/x230ding.scm create mode 100644 fschl/utils.scm diff --git a/.bin/activate-profiles b/.bin/activate-profiles new file mode 100755 index 0000000..90b3333 --- /dev/null +++ b/.bin/activate-profiles @@ -0,0 +1,39 @@ +#!/bin/sh +# NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +GREEN='\033[1;32m' +RED='\033[1;30m' +NC='\033[0m' +GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles + +profiles=$* +if [[ $# -eq 0 ]]; then + profiles="$HOME/.config/guix/manifests/*.scm"; +fi + +for profile in $profiles; do + # Remove the path and file extension, if any + profileName=$(basename $profile) + profileName="${profileName%.*}" + profilePath="$GUIX_EXTRA_PROFILES/$profileName" + manifestPath=$HOME/.config/guix/manifests/$profileName.scm + + if [ -f $manifestPath ]; then + echo + echo -e "${GREEN}Activating profile:" $manifestPath "${NC}" + echo + + mkdir -p $profilePath + guix package --manifest=$manifestPath --profile="$profilePath/$profileName" + + # Source the new profile + GUIX_PROFILE="$profilePath/$profileName" + if [ -f $GUIX_PROFILE/etc/profile ]; then + . "$GUIX_PROFILE"/etc/profile + else + echo -e "${RED}Couldn't find profile:" $GUIX_PROFILE/etc/profile "${NC}" + fi + else + echo "No profile found at path" $profilePath + fi +done diff --git a/.bin/sync-dotfiles b/.bin/sync-dotfiles new file mode 100755 index 0000000..66973af --- /dev/null +++ b/.bin/sync-dotfiles @@ -0,0 +1,42 @@ +#!/bin/sh +# Sync dotfiles repo and ensure that dotfiles are tangled correctly afterward + +GREEN='\033[1;32m' +BLUE='\033[1;34m' +RED='\033[1;30m' +NC='\033[0m' + +# Navigate to the directory of this script (generally ~/.dotfiles/.bin) +cd $(dirname $(readlink -f $0)) +cd .. + +echo +echo -e "${BLUE}Saving Org buffers if Emacs is running...${NC}" +emacsclient -u -e "(org-save-all-org-buffers)" -a "echo 'Emacs is not currently running'" + +echo -e "${BLUE}Stashing existing changes...${NC}" +stash_result=$(git stash push -m "sync-dotfiles: Before syncing dotfiles") +needs_pop=1 +if [ "$stash_result" = "No local changes to save" ]; then + needs_pop=0 +fi + +echo -e "${BLUE}Pulling updates from dotfiles repo...${NC}" +echo +git pull origin master +echo + +if [[ $needs_pop -eq 1 ]]; then + echo -e "${BLUE}Popping stashed changes...${NC}" + echo + git stash pop +fi + +unmerged_files=$(git diff --name-only --diff-filter=U) +if [[ ! -z $unmerged_files ]]; then + echo -e "${RED}The following files have merge conflicts after popping the stash:${NC}" + echo + printf %"s\n" $unmerged_files # Ensure newlines are printed +else + update-dotfiles +fi diff --git a/.bin/update-channels b/.bin/update-channels new file mode 100755 index 0000000..d8689e4 --- /dev/null +++ b/.bin/update-channels @@ -0,0 +1,3 @@ +#!/bin/sh +guix pull --channels=$HOME/.config/guix/base-channels.scm +guix describe --format=channels > ~/.config/guix/channels.scm diff --git a/.bin/update-dotfiles b/.bin/update-dotfiles new file mode 100755 index 0000000..6408e85 --- /dev/null +++ b/.bin/update-dotfiles @@ -0,0 +1,13 @@ +#!/bin/sh +# Navigate to the directory of this script (generally ~/.dotfiles/.bin) +cd $(dirname $(readlink -f $0)) +cd .. + +# The heavy lifting is done by an Emacs script +emacs -Q --script ./.emacs.d/tangle-dotfiles.el + +# Make sure any running Emacs instance gets updated settings +emacsclient -e '(load-file "~/.emacs.d/per-system-settings.el")' -a "echo 'Emacs is not currently running'" + +# Update configuration symlinks +stow . diff --git a/.bin/update-profiles b/.bin/update-profiles new file mode 100755 index 0000000..b8d48e4 --- /dev/null +++ b/.bin/update-profiles @@ -0,0 +1,22 @@ +#!/bin/sh +# NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +GREEN='\033[1;32m' +NC='\033[0m' +GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles + +profiles=$* +if [[ $# -eq 0 ]]; then + profiles="$GUIX_EXTRA_PROFILES/*"; +fi + +for profile in $profiles; do + profileName=$(basename $profile) + profilePath=$GUIX_EXTRA_PROFILES/$profileName + + echo + echo -e "${GREEN}Updating profile:" $profilePath "${NC}" + echo + + guix package --profile="$profilePath/$profileName" --manifest="$HOME/.config/guix/manifests/$profileName.scm" +done diff --git a/README-guix.org b/README-guix.org new file mode 100644 index 0000000..7c36e03 --- /dev/null +++ b/README-guix.org @@ -0,0 +1,21 @@ +* GUIX systems and home +** Backlog +*** TODO add ssh config +*** TODO add ssh keys +*** TODO password management +start with keepassxc, but try password-store +*** TODO figure out how to maintain emacs config +*** TODO add LaTeX +with XDG_CONFIG_DIR, XDG_DATA_DIR +https://wiki.archlinux.org/title/XDG_Base_Directory + +and make letter creation from org-capture work +*** TODO add wireguard configuration +*** TODO add libreoffice +*** TODO add email management (mu4e?) +*** TODO add config for desktop (multi-monitor) +*** TODO add syncthing config +how to back that up? +*** TODO figure out luks setup +*** TODO securely manage ssh keys +they are in the keepass database file diff --git a/Systems.org b/Systems.org new file mode 100644 index 0000000..924b27c --- /dev/null +++ b/Systems.org @@ -0,0 +1,1081 @@ +#+TITLE: System Configuration with Guix +#+PROPERTY: header-args :tangle-mode (identity #o444) +#+PROPERTY: header-args:sh :tangle-mode (identity #o555) + +* Table of Contents +:PROPERTIES: +:TOC: :include all :ignore this +:END: +:CONTENTS: +- [[#channels][Channels]] +- [[#systems][Systems]] + - [[#base-configuration][Base Configuration]] + - [[#machines][Machines]] + - [[#per-system-settings][Per-System Settings]] + - [[#zerocool][zerocool]] + - [[#acidburn][acidburn]] + - [[#davinci][davinci]] + - [[#phantom][phantom]] + - [[#usb-installation-image][USB Installation Image]] +- [[#profile-management][Profile Management]] + - [[#activating-profiles][Activating Profiles]] + - [[#updating-profiles][Updating Profiles]] + - [[#updating-channels][Updating Channels]] +- [[#dotfiles-management][Dotfiles Management]] + - [[#syncing][Syncing]] + - [[#updating][Updating]] +- [[#nix-package-manager][Nix Package Manager]] +- [[#system-installation][System Installation]] + - [[#building-the-installation-image][Building the Installation Image]] + - [[#installing-guix][Installing Guix]] + - [[#setting-up-wifi][Setting up WiFi]] + - [[#setting-up-partitions][Setting Up Partitions]] + - [[#initial-system-installation][Initial System Installation]] + - [[#initial-system-setup][Initial System Setup]] +:END: + +* Channels + +Guix supports the concept of [[https://guix.gnu.org/manual/en/html_node/Channels.html#Channels][channels]] which basically amount to Git repositories which contain Guix package definitions that can be installed on your machine. Aside from the =%default-channels= list, I also use the [[https://gitlab.com/nonguix/nonguix][Nonguix]] channel to install packages that aren't included with Guix by default like the non-free Linux kernel. + +I also generate my real =.config/guix/channels.scm= file based on this =base-channels.scm= file. This allows me to keep a pinned channel list in the real channels file while maintaining a canonical channel listing that I generate it from using the =update-channels= script (defined later in this file). + +*.config/guix/base-channels.scm:* + +#+begin_src scheme :tangle .config/guix/base-channels.scm + + ;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + + (list (channel + ;; (name 'channel-x) + ;; (url "file:///home/fschl/src/guix-fschl-infra/")) + ;; (channel + (name 'flat) + (url "https://github.com/flatwhatson/guix-channel.git") + (commit + "7b8353ebbcf486e3344924d1cac0fa7ba47c371d") + (introduction + (make-channel-introduction + "33f86a4b48205c0dc19d7c036c85393f0766f806" + (openpgp-fingerprint + "736A C00E 1254 378B A982 7AF6 9DBE 8265 81B6 4490")))) + (channel + (name 'rde) + (url "https://git.sr.ht/~abcdw/rde") + (introduction + (make-channel-introduction + "257cebd587b66e4d865b3537a9a88cccd7107c95" + (openpgp-fingerprint + "2841 9AC6 5038 7440 C7E9 2FFA 2208 D209 58C1 DEB0")))) + (channel + (name 'nonguix) + (url "https://gitlab.com/nonguix/nonguix")) + (channel + (name 'guix) + (url "https://git.savannah.gnu.org/git/guix.git") + ;; (url "file:///home/daviwil/Projects/Code/guix")) + (introduction + (make-channel-introduction + "9edb3f66fd807b096b48283debdcddccfea34bad" + (openpgp-fingerprint + "BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA"))))) + +#+end_src + +The following channel list can be used when testing patches to packages and services from a local clone of the Guix repo. You'll have to create a branch and commit changes to it before =guix pull= can pick them up, though. You can change the target branch using the =branch= field of the =channel=. + +#+begin_src scheme :tangle .config/guix/channels.scm + +;; (list (channel +;; (name 'nonguix) +;; (url "https://gitlab.com/nonguix/nonguix")) +;; (channel +;; (name 'guix) +;; (branch "fix-glu-pkg-config") +;; (url "file:///home/daviwil/Projects/Code/guix") +;; (introduction +;; (make-channel-introduction +;; "d06d5db885e4b8399e878708862fbe3a67f0592c" +;; (openpgp-fingerprint +;; "53C4 1E6E 41AA FE55 335A CA5E 446A 2ED4 D940 BF14"))))) + +#+end_src + +* Systems + +** Base Configuration + +This base configuration is shared between all of the machines I manage with Guix. Since all of my machines are Lenovo ThinkPad laptops, the same basic configuration applies pretty cleanly across all of them. This may change in the future. + +Any configuration that derives from =base-operating-system= must invoke =guix system= in a specific way to ensure it gets loaded correctly: + +#+begin_src sh + +sudo -E guix system -L ~/.dotfiles/.config/guix/systems reconfigure ~/.dotfiles/.config/guix/systems/davinci.scm + +#+end_src + +*.config/guix/systems/base-system.scm:* + +#+begin_src scheme :tangle .config/guix/systems/base-system.scm + +;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +(define-module (base-system) + #:use-module (gnu) + #:use-module (srfi srfi-1) + #:use-module (gnu system nss) + #:use-module (gnu services pm) + #:use-module (gnu services cups) + #:use-module (gnu services desktop) + #:use-module (gnu services docker) + #:use-module (gnu services networking) + #:use-module (gnu services virtualization) + #:use-module (gnu packages wm) + #:use-module (gnu packages cups) + #:use-module (gnu packages vim) + #:use-module (gnu packages gtk) + #:use-module (gnu packages xorg) + #:use-module (gnu packages emacs) + #:use-module (gnu packages file-systems) + #:use-module (gnu packages gnome) + #:use-module (gnu packages mtools) + #:use-module (gnu packages linux) + #:use-module (gnu packages audio) + #:use-module (gnu packages gnuzilla) + #:use-module (gnu packages pulseaudio) + #:use-module (gnu packages web-browsers) + #:use-module (gnu packages version-control) + #:use-module (gnu packages package-management) + #:use-module (nongnu packages linux) + #:use-module (nongnu system linux-initrd)) + +(use-service-modules nix) +(use-service-modules desktop xorg) +(use-package-modules certs) +(use-package-modules shells) + +#+end_src + +Add a =udev= rule to enable members of the =video= group to control screen brightness. + +#+begin_src scheme :tangle .config/guix/systems/base-system.scm + + ;; Allow members of the "video" group to change the screen brightness. + (define %backlight-udev-rule + (udev-rule + "90-backlight.rules" + (string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", " + "RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\"" + "\n" + "ACTION==\"add\", SUBSYSTEM==\"backlight\", " + "RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\""))) + +#+end_src + +Override the default =%desktop-services= to add the =udev= backlight configuration and include OpenVPN in the list of NetworkManager plugins. + +#+begin_src scheme :tangle .config/guix/systems/base-system.scm + + (define %my-desktop-services + (modify-services %desktop-services + (elogind-service-type config => + (elogind-configuration (inherit config) + (handle-lid-switch-external-power 'suspend))) + (udev-service-type config => + (udev-configuration (inherit config) + (rules (cons %backlight-udev-rule + (udev-configuration-rules config))))) + (network-manager-service-type config => + (network-manager-configuration (inherit config) + (vpn-plugins (list network-manager-openvpn)))))) + +#+end_src + +Use the =libinput= driver for all input devices since it's a bit more modern than the default. + +#+begin_src scheme :tangle .config/guix/systems/base-system.scm + + (define %xorg-libinput-config + "Section \"InputClass\" + Identifier \"Touchpads\" + Driver \"libinput\" + MatchDevicePath \"/dev/input/event*\" + MatchIsTouchpad \"on\" + + Option \"Tapping\" \"on\" + Option \"TappingDrag\" \"on\" + Option \"DisableWhileTyping\" \"on\" + Option \"MiddleEmulation\" \"on\" + Option \"ScrollMethod\" \"twofinger\" + EndSection + Section \"InputClass\" + Identifier \"Keyboards\" + Driver \"libinput\" + MatchDevicePath \"/dev/input/event*\" + MatchIsKeyboard \"on\" + EndSection + ") + +#+end_src + +Define the =base-operating-system= which will be inherited by all machine configurations. + +#+begin_src scheme :tangle .config/guix/systems/base-system.scm + +(define-public base-operating-system + (operating-system + (host-name "hackstock") + ;(timezone "America/Los_Angeles") + (timezone "Europe/Berlin") + (locale "en_US.utf8") + + ;; Use non-free Linux and firmware + (kernel linux) + (firmware (list linux-firmware)) + (initrd microcode-initrd) + + ;; Choose US English keyboard layout. The "altgr-intl" + ;; variant provides dead keys for accented characters. + (keyboard-layout (keyboard-layout "de" "altgr-intl" #:model "thinkpad")) + + ;; Use the UEFI variant of GRUB with the EFI System + ;; Partition mounted on /boot/efi. + (bootloader (bootloader-configuration + (bootloader grub-efi-bootloader) + (target "/boot/efi") + (keyboard-layout keyboard-layout))) + + + ;; Guix doesn't like it when there isn't a file-systems + ;; entry, so add one that is meant to be overridden + (file-systems (cons* + (file-system + (mount-point "/tmp") + (device "none") + (type "tmpfs") + (check? #f)) + %base-file-systems)) + + (users (cons (user-account + (name "daviwil") + (comment "David Wilson") + (group "users") + (home-directory "/home/daviwil") + (supplementary-groups '( + "wheel" ;; sudo + "netdev" ;; network devices + "kvm" + "tty" + "input" + "docker" + "realtime" ;; Enable realtime scheduling + "lp" ;; control bluetooth devices + "audio" ;; control audio devices + "video"))) ;; control video devices + + %base-user-accounts)) + + ;; Add the 'realtime' group + (groups (cons (user-group (system? #t) (name "realtime")) + %base-groups)) + + ;; Install bare-minimum system packages + (packages (append (list + git + ntfs-3g + exfat-utils + fuse-exfat + stow + vim + emacs + xterm + bluez + bluez-alsa + pulseaudio + tlp + xf86-input-libinput + nss-certs ;; for HTTPS access + gvfs) ;; for user mounts + %base-packages)) + + ;; Use the "desktop" services, which include the X11 log-in service, + ;; networking with NetworkManager, and more + (services (cons* (service slim-service-type + (slim-configuration + (xorg-configuration + (xorg-configuration + (keyboard-layout keyboard-layout) + (extra-config (list %xorg-libinput-config)))))) + (service tlp-service-type + (tlp-configuration + (cpu-boost-on-ac? #t) + (wifi-pwr-on-bat? #t))) + (pam-limits-service ;; This enables JACK to enter realtime mode + (list + (pam-limits-entry "@realtime" 'both 'rtprio 99) + (pam-limits-entry "@realtime" 'both 'memlock 'unlimited))) + (extra-special-file "/usr/bin/env" + (file-append coreutils "/bin/env")) + (service thermald-service-type) + (service docker-service-type) + (service libvirt-service-type + (libvirt-configuration + (unix-sock-group "libvirt") + (tls-port "16555"))) + (service cups-service-type + (cups-configuration + (web-interface? #t) + (extensions + (list cups-filters)))) + (service nix-service-type) + (bluetooth-service #:auto-enable? #t) + (remove (lambda (service) + (eq? (service-kind service) gdm-service-type)) + %my-desktop-services))) + + ;; Allow resolution of '.local' host names with mDNS + (name-service-switch %mdns-host-lookup-nss))) + +#+end_src + +** Machines + +Because I'm lame, all of my machines are named from characters, things, and places from the movie Hackers. + +*** Per-System Settings + +Some settings need to be customized on a per-system basis without tweaking individual configuration files. Thanks to org-mode's =noweb= functionality, I can define a set of variables that can be tweaked for each system and applied across these configuration files when they get generated. + +I also define a function called =dw/system-settings-get= which can retrieve these settings appropriately. + +#+begin_src emacs-lisp :tangle .emacs.d/per-system-settings.el :noweb yes + +(require 'map) ;; Needed for map-merge + +(setq dw/system-settings + (map-merge + 'list + '((desktop/dpi . 180) + (desktop/background . "samuel-ferrara-uOi3lg8fGl4-unsplash.jpg") + (emacs/default-face-size . 220) + (emacs/variable-face-size . 245) + (emacs/fixed-face-size . 200) + (polybar/height . 35) + (polybar/font-0-size . 18) + (polybar/font-1-size . 14) + (polybar/font-2-size . 20) + (polybar/font-3-size . 13) + (dunst/font-size . 20) + (dunst/max-icon-size . 88) + (vimb/default-zoom . 180) + (qutebrowser/default-zoom . 200)) + <>)) + +#+end_src + +*** x230-guixXorg + +=zerocool= is a Thinkpad x230 that I use for system testing and Guix demonstrations for System Crafters. + +*.config/guix/systems/x230-guix.scm:* + +#+begin_src scheme :tangle .config/guix/systems/x230-guix.scm + +;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +(define-module (zerocool) + #:use-module (base-system) + #:use-module (gnu)) + +(operating-system + (inherit base-operating-system) + (host-name "x230-guixXorg") + + (mapped-devices + (list (mapped-device + (source (uuid "039d3ff8-0f90-40bf-89d2-4b2454ada6df")) + (target "system-root") + (type luks-device-mapping)))) + + (file-systems (cons* + (file-system + (device (file-system-label "x230-guixXorg")) + (mount-point "/") + (type "ext4") + (dependencies mapped-devices)) + (file-system + (device "/dev/nvme0n1p1") + (mount-point "/boot/efi") + (type "vfat")) + %base-file-systems))) + +#+end_src + +*** t430-guixServer + +=acidburn= is a Thinkpad T430 that I use for most of my home automation server. + +*.config/guix/systems/t430-guixServer.scm:* + +#+begin_src scheme :tangle .config/guix/systems/t430-guixServer.scm + + ;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + + (define-module (acidburn) + #:use-module (base-system) + #:use-module (gnu) + #:use-module (nongnu packages linux)) + + (operating-system + (inherit base-operating-system) + (host-name "t430-guixServer") + + (firmware (list linux-firmware sof-firmware)) + + (mapped-devices + (list (mapped-device + (source (uuid "15ece913-c423-49aa-ac42-3bad39fdd966")) + (target "system-root") + (type luks-device-mapping)))) + + (file-systems (cons* + (file-system + (device (file-system-label "system-root")) + (mount-point "/") + (type "ext4") + (dependencies mapped-devices)) + (file-system + (device "/dev/nvme0n1p1") + (mount-point "/boot/efi") + (type "vfat")) + %base-file-systems))) + +#+end_src + +*System Settings* + +#+begin_src emacs-lisp :noweb-ref system-settings :noweb-sep "" + + (when (equal system-name "acidburn") + '((desktop/dpi . 180) + (emacs/default-face-size . 190) + (emacs/variable-face-size . 200) + (emacs/fixed-face-size . 190) + (polybar/height . 30) + (polybar/font-0-size . 16) + (polybar/font-1-size . 12) + (polybar/font-2-size . 18) + (polybar/font-3-size . 11) + (dunst/font-size . 20) + (dunst/max-icon-size . 88) + (vimb/default-zoom . 160) + (qutebrowser/default-zoom . 180))) + + +#+end_src + +*** davinci + +=davinci= is a ThinkPad T480s that I use at my day job. + +*.config/guix/systems/davinci.scm:* + +#+begin_src scheme :tangle .config/guix/systems/davinci.scm + +;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +(define-module (davinci) + #:use-module (base-system) + #:use-module (gnu)) + +(operating-system + (inherit base-operating-system) + (host-name "davinci") + + (mapped-devices + (list (mapped-device + (source (uuid "eaba53d9-d7e5-4129-82c8-df28bfe6527e")) + (target "system-root") + (type luks-device-mapping)))) + + (file-systems (cons* + (file-system + (device (file-system-label "system-root")) + (mount-point "/") + (type "ext4") + (dependencies mapped-devices)) + (file-system + (device "/dev/nvme0n1p2") + (mount-point "/boot/efi") + (type "vfat")) + %base-file-systems))) + +#+end_src + +*System Settings* + +#+begin_src emacs-lisp :noweb-ref system-settings :noweb-sep "" + + (when (equal system-name "davinci") + '((desktop/dpi . 130) + (emacs/default-face-size . 165) + (emacs/fixed-face-size . 165) + (emacs/variable-face-size . 190) + (polybar/height . 25) + (polybar/font-0-size . 12) + (polybar/font-1-size . 8) + (polybar/font-2-size . 14) + (polybar/font-3-size . 9) + (dunst/font-size . 14) + (dunst/max-icon-size . 64) + (vimb/default-zoom . 150) + (qutebrowser/default-zoom . 150))) + + ;; When booted into Windows + (when (equal system-name "daviwil-t480") + '((emacs/default-face-size . 110) + (emacs/fixed-face-size . 110) + (emacs/variable-face-size . 134))) + +#+end_src + +*** phantom + +=phantom= is a ThinkPad X1 Extreme that I use for music production and video editing. For whatever reason, loading the =nouveau= driver crashes the machine upon booting so I've blacklisted it for now until I figure out how to get it working correctly. + +*.config/guix/systems/phantom.scm:* + +#+begin_src scheme :tangle .config/guix/systems/phantom.scm + +;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +(define-module (phantom) + #:use-module (base-system) + #:use-module (gnu)) + +(operating-system + (inherit base-operating-system) + (host-name "phantom") + + (mapped-devices + (list (mapped-device + (source (uuid "091b8ad5-efb3-4c5b-8370-7db99c404a30")) + (target "system-root") + (type luks-device-mapping)))) + + (file-systems (cons* + (file-system + (device (file-system-label "system-root")) + (mount-point "/") + (type "ext4") + (dependencies mapped-devices)) + (file-system + (device "/dev/nvme0n1p1") + (mount-point "/boot/efi") + (type "vfat")) + %base-file-systems))) + +#+end_src + +*System Settings* + +#+begin_src emacs-lisp :noweb-ref system-settings :noweb-sep "" + +(when (equal system-name "phantom") + '((desktop/dpi . 240) + (polybar/height . 40) + (vimb/default-zoom . 200))) + +#+end_src + +** USB Installation Image + +To install Guix on another machine, you first to build need a USB image. Since I use modern laptops that require non-free components, I have to build a custom installation image with the full Linux kernel. I also include a few other programs that are useful for the installation process. I adapted this image from [[https://gitlab.com/nonguix/nonguix/blob/master/nongnu/system/install.scm][one found on the Nonguix repository]], hence the copyright header. + +*.config/guix/systems/install.scm:* + +#+begin_src scheme :tangle .config/guix/systems/install.scm + + ;;; Copyright © 2019 Alex Griffin + ;;; Copyright © 2019 Pierre Neidhardt + ;;; Copyright © 2019 David Wilson + ;;; + ;;; This program is free software: you can redistribute it and/or modify + ;;; it under the terms of the GNU General Public License as published by + ;;; the Free Software Foundation, either version 3 of the License, or + ;;; (at your option) any later version. + ;;; + ;;; This program is distributed in the hope that it will be useful, + ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of + ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ;;; GNU General Public License for more details. + ;;; + ;;; You should have received a copy of the GNU General Public License + ;;; along with this program. If not, see . + + ;; Generate a bootable image (e.g. for USB sticks, etc.) with: + ;; $ guix system disk-image nongnu/system/install.scm + + (define-module (nongnu system install) + #:use-module (gnu system) + #:use-module (gnu system install) + #:use-module (gnu packages version-control) + #:use-module (gnu packages vim) + #:use-module (gnu packages curl) + #:use-module (gnu packages emacs) + #:use-module (gnu packages linux) + #:use-module (gnu packages mtools) + #:use-module (gnu packages package-management) + #:use-module (nongnu packages linux) + #:export (installation-os-nonfree)) + + (define installation-os-nonfree + (operating-system + (inherit installation-os) + (kernel linux) + (firmware (list linux-firmware)) + + ;; Add the 'net.ifnames' argument to prevent network interfaces + ;; from having really long names. This can cause an issue with + ;; wpa_supplicant when you try to connect to a wifi network. + (kernel-arguments '("quiet" "modprobe.blacklist=radeon" "net.ifnames=0")) + + ;; Add some extra packages useful for the installation process + (packages + (append (list exfat-utils fuse-exfat git curl stow vim emacs-no-x-toolkit) + (operating-system-packages installation-os))))) + + installation-os-nonfree + +#+end_src + +* Profile Management + +I like to separate my packages into separate manifests that get installed as profiles which can be updated independently. These profiles get installed under the =~/.guix-extra-profiles= path and sourced by my =~/.profile= when I log in. + +To make the management of multiple profiles easier, I've created a couple of shell scripts: + +** Activating Profiles + +This script accepts a space-separated list of manifest file names (without extension) under the =~/.config/guix/manifests= folder and then installs those profiles for the first time. For example: + +#+begin_src sh + +activate-profiles desktop emacs music + +#+end_src + +*.bin/activate-profiles:* + +#+begin_src sh :tangle .bin/activate-profiles :shebang #!/bin/sh + +# NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +GREEN='\033[1;32m' +RED='\033[1;30m' +NC='\033[0m' +GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles + +profiles=$* +if [[ $# -eq 0 ]]; then + profiles="$HOME/.config/guix/manifests/*.scm"; +fi + +for profile in $profiles; do + # Remove the path and file extension, if any + profileName=$(basename $profile) + profileName="${profileName%.*}" + profilePath="$GUIX_EXTRA_PROFILES/$profileName" + manifestPath=$HOME/.config/guix/manifests/$profileName.scm + + if [ -f $manifestPath ]; then + echo + echo -e "${GREEN}Activating profile:" $manifestPath "${NC}" + echo + + mkdir -p $profilePath + guix package --manifest=$manifestPath --profile="$profilePath/$profileName" + + # Source the new profile + GUIX_PROFILE="$profilePath/$profileName" + if [ -f $GUIX_PROFILE/etc/profile ]; then + . "$GUIX_PROFILE"/etc/profile + else + echo -e "${RED}Couldn't find profile:" $GUIX_PROFILE/etc/profile "${NC}" + fi + else + echo "No profile found at path" $profilePath + fi +done + +#+end_src + +** Updating Profiles + +This script accepts a space-separated list of manifest file names (without extension) under the =~/.config/guix/manifests= folder and then installs any updates to the packages contained within them. If no profile names are provided, it walks the list of profile directories under =~/.guix-extra-profiles= and updates each one of them. + +#+begin_src sh + +update-profiles emacs + +#+end_src + +*.bin/update-profiles:* + +#+begin_src sh :tangle .bin/update-profiles :shebang #!/bin/sh + +# NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +GREEN='\033[1;32m' +NC='\033[0m' +GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles + +profiles=$* +if [[ $# -eq 0 ]]; then + profiles="$GUIX_EXTRA_PROFILES/*"; +fi + +for profile in $profiles; do + profileName=$(basename $profile) + profilePath=$GUIX_EXTRA_PROFILES/$profileName + + echo + echo -e "${GREEN}Updating profile:" $profilePath "${NC}" + echo + + guix package --profile="$profilePath/$profileName" --manifest="$HOME/.config/guix/manifests/$profileName.scm" +done + +#+end_src + +** Updating Channels + +This script makes it easy to update all channels to the latest commit based on an original channel file (see the Channels section at the top of this document). + +#+begin_src sh :tangle .bin/update-channels :shebang #!/bin/sh + + guix pull --channels=$HOME/.config/guix/base-channels.scm + guix describe --format=channels > ~/.config/guix/channels.scm + +#+end_src + +* Dotfiles Management + +Since I keep all of my important configuration files in Org Mode code blocks, I have to ensure that the real configuration files are kept up to date when I sync the latest changes to my [[https://github.com/daviwil/dotfiles][dotfiles]] repo. I've written a couple of scripts to simplify that process: + +** Syncing + +When I want to sync my dotfiles repo into my local clone which likely has uncommitted changes, I run =sync-dotfiles=. This script first makes sure that all Org files are saved in a running Emacs instance and then stashes everything before pulling the latest changes from =origin=. After pulling, the stash is popped and then the script verifies there are no merge conflicts from the stash before proceeding. If there are no conflicts, =update-dotfiles= is run, otherwise I'll fix the merge conflicts manually and run =update-dotfiles= myself. + +*.bin/sync-dotfiles* + +#+begin_src sh :tangle .bin/sync-dotfiles :shebang #!/bin/sh + +# Sync dotfiles repo and ensure that dotfiles are tangled correctly afterward + +GREEN='\033[1;32m' +BLUE='\033[1;34m' +RED='\033[1;30m' +NC='\033[0m' + +# Navigate to the directory of this script (generally ~/.dotfiles/.bin) +cd $(dirname $(readlink -f $0)) +cd .. + +echo +echo -e "${BLUE}Saving Org buffers if Emacs is running...${NC}" +emacsclient -u -e "(org-save-all-org-buffers)" -a "echo 'Emacs is not currently running'" + +echo -e "${BLUE}Stashing existing changes...${NC}" +stash_result=$(git stash push -m "sync-dotfiles: Before syncing dotfiles") +needs_pop=1 +if [ "$stash_result" = "No local changes to save" ]; then + needs_pop=0 +fi + +echo -e "${BLUE}Pulling updates from dotfiles repo...${NC}" +echo +git pull origin master +echo + +if [[ $needs_pop -eq 1 ]]; then + echo -e "${BLUE}Popping stashed changes...${NC}" + echo + git stash pop +fi + +unmerged_files=$(git diff --name-only --diff-filter=U) +if [[ ! -z $unmerged_files ]]; then + echo -e "${RED}The following files have merge conflicts after popping the stash:${NC}" + echo + printf %"s\n" $unmerged_files # Ensure newlines are printed +else + update-dotfiles +fi + +#+end_src + +** Updating + +Updating my dotfiles requires running a script in Emacs to loop over all of my literate configuration =.org= files and run =org-babel-tangle-file= to make sure all of my configuration files are up to date. + +*.bin/update-dotfiles* + +#+begin_src sh :tangle .bin/update-dotfiles :shebang #!/bin/sh + + # Navigate to the directory of this script (generally ~/.dotfiles/.bin) + cd $(dirname $(readlink -f $0)) + cd .. + + # The heavy lifting is done by an Emacs script + emacs -Q --script ./.emacs.d/tangle-dotfiles.el + + # Make sure any running Emacs instance gets updated settings + emacsclient -e '(load-file "~/.emacs.d/per-system-settings.el")' -a "echo 'Emacs is not currently running'" + + # Update configuration symlinks + stow . + +#+end_src + +*.emacs.d/tangle-dotfiles.el* + +#+begin_src emacs-lisp :tangle .emacs.d/tangle-dotfiles.el + + (require 'org) + (load-file "~/.dotfiles/.emacs.d/lisp/dw-settings.el") + + ;; Don't ask when evaluating code blocks + (setq org-confirm-babel-evaluate nil) + + (let* ((dotfiles-path (expand-file-name "~/.dotfiles")) + (org-files (directory-files dotfiles-path nil "\\.org$"))) + + (defun dw/tangle-org-file (org-file) + (message "\n\033[1;32mUpdating %s\033[0m\n" org-file) + (org-babel-tangle-file (expand-file-name org-file dotfiles-path))) + + ;; Tangle Systems.org first + (dw/tangle-org-file "Systems.org") + + (dolist (org-file org-files) + (unless (member org-file '("README.org" "Systems.org")) + (dw/tangle-org-file org-file)))) + +#+end_src + +* Nix Package Manager + +In an ironic twist of fate, I've found that certain tools I need to use are more easily available in the Nix package repository, so I use it to install them. + +#+begin_src conf :tangle .nix-channels + +https://nixos.org/channels/nixpkgs-unstable nixpkgs + +#+end_src + +The channel needs to be updated before any packages can be installed: + +#+begin_src sh + +nix-channel --update + +#+end_src + +Installing packages: + +#+begin_src sh + +nix-env -i nodejs dotnet-sdk gh hledger +# nix-env -iA nixpkgs.nodejs-12_x # For a specific version + +#+end_src + +* System Installation + +Here's a guide for how I install my GNU Guix systems from scratch. This process is simplified because I've already prepared a reusable system configuration so you might need to do extra work if you end up following this for your own system install. + +** Building the Installation Image + +Since I use modern Thinkpads, I have to use the non-free kernel and firmware blobs from the [[https://gitlab.com/nonguix/nonguix][nonguix]] channel. After cloning the repo, the installation image can be built with this command: + +#+begin_src sh + + # Create a slightly larger install image to have some headroom + # for temporary file creation and avoid "no space free" errors + guix system image ./install.scm --image-size=5G + +#+end_src + +*NOTE:* It can take an hour or more for this to complete, so be patient... + +Once the build is complete, Guix will print out the path to the disk image file that was created. You can now write the installation image to a USB stick using =dd=: + +#+begin_src sh + + sudo dd if=/gnu/store/nyg6jv3a4l0pbcvb0x7jfsb60k9qalga-disk-image of=/dev/sdX status=progress + +#+end_src + +** Installing Guix + +With the newly "burned" installation image, boot from the USB drive and choose "Install using the shell based process." + +*** Setting up WiFi + +Use an editor (or =echo=) to create a new file called =wifi.conf= to store the wifi configuration. Make sure to set =ssid= to the name of your wifi access point and =psk= to the passphrase for your wifi. You may also need to change the =key_mgmt= parameter depending on the type of authentication your wifi router supports ([[https://wiki.archlinux.org/index.php/Wpa_supplicant#Configuration][some examples]] on Arch Wiki). + +#+begin_src + + network={ + ssid="ssid-name" + key_mgmt=WPA-PSK + psk="unencrypted passphrase" + } + +#+end_src + +First, run the following commands to unblock the wifi card, determine its device name, and connect using the device name you received from =ifconfig -a=. In my case it's =wlp4s0= so I run the command like so: + +#+begin_src sh + + rfkill unblock all + ifconfig -a + wpa_supplicant -c wifi.conf -i wlp4s0 -B + +#+end_src + +#+begin_quote + +*NOTE:* If for any reason running =wpa_supplicant= fails, make sure to kill any background instances of it before trying to run it again because the old instances will block new runs from working. This wasted a couple hours of my time the first time I tried installing Guix! + +#+end_quote + +The last step to set up networking is to run =dhclient= to turn on DNS for your wifi connection: + +#+begin_src sh + + dhclient -v wlp4s0 + +#+end_src + +*** Setting Up Partitions + +Since we're installing on a ThinkPad with UEFI, follow the [[https://guix.gnu.org/manual/en/guix.html#Disk-Partitioning][instructions in the Guix manual]] for disk partitioning. The short of it is that you need to use =cfdisk= to create a partition in your free space: + +#+begin_src sh + + cfdisk /dev/nvme0n1 + +#+end_src + +Once you have your Linux root partition set up, you can enable LUKS to encrypt that partition by running the following commands (where =/dev/nvme0n1p5= is your root partition and =system-root= is an arbitrary label you'd like to use for it): + +#+begin_src sh + + cryptsetup luksFormat /dev/nvme0n1p5 + cryptsetup open --type luks /dev/nvme0n1p5 system-root + mkfs.ext4 -L system-root /dev/mapper/system-root + mount LABEL=system-root /mnt + +#+end_src + +Finally, make sure to mount your EFI partition to =/mnt/boot= so that the installer can install the bootloader. The Guix installation instructions obscure this step slightly so it's easy to miss: + +#+begin_src sh + + mkdir -p /mnt/boot/efi + mount /dev/ /mnt/boot/efi + +#+end_src + +Now your EFI and encrypted root filesystems are mounted so you can proceed with system installation. You must now set up the installation enviornment using =herd=: + +#+begin_src sh + + herd start cow-store /mnt + +#+end_src + +*** Initial System Installation + +If you've got a system configuration prepared already, you can use =git= to pull it down into the current directory (the one you're already in, not =/mnt=): + +#+begin_src sh + + git clone https://github.com/daviwil/dotfiles + +#+end_src + +One important step before you attempt system installation is to set up the =nonguix= channel so that the system can be installed from it. Once you've cloned your dotfiles repo, you can place your =channels.scm= file into the root user's =.config/guix= path and then run =guix pull= to activate it: + +#+begin_src sh + + mkdir -p ~/.config/guix + cp dotfiles/guix/channels.scm ~/.config/guix + guix pull + hash guix # This is necessary to ensure the updated profile path is active! + +#+end_src + +The pull operation may take a while depending on how recently you generated your installation USB image (if packages in the main Guix repository have been updated since then). + +Once your channels are set up, you will need to tweak your configuration to reflect the partition UUIDs and labels for the system that you are installing. To figure out the UUID of your encrypted root partition, you can use the following command: + +#+begin_src sh + + cryptsetup luksUUID /dev/ + +#+end_src + +#+begin_quote + +**TIP:** To make it easier to copy the UUID into your config file, you can switch to another tty using =Ctrl-Alt-F4= and press =Enter= to get to another root prompt. You can then switch back and forth between the previous TTY on =F3=. + +#+end_quote + +Now you can initialize your system using the following command: + +#+begin_src sh + + guix system -L ~/.dotfiles/.config/guix/systems init path/to/config.scm /mnt + +#+end_src + +This could take a while, so make sure your laptop is plugged in and let it run. If you see any errors during installation, don't fret, you can usually resume from where you left off because your Guix store will have any packages that were already installed. + +*** Initial System Setup + +Congrats! You now have a new Guix system installed, reboot now to complete the initial setup of your user account. + +The first thing you'll want to do when you land at the login prompt is login as =root= and immediately change the =root= and user passwords using =passwd= (there isn't a root password by default!): + +#+begin_src sh + + passwd # Set passwd for 'root' + passwd # Set password for your user account (no angle brackets) + +#+end_src + +Now log into your user account and clone your dotfiles repository. + +Since we used the =nonguix= channel to install the non-free Linux kernel, we'll need to make sure that channel is configured in our user account so that we have access to those packages the next time we =guix pull=. At the moment I just symlink the Guix config folder from my =.dotfiles= to =~/.config/guix=: + +#+begin_src sh + + ln -sf ~/.dotfiles/guix ~/.config/guix + +#+end_src + +Verify that your =channels.scm= file is in the target path (=~/.config/guix/channels.scm=) and then run =guix pull= to sync in the new channel. + +Now you can install the packages that you want to use for day-to-day activities. I separate different types of packages into individual manifest files and manage them with my =activate-profiles= script: + +#+begin_src sh + + activate-profiles desktop emacs + +#+end_src + +Now the packages for these manifests will be installed and usable. They can be updated in the future by using the =update-profiles= script. diff --git a/fschl/base-channels.scm b/fschl/base-channels.scm new file mode 100644 index 0000000..cd8ca06 --- /dev/null +++ b/fschl/base-channels.scm @@ -0,0 +1,37 @@ +;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there. + +(list (channel +; (name 'flat) +; (url "https://github.com/flatwhatson/guix-channel.git") +; (commit +; "7b8353ebbcf486e3344924d1cac0fa7ba47c371d") +; (introduction +; (make-channel-introduction +; "33f86a4b48205c0dc19d7c036c85393f0766f806" +; (openpgp-fingerprint +; "736A C00E 1254 378B A982 7AF6 9DBE 8265 81B6 4490")))) +; (channel + (name 'rde) + (url "https://git.sr.ht/~abcdw/rde") + (introduction + (make-channel-introduction + "257cebd587b66e4d865b3537a9a88cccd7107c95" + (openpgp-fingerprint + "2841 9AC6 5038 7440 C7E9 2FFA 2208 D209 58C1 DEB0")))) + (channel + (name 'nonguix) + (url "https://gitlab.com/nonguix/nonguix") + (introduction + (make-channel-introduction + "897c1a470da759236cc11798f4e0a5f7d4d59fbc" + (openpgp-fingerprint + "2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5")))) + (channel + (name 'guix) + (url "https://git.savannah.gnu.org/git/guix.git") + ;; (url "file:///home/daviwil/Projects/Code/guix")) + (introduction + (make-channel-introduction + "9edb3f66fd807b096b48283debdcddccfea34bad" + (openpgp-fingerprint + "BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA"))))) diff --git a/fschl/files/bash-prompt b/fschl/files/bash-prompt new file mode 100644 index 0000000..e951c41 --- /dev/null +++ b/fschl/files/bash-prompt @@ -0,0 +1,76 @@ +# -*- mode: sh; -*- +# Adapted from https://jdhao.github.io/2021/03/31/bash_prompt_config/ + +function fromhex() { + hex=$1 + if [[ $hex == "#"* ]]; then + hex=$(echo $1 | awk '{print substr($0,2)}') + fi + r=$(printf '0x%0.2s' "$hex") + g=$(printf '0x%0.2s' ${hex#??}) + b=$(printf '0x%0.2s' ${hex#????}) + echo -e `printf "%03d" "$(((r<75?0:(r-35)/40)*6*6+(g<75?0:(g-35)/40)*6+(b<75?0:(b-35)/40)+16))"` +} + +GRAY="\e[1;30m" +BOLD="\033[1m" +LT_CYAN="\e[1;36m" +LT_GREEN="\e[1;32m" +LT_RED="\e[1;31m" +GREEN="\e[0;32m" +PURPLE="\e[1;35m" +COLOR_NONE="\e[0m" + +# Detect whether the current directory is a git repository. +function is_git_repository() { + git branch > /dev/null 2>&1 +} + +function set_git_branch () { + # Note that for new repo without commit, git rev-parse --abbrev-ref HEAD + # will error out. + if git rev-parse --abbrev-ref HEAD > /dev/null 2>&1; then + BRANCH=" $(git rev-parse --abbrev-ref HEAD)" + else + BRANCH="" + fi +} + +function set_bash_prompt () { + PS1="\n" + + # Host and directory + PS1+="${LT_CYAN}\u@\h${COLOR_NONE} ${LT_RED}${BOLD}⛧${COLOR_NONE} " + PS1+="${GREEN}\w${COLOR_NONE} • " + + # Add git branch + if is_git_repository; then + set_git_branch + PS1+="${PURPLE}${BRANCH}${COLOR_NONE} • " + fi + + # Current time in 12 hour format + PS1+="${GREEN}$(date +'%r')${COLOR_NONE}\n" + + # Prompt character with color based on exit code + if [ "$?" == "0" ]; then + PS1+="${LT_GREEN}" + else + PS1+="${LT_RED}" + fi + PS1+="λ${COLOR_NONE}" + + # If inside vterm, add prompt metadata + if [[ "$INSIDE_EMACS" = 'vterm' ]]; then + PS1=$PS1' \[$(vterm_prompt_end)\]' + fi +} + +# Include common vterm functions +if [[ "$INSIDE_EMACS" = 'vterm' ]] \ + && [[ -n ${EMACS_VTERM_PATH} ]] \ + && [[ -f ${EMACS_VTERM_PATH}/etc/emacs-vterm-bash.sh ]]; then + source ${EMACS_VTERM_PATH}/etc/emacs-vterm-bash.sh +fi + +export PROMPT_COMMAND=set_bash_prompt diff --git a/fschl/files/inputrc b/fschl/files/inputrc new file mode 100644 index 0000000..44df6dd --- /dev/null +++ b/fschl/files/inputrc @@ -0,0 +1,7 @@ +set show-all-if-ambiguous on +set menu-complete-display-prefix on +TAB: menu-complete +set visible-stats on +set colored-stats on +set colored-completion-prefix on +set menu-complete-display-prefix on diff --git a/fschl/home-services/desktop.scm b/fschl/home-services/desktop.scm new file mode 100644 index 0000000..029dcec --- /dev/null +++ b/fschl/home-services/desktop.scm @@ -0,0 +1,133 @@ +(define-module (fschl home-services desktop) + #:use-module (gnu packages) + #:use-module (gnu packages linux) + #:use-module (gnu packages glib) +;; #:use-module (fschl packages fonts) + #:use-module (gnu services) + #:use-module (gnu home services) + #:use-module (gnu home services dotfiles) + #:use-module (gnu home services shepherd) + #:use-module (guix gexp) + + #:export (home-desktop-service-type)) + +(define (home-desktop-profile-service config) + (cons* + ;; NOTE: This is a very weird hack to get around an issue where "glib:bin" + ;; returns a newer version of glib than what most packages are using via the + ;; exported `glib' symbol. The "bin" output is needed to get the `gsettings' + ;; program to control GTK theme settings without a configuration file. + (list glib "bin") + (map specification->package+output + '(;; Sway setup + "sway" + "swayidle" + "swaylock" + "waybar" + "fuzzel" + "mako" + "gammastep" + "grimshot" ;; grimshot --notify copy area + "feh" + "network-manager-applet" + + ;; Compatibility for older Xorg applications + "xorg-server-xwayland" + + ;; Flatpak and XDG utilities + ;; "flatpak" + "xdg-desktop-portal" + "xdg-desktop-portal-gtk" + "xdg-desktop-portal-wlr" + "xdg-utils" ;; For xdg-open, etc + "xdg-dbus-proxy" + "shared-mime-info" + + ;; TODO: Remove when Emacs service is working + "emacs-next-pgtk" + + ;; Appearance + "matcha-theme" + "papirus-icon-theme" + "breeze-icons" ;; For KDE apps + + ;; Fonts + ;; "font-jost" + "font-iosevka-ss08" + "font-iosevka-aile" + "font-jetbrains-mono" + "font-google-noto" + "font-google-noto-emoji" + "font-liberation" + "font-awesome" + "gucharmap" + "fontmanager" + + ;; Browsers + "qtwayland@5" + "qutebrowser" + + ;; Authentication + "password-store" + "keepassxc" + + ;; Audio devices and media playback + "mpv" + "mpv-mpris" + "youtube-dl" + "playerctl" + "gstreamer" + "gst-plugins-base" + "gst-plugins-good" + "gst-plugins-bad" + "gst-plugins-ugly" + "gst-libav" + "alsa-utils" + "pavucontrol" + + ;; Graphics + "gimp" + + ;; PDF reader + "zathura" + "zathura-pdf-mupdf" + + ;; File syncing + "syncthing" + "syncthing-gtk" + "borg" + + ;; General utilities + "curl" + "wget" + "openssh" + "zip" + "unzip" + "trash-cli")))) + +(define (home-desktop-shepherd-services config) + (list + ;; TODO: Use built-in syncthing service + (shepherd-service + (provision '(syncthing)) + (documentation "Run and control syncthing.") + (start #~(make-forkexec-constructor '("syncthing" "-no-browser"))) + (stop #~(make-kill-destructor))))) + +(define (home-desktop-environment-variables config) + '(("_JAVA_AWT_WM_NONREPARENTING" . "1"))) + +(define home-desktop-service-type + (service-type (name 'home-desktop) + (description "My desktop environment service.") + (extensions + (list (service-extension + home-profile-service-type + home-desktop-profile-service) + (service-extension + home-shepherd-service-type + home-desktop-shepherd-services) + (service-extension + home-environment-variables-service-type + home-desktop-environment-variables))) + (default-value #f))) diff --git a/fschl/home-services/dotfiles/.config/dunst/dunstrc b/fschl/home-services/dotfiles/.config/dunst/dunstrc new file mode 100755 index 0000000..a3af259 --- /dev/null +++ b/fschl/home-services/dotfiles/.config/dunst/dunstrc @@ -0,0 +1,202 @@ +[global] + ### Display ### + monitor = 0 + + # The geometry of the window: + # [{width}]x{height}[+/-{x}+/-{y}] + geometry = "500x10-10+50" + + # Show how many messages are currently hidden (because of geometry). + indicate_hidden = yes + + # Shrink window if it's smaller than the width. Will be ignored if + # width is 0. + shrink = no + + # The transparency of the window. Range: [0; 100]. + transparency = 10 + + # The height of the entire notification. If the height is smaller + # than the font height and padding combined, it will be raised + # to the font height and padding. + notification_height = 0 + + # Draw a line of "separator_height" pixel height between two + # notifications. + # Set to 0 to disable. + separator_height = 1 + separator_color = frame + + # Padding between text and separator. + padding = 8 + + # Horizontal padding. + horizontal_padding = 8 + + # Defines width in pixels of frame around the notification window. + # Set to 0 to disable. + frame_width = 2 + + # Defines color of the frame around the notification window. + frame_color = "#89AAEB" + + # Sort messages by urgency. + sort = yes + + # Don't remove messages, if the user is idle (no mouse or keyboard input) + # for longer than idle_threshold seconds. + idle_threshold = 120 + + ### Text ### + + font = Iosevka Aile 12 + + # The spacing between lines. If the height is smaller than the + # font height, it will get raised to the font height. + line_height = 0 + markup = full + + # The format of the message. Possible variables are: + # %a appname + # %s summary + # %b body + # %i iconname (including its path) + # %I iconname (without its path) + # %p progress value if set ([ 0%] to [100%]) or nothing + # %n progress value if set without any extra characters + # %% Literal % + # Markup is allowed + format = "%s\n%b" + + # Alignment of message text. + # Possible values are "left", "center" and "right". + alignment = left + + # Show age of message if message is older than show_age_threshold + # seconds. + # Set to -1 to disable. + show_age_threshold = 60 + + # Split notifications into multiple lines if they don't fit into + # geometry. + word_wrap = yes + + # When word_wrap is set to no, specify where to make an ellipsis in long lines. + # Possible values are "start", "middle" and "end". + ellipsize = middle + + # Ignore newlines '\n' in notifications. + ignore_newline = no + + # Stack together notifications with the same content + stack_duplicates = true + + # Hide the count of stacked notifications with the same content + hide_duplicate_count = false + + # Display indicators for URLs (U) and actions (A). + show_indicators = yes + + ### Icons ### + + # Align icons left/right/off + icon_position = left + + # Scale larger icons down to this size, set to 0 to disable + max_icon_size = 88 + + # Paths to default icons. + icon_path = /home/daviwil/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/status/:/home/daviwil/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/devices/:/home/daviwil/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/emblems/ + + ### History ### + + # Should a notification popped up from history be sticky or timeout + # as if it would normally do. + sticky_history = no + + # Maximum amount of notifications kept in history + history_length = 20 + + ### Misc/Advanced ### + + # Browser for opening urls in context menu. + browser = qutebrowser + + # Always run rule-defined scripts, even if the notification is suppressed + always_run_script = true + + # Define the title of the windows spawned by dunst + title = Dunst + + # Define the class of the windows spawned by dunst + class = Dunst + + startup_notification = false + verbosity = mesg + + # Define the corner radius of the notification window + # in pixel size. If the radius is 0, you have no rounded + # corners. + # The radius will be automatically lowered if it exceeds half of the + # notification height to avoid clipping text and/or icons. + corner_radius = 4 + + mouse_left_click = close_current + mouse_middle_click = do_action + mouse_right_click = close_all + +# Experimental features that may or may not work correctly. Do not expect them +# to have a consistent behaviour across releases. +[experimental] + # Calculate the dpi to use on a per-monitor basis. + # If this setting is enabled the Xft.dpi value will be ignored and instead + # dunst will attempt to calculate an appropriate dpi value for each monitor + # using the resolution and physical size. This might be useful in setups + # where there are multiple screens with very different dpi values. + per_monitor_dpi = false + +[shortcuts] + + # Shortcuts are specified as [modifier+][modifier+]...key + # Available modifiers are "ctrl", "mod1" (the alt-key), "mod2", + # "mod3" and "mod4" (windows-key). + # Xev might be helpful to find names for keys. + + # Close notification. + #close = ctrl+space + + # Close all notifications. + #close_all = ctrl+shift+space + + # Redisplay last message(s). + # On the US keyboard layout "grave" is normally above TAB and left + # of "1". Make sure this key actually exists on your keyboard layout, + # e.g. check output of 'xmodmap -pke' + history = ctrl+grave + + # Context menu. + context = ctrl+shift+period + +[urgency_low] + # IMPORTANT: colors have to be defined in quotation marks. + # Otherwise the "#" and following would be interpreted as a comment. + background = "#222222" + foreground = "#888888" + timeout = 10 + # Icon for notifications with low urgency, uncomment to enable + #icon = /path/to/icon + +[urgency_normal] + background = "#1c1f26" + foreground = "#ffffff" + timeout = 10 + # Icon for notifications with normal urgency, uncomment to enable + #icon = /path/to/icon + +[urgency_critical] + background = "#900000" + foreground = "#ffffff" + frame_color = "#ff0000" + timeout = 0 + # Icon for notifications with critical urgency, uncomment to enable + #icon = /path/to/icon diff --git a/fschl/home-services/dotfiles/.config/polybar/config b/fschl/home-services/dotfiles/.config/polybar/config new file mode 100755 index 0000000..e9c2e2d --- /dev/null +++ b/fschl/home-services/dotfiles/.config/polybar/config @@ -0,0 +1,233 @@ +; Docs: https://github.com/polybar/polybar +;========================================================== + +[settings] +screenchange-reload = true + +[global/wm] +margin-top = 0 +margin-bottom = 0 + +[colors] +background = #f0232635 +background-alt = #576075 +foreground = #A6Accd +foreground-alt = #555 +primary = #ffb52a +secondary = #e60053 +alert = #bd2c40 +underline-1 = #c792ea + +[bar/panel] +width = 100% +height = 30 +offset-x = 0 +offset-y = 0 +fixed-center = true +enable-ipc = true + +background = ${colors.background} +foreground = ${colors.foreground} + +line-size = 2 +line-color = #f00 + +border-size = 0 +border-color = #00000000 + +padding-top = 5 +padding-left = 1 +padding-right = 1 + +module-margin = 1 + +font-0 = "Iosevka Aile:size=16:weight=light;2" +font-1 = "Font Awesome:size=12;2" +font-2 = "Material Icons:size=18;5" +font-3 = "Fira Mono:size=11;-3" + +modules-left = exwm exwm-path +modules-center = spotify +modules-right = telegram mu4e cpu temperature battery date + +tray-position = right +tray-padding = 2 +tray-maxsize = 28 + +cursor-click = pointer +cursor-scroll = ns-resize + +[bar/herbst] +width = 100% +height = 30 +offset-x = 0 +offset-y = 0 +fixed-center = true +enable-ipc = true + +background = ${colors.background} +foreground = ${colors.foreground} + +line-size = 2 +line-color = #f00 + +border-size = 0 +border-color = #00000000 + +padding-top = 5 +padding-left = 1 +padding-right = 1 + +module-margin = 1 + +font-0 = "Iosevka Aile:size=16:weight=semibold;2" +font-1 = "Font Awesome:size=12;2" +font-2 = "Material Icons:size=18;5" +font-3 = "Fira Mono:size=11;-3" + +modules-left = xworkspaces +modules-center = spotify +modules-right = cpu temperature battery date + +tray-position = right +tray-padding = 2 +tray-maxsize = 28 + +cursor-click = pointer +cursor-scroll = ns-resize + +[module/xworkspaces] +type = internal/xworkspaces +enable-click = false + +[module/exwm] +type = custom/ipc +hook-0 = emacsclient -e "(dw/polybar-exwm-workspace)" | sed -e 's/^"//' -e 's/"$//' +initial = 1 +format-underline = ${colors.underline-1} +format-background = ${colors.background-alt} +format-padding = 1 + +[module/exwm-path] +type = custom/ipc +hook-0 = emacsclient -e "(dw/polybar-exwm-workspace-path)" | sed -e 's/^"//' -e 's/"$//' +format-foreground = #f78c6c +initial = 1 + +[module/spotify] +type = custom/script +exec = ~/.config/polybar/player-status.sh +interval = 3 + +[module/mu4e] +type = custom/ipc +hook-0 = emacsclient -e '(dw/polybar-mail-count 500)' | sed -e 's/^"//' -e 's/"$//' +initial = 1 +format-underline = ${colors.underline-1} +click-left = emacsclient -e '(dw/go-to-inbox)' + +[module/telegram] +type = custom/ipc +hook-0 = emacsclient -e '(dw/polybar-telegram-chats)' | sed -e 's/^"//' -e 's/"$//' +format-padding = 3 +initial = 1 + +[module/xkeyboard] +type = internal/xkeyboard +blacklist-0 = num lock + +format-prefix-font = 1 +format-prefix-foreground = ${colors.foreground-alt} +format-prefix-underline = ${colors.underline-1} + +label-layout = %layout% +label-layout-underline = ${colors.underline-1} + +label-indicator-padding = 2 +label-indicator-margin = 1 +label-indicator-underline = ${colors.underline-1} + +[module/cpu] +type = internal/cpu +interval = 2 +format = 