My neurosys encompasses configuration for:
- NixOS (config)
- XMonad (config)
- Doom Emacs (config)
- Includes a neurosys module with utilities (e.g. remote deployment)
These define a my computing environment, which strives to be
- Effective: interactions with code/data should occur at the speed of thought.
- Extensible: otherwise, it’s not really mine.
- Long-lived: resist entropy/bitrot/bankruptcy until the end of the keyboard + screen era.
- Minimal: less is more for the base configuration - Nix enables project-level dependency management.
- Reproducible: enabled by the content-based hashes of Nix + Git. No fear of hitting un-recoverable states.
This literate org file, along with another for Doom, are the only two source files. The rest are generated via tangling.
If you are viewing this in a browser, consider opening the original org file in Emacs for the full experience. The HTML version is an imperfect rendering.
The name neurosys is used half-jokingly.
In no particular order, I found the following configurations especially helpful:
- jwiegley/nix-config: My local Nix configuration
- IvanMalison/dotfiles: Configuration files for XMonad, Emacs, NixOS, …
- willbush/system: System configuration
- malloc47/config: personal config files, cannibalized from a number o…
- hlissner/dotfiles: NixOS dotfiles for veteran bike shedders
- bauer: an Emacs+Nix IDE
- Nicolas Mattia – Nix: A Reproducible Setup for Linux and macOS
- malloc47/Migrating to NixOS
- My NixOS Desktop Flow - Christine Dodrill
- Choosing Software · Gwern.net
Followed: https://www.linode.com/docs/tools-reference/custom-kernels-distros/install-nixos-on-linode/
NIXOS_VERSION=20.03
nix-channel --add "https://nixos.org/channels/nixos-${NIXOS_VERSION}" nixos
nix-channel --add "https://github.com/rycee/home-manager/archive/release-${NIXOS_VERSION}.tar.gz" home-manager
nix-channel --add "https://nixos.org/channels/nixpkgs-${NIXOS_VERSION}" nixpkgs
nix-channel update
nix-channel --add https://github.com/rycee/home-manager/archive/master.tar.gz home-manager
nix-channel --add https://nixos.org/channels/nixos-unstable nixos
nix-channel --add "https://nixos.org/channels/nixpkgs-unstable" nixpkgs-unstable
nix-channel update
Don’t forget to clone recursively, because of the submodules:
git clone --recursive [email protected]:dangirsh/neurosys.git
Run neurosys/deploy-to-host, which will tangle this file and rsync
the results to a specified host.
HOST=$1
HOST_HOME=$2
rsync -Pav --rsync-path="sudo rsync" nixos/ $HOST:/etc/nixos/
rsync -Pav home/ $HOST:$HOST_HOME
My Doom Emacs Configuration is tracked in the home folder as a git submodule.
Until projects like nix-doom-emacs are stable, I’m not yet tracking my Emacs packages / config in Nix. For now, I track known-good commits via submodules / straight.el, and tie them to external dependencies (all managed by Nix) in this repo. If you know a better way to do this, please let me know.
Emacs itself is tracked via the emacs-overlay, which is version pinned via niv in sources.json. See the nix delaration.
I use XMonad as a window manager and minimal desktop environment. I don’t run any additional desktop environment (e.g. XFCE). Instead, I have the interface to the few things I need configured here in Haskell, or elsewhere (Emacs).
I’ve don’t use any system trays / status bars / panels, since the Emacs modeline is enough for me. This choice reduces the complexity of the XMonad configuration, and avoids depending on xmobar/polybar.
import XMonad
import XMonad.Hooks.SetWMName
import XMonad.Hooks.DynamicProperty (dynamicTitle)
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.UrgencyHook
import XMonad.Layout.Grid
import XMonad.Layout.Fullscreen
import XMonad.Layout.Minimize
import XMonad.Actions.Minimize
import XMonad.Layout.NoBorders
import XMonad.Layout.NoFrillsDecoration (noFrillsDeco, shrinkText,
inactiveBorderColor, inactiveColor, inactiveTextColor, activeBorderColor,
activeColor, activeTextColor, urgentBorderColor, urgentTextColor, decoHeight)
import XMonad.Layout.Tabbed (simpleTabbed)
import XMonad.Layout.ResizableTile
import XMonad.Layout.MultiColumns
import XMonad.Actions.CycleWS (toggleWS)
import XMonad.Actions.CycleRecentWS (cycleRecentWS)
import qualified XMonad.StackSet as W
import XMonad.Prompt
import XMonad.Prompt.AppLauncher as AL
import XMonad.Util.Run
import Data.Monoid
import Data.Default (def)
import Data.Map as M (fromList,union, Map())
import Data.List (isPrefixOf)
main :: IO ()
main = xmonad $
withUrgencyHook NoUrgencyHook $
ewmh $
fullscreenSupport def {
borderWidth = 1
, focusedBorderColor = blue
, terminal = "alacritty"
, layoutHook = smartBorders $ -- no borders for sole windows
noFrillsDeco shrinkText topBarTheme $ -- visually mark the focused window with a top bar
minimize
(ResizableTall 1 (3/100) (1/2) []
||| Mirror (ResizableTall 1 (3/100) (1/2) [])
||| multiCol [1] 1 0.01 (-0.5)
||| noBorders Full
||| simpleTabbed
||| Grid)
, workspaces = map show $ [1..9] ++ [0 :: Int]
, modMask = mod4Mask -- super key as modifier
, keys = \c -> myKeys c `M.union` keys def c
, manageHook = myManageHook <+> manageZoomHook
, handleEventHook = ewmhDesktopsEventHook <+> myHandleEventHook
, startupHook = do
-- http://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-SetWMName.html
setWMName "LG3D"
windows $ W.greedyView "1"
}
From https://xmonad.org/manpage.html#default-keyboard-bindings
source
binding | command |
---|---|
mod-shift-return | Launch terminal |
mod-p | Launch |
mod-shift-c | Close the focused window |
mod-space | Rotate through the available layout algorithms |
mod-shift-space | Reset the layouts on the current workspace to default |
mod-tab | Move focus to the next window |
mod-shift-tab | Move focus to the previous window |
mod-j | Move focus to the next window |
mod-k | Move focus to the previous window |
mod-return | Swap the focused window and the master window |
mod-shift-j | Swap the focused window with the next window |
mod-shift-k | Swap the focused window with the previous window |
mod-h | Shrink the master area |
mod-l | Expand the master area |
mod-t | Push window back into tiling |
mod-shift-q | Quit xmonad |
mod-shift-slash | Run xmessage with a summary of the default keybindings (useful for beginners) |
mod-[1..9] | Switch to workspace N |
mod-shift-[1..9] | Move client to workspace N |
mod-{w,e,r} | Switch to physical/Xinerama screens 1, 2, or 3 |
mod-shift-{w,e,r} | Move client to screen 1, 2, or 3 |
mod-button1 | Set the window to floating mode and move by dragging |
mod-button2 | Raise the window to the top of the stack |
mod-button3 | Set the window to floating mode and resize by dragging |
myKeys :: XConfig t -> M.Map (KeyMask, KeySym) (X ())
myKeys XConfig {modMask = m, terminal = term} = M.fromList $ [
((m .|. shiftMask .|. mod1Mask, xK_r), spawn "reboot")
, ((m .|. shiftMask .|. mod1Mask, xK_i), spawn "xmonad --recompile && xmonad --restart")
, ((m, xK_0), windows $ W.greedyView "0")
, ((m .|. shiftMask, xK_0), windows $ W.shift "0")
I currently use rofi to run programs or switch between open windows. It’s simple, fast, and supports fuzzy search.
, ((m, xK_p), spawn "rofi -show drun -modi drun -show-icons -matching fuzzy")
, ((m .|. shiftMask, xK_p), spawn "GDK_SCALE=2 rofi -show drun -modi drun -show-icons -matching fuzzy")
, ((m, xK_b), spawn "rofi -show window -show-icons -matching fuzzy")
-- Like M-y for helm-show-kill-ring in Emacs
, ((m, xK_y), spawn "rofi -modi \"clipboard:greenclip print\" -show clipboard -run-command '{cmd}'")
-- Text espander
, ((m .|. shiftMask .|. mod1Mask, xK_j), spawn "texpander.sh")
, ((m, xK_n), spawn "emacsclient -c")
, ((m .|. shiftMask .|. mod1Mask, xK_n), spawn "EMACS_NON_WORK_MODE=1 ~/scripts/run_emacs.sh")
, ((m .|. shiftMask, xK_n), spawn "~/scripts/run_emacs.sh")
, ((m .|. shiftMask .|. mod1Mask, xK_o), spawn "xtrlock -b")
An obvious missing default…
, ((m .|. shiftMask, xK_h), sendMessage MirrorShrink)
, ((m .|. shiftMask, xK_l), sendMessage MirrorExpand)
, ((m, xK_m), withFocused minimizeWindow)
, ((m .|. shiftMask, xK_m), withLastMinimized maximizeWindowAndFocus)
, ((m .|. shiftMask, xK_f), withFocused $ \f -> windows =<< appEndo `fmap` runQuery doFullFloat f)
Using mod+comma
quickly swap between workspaces is very handy.
, ((m, xK_comma), toggleWS)
Some layouts, like ResizableTall
, have a “master” area, with 1 window initially assigned there. These commands enable incrementing or decrementing that number.
They are bound by default to mod+
, and mod+.
, but mod+,
is much more useful for Workspace Swapping. Here I add Shift
to the defaults.
, ((m .|. shiftMask, xK_comma), sendMessage (IncMasterN 1))
, ((m .|. shiftMask, xK_period), sendMessage (IncMasterN (-1)))
- I find the default
mod+shift+c
binding to be clumbsy for killing windows. mod+q
is easier / more natural.- The default
mod+q
for killing XMonad is something I’ve never needed.
, ((m, xK_q), kill)
I don’t run a desktop environment, so the volume buttons on my keyboard don’t do anything by default.
, ((m .|. shiftMask, xK_Up), spawn "amixer -c 0 -q set Master 2dB+ unmute")
, ((m .|. shiftMask, xK_Down),spawn "amixer -c 0 -q set Master 2dB- unmute")
,((0, xK_Print), myScreenshot)
,((m, xK_Print), myScreenshotClipboard)
, ((m .|. shiftMask, xK_i), spawn "setxkbmap -option 'ctrl:nocaps' && xset r rate 160 80")
I have main.sh
and laptop.sh
symlinked to whatever the current xrandr scripts are for my desk / laptop.
, ((m, xK_s), spawn "/home/dan/.screenlayout/main.sh && feh --bg-fill --no-xinerama --randomize ~/Media/images/wallpaper/* &" )
, ((m .|. shiftMask, xK_s), spawn "/home/dan/.screenlayout/laptop.sh && feh --bg-fill --no-xinerama --randomize ~/Media/images/wallpaper/*" )
, ((m .|. shiftMask, xK_Tab), cycleRecentWS [xK_Super_L] xK_Tab xK_BackSpace)
The functionality here is a primary reason for choosing XMonad: a natural, keyboard-driven way for coordinating workspaces across multiple monitors. I’m genuinely curious to know if others have found something on-par/better elsewhere. Please contact me if you do.
- Bind
mod-{w, e, r}
to switch focus between monitors. - Bind
mod-shift-{w, e, r}
to move workspaces between monitors.
] ++
[((m .|. nilOrShift, key), screenWorkspace sc
>>= flip whenJust (windows . f))
| (key, sc) <- zip [xK_w, xK_r, xK_e] [0..]
, (f, nilOrShift) <- [(W.view, 0), (W.shift, shiftMask)]]
red = "#dc322f"
blue = "#268bd2"
yellow = "#b58900"
inactive = "#002b36"
active = blue
topBarTheme = def
{ inactiveBorderColor = inactive
, inactiveColor = inactive
, inactiveTextColor = inactive
, activeBorderColor = active
, activeColor = active
, activeTextColor = active
, urgentBorderColor = red
, urgentTextColor = yellow
, decoHeight = 10
}
myShellPrompt = def
{ font = "xft:Hack:pixelsize=30"
, promptBorderWidth = 1
, position = Top
, height = 42
, defaultText = []
}
manageZoomHook =
composeAll $
[ (className =? zoomClassName) <&&> shouldFloat <$> title --> doFloat,
(className =? zoomClassName) <&&> shouldSink <$> title --> doSink
]
where
zoomClassName = "zoom"
tileTitles =
[ "Zoom - Free Account", -- main window
"Zoom - Licensed Account", -- main window
"Zoom", -- meeting window on creation
"Zoom Meeting" -- meeting window shortly after creation
]
shouldFloat title = title `notElem` tileTitles
shouldSink title = title `elem` tileTitles
doSink = (ask >>= doF . W.sink) <+> doF W.swapDown
myHandleEventHook =
mconcat
[ dynamicTitle manageZoomHook,
handleEventHook defaultConfig
]
myManageHook = composeAll [ appName =? "Open Files" --> doFloat,
className =? "Zenity" --> doFloat]
myScreenshot = do
-- init takes care of the trailing newline character returned by date
date <- init <$> runProcessWithInput "date" ["+%Y-%m-%d-%H:%M:%S"] []
AL.launchApp myShellPrompt { defaultText = "~/screenshots/" ++ date ++ ".png"} "maim -s"
myScreenshotClipboard :: X ()
myScreenshotClipboard = spawn "maim -s | xclip -selection clipboard -t image/png"
This is currently only used by when on non-NixOS systems (e.g. Ubuntu).
#!/bin/bash
# Identify the home of our gtkrc file, important for setting styles of
# gtk-based applications
export GTK2_RC_FILES="$HOME/.gtkrc-2.0"
# enable for hidpi displays
export GDK_SCALE=1
setxkbmap -option 'ctrl:nocaps'
setxkbmap us -variant colemak_dh
# set keyboard rate
xset r rate 160 80
sudo timedatectl set-timezone Europe/Berlin
# sudo timedatectl set-timezone America/New_York
# sudo timedatectl set-timezone America/Los_Angeles
# Ensure Zoom output volume stays constant
# /home/dan/scripts/fuck_zoom.sh 100 &
# Clipboard manager (used with rofi)
greenclip daemon &
# Start espanso
# espanso restart # broken in Ubuntu 22
# set trackball rate
xinput --set-prop "Primax Kensington Eagle Trackball" "libinput Accel Speed" 1 || true
# eye breaks
# safeeyes &
# Wallpaper
feh --bg-fill --no-xinerama --randomize ~/Media/images/wallpaper/*
# xsetroot -solid black
# Config in ~/.config/redshift/redshift.conf
redshift &
picom -b
eval $(ssh-agent)
syncthing serve &
# Now, finally, start xmonad
exec xmonad
/usr/share/xsessions/xmonad.desktop
[Desktop Entry]
Name=XMonad
Comment=Lightweight tiling window manager
Exec=/home/dan/.xmonad/start-xmonad
Icon=xmonad.png
Type=XSession
{ config, pkgs, ... }:
let
sources = import ./nix/sources.nix;
# ghcide-nix = import sources."ghcide-nix" { };
in {
imports =
[ ./hardware-configuration.nix
./settings.nix
"${builtins.fetchTarball https://github.com/rycee/home-manager/archive/release-20.03.tar.gz}/nixos"
];
system.stateVersion = "20.03";
nixpkgs.config = {
# Allow unfree, which is required for some drivers.
allowUnfree = true;
};
nix = {
useSandbox = true;
autoOptimiseStore = true;
maxJobs = 3; # should be 1 per CPU logical core
binaryCaches = [
"https://cache.nixos.org/"
"https://ghcide-nix.cachix.org"
"https://hercules-ci.cachix.org"
"https://iohk.cachix.org"
"https://nix-tools.cachix.org"
];
binaryCachePublicKeys = [
"ghcide-nix.cachix.org-1:ibAY5FD+XWLzbLr8fxK6n8fL9zZe7jS+gYeyxyWYK5c="
"hercules-ci.cachix.org-1:ZZeDl9Va+xe9j+KqdzoBZMFJHVQ42Uu/c/1/KMC5Lw0="
"iohk.cachix.org-1:DpRUyj7h7V830dp/i6Nti+NEO2/nhblbov/8MW7Rqoo="
"nix-tools.cachix.org-1:ebBEBZLogLxcCvipq2MTvuHlP7ZRdkazFSQsbs0Px1A="
];
gc = {
automatic = true;
dates = "23:00";
options = "--delete-older-than 30d";
};
};
time.timeZone = "America/Los_Angeles";
boot = {
cleanTmpDir = true;
loader = {
timeout = 1; # Timeout (in seconds) until loader boots the default menu item.
grub = {
enable = true;
version = 2;
device = "nodev";
copyKernels = true;
fsIdentifier = "provided";
extraConfig = "serial; terminal_input serial; terminal_output serial";
};
systemd-boot.enable = false;
efi.canTouchEfiVariables = false;
};
};
networking.useDHCP = false;
networking.usePredictableInterfaceNames = false;
networking.interfaces.eth0.useDHCP = true;
networking.firewall.enable = false;
networking.firewall.allowPing = true;
# networking.networkmanager.enable = true;
networking.hostName = "nixos-dev";
networking.interfaces.eth0.tempAddress = "disabled";
services = {
xserver = {
enable = true;
layout = "us";
windowManager.xmonad = {
enable = true;
enableContribAndExtras = true;
extraPackages = haskellPackges: [
haskellPackges.xmonad-contrib
haskellPackges.xmonad-extras
haskellPackges.xmonad
];
};
displayManager = {
defaultSession = "none+xmonad";
lightdm.enable = true;
};
desktopManager.xterm.enable = false;
};
# https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/syncthing.nix
syncthing = {
enable = true;
openDefaultPorts = true;
user = "${config.settings.username}";
configDir = "/home/${config.settings.username}/.config/syncthing";
dataDir = "/home/${config.settings.username}/.local/share/syncthing";
declarative = {
devices = {
nixos-dev.id = "EEMRJQE-TBONTUL-UBGJ6FT-AAUS25K-COP3VHE-WERN7IN-PTNZ63Z-GZZX2AY";
x1carbon9.id = "EIZV5LR-F3JILKF-7MD5UMZ-KYRW37L-RVJ2WI4-7LQD7VC-U5BSEBD-YMGQPQ3";
pixel6-pro.id = "DISECZT-3ILXZ2S-B7BTYBI-R6KKLH2-YYIDZGD-4LP2OEF-NAURN57-ZPR6XAD";
};
folders = {
sync = rec {
id = "at23u-zmxto";
devices = [ "nixos-dev" "x1carbon9" "pixel6-pro"];
path = "/bkp/Sync";
watch = false;
rescanInterval = 3600 * 1;
type = "receiveonly"; # sendreceive
enable = true;
versioning.type = "simple";
versioning.params.keep = "5";
};
media = rec {
id = "media";
devices = [ "nixos-dev" "x1carbon9" "pixel6-pro"];
path = "/bkp/Media";
watch = false;
rescanInterval = 3600 * 6;
type = "receiveonly"; # sendreceive
enable = true;
versioning.type = "simple";
versioning.params.keep = "5";
};
work = rec {
id = "d7svv-zjsz2";
devices = [ "nixos-dev" "x1carbon9" "pixel6-pro"];
path = "/bkp/Work";
watch = false;
rescanInterval = 3600 * 6;
type = "receiveonly"; # sendreceive
enable = true;
versioning.type = "simple";
versioning.params.keep = "5";
};
};
};
};
nixpkgs/tarsnap.nix at master · NixOS/nixpkgs · GitHub
tarsnap.enable = true;
tarsnap.keyfile = "/bkp/Sync/keys/nixos-dev-tarsnap.key";
tarsnap.archives = {
main = {
keyfile = "/bkp/Sync/keys/nixos-dev-tarsnap.key";
directories = ["/bkp/Sync" "/bkp/Work" "/bkp/Media"];
};
};
};
# virtualisation.docker.enable = true;
environment.systemPackages = with pkgs; [
coreutils binutils
curl wget
zip unzip
git
killall
syncthing-cli
sshfs
mtr # traceroute
sysstat
htop
];
fonts = {
enableFontDir = true;
enableGhostscriptFonts = true;
fonts = with pkgs; [
corefonts
hack-font
];
};
security.sudo.wheelNeedsPassword = false;
users.mutableUsers = false;
users.extraUsers.${config.settings.username} = {
isNormalUser = true;
uid = 1000;
createHome = true;
home = "/home/${config.settings.username}";
description = "${config.settings.name}";
extraGroups = [
"audio"
"networkmanager"
"systemd-journal"
"vboxusers"
"video"
"wheel"
];
};
home-manager.users.dan = import ./home.nix ;
services.openssh = {
enable = true;
forwardX11 = true;
permitRootLogin = "without-password";
passwordAuthentication = false;
};
users.users.${config.settings.username}.openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+yJ5sv7iO9PBuozfmitR0JJfqDsJ7w+rlryq5CwdatO3tkRdR5dMYdFTFCeHbmeakPTC/uys08fziEUXh3DL206jDKQEMBoMGXNowZHyYzr25nIogHbveqeNTgP8jsTw5uBaJu8LFzHHey4Sw9WlRrvIqguUT5jB3omZh8yDWcxTrTJlTsN2TM3HILvirfVwBkD2uNTDdd5LplbZhx6x87VCs6ZNYhBjJ4CPcO4zTQuEdyyxUHEgtMkYgrS4Jb/Kl6Tleftlh55E74SZ3XXnw3lWdH9ra8ewH265iqNr/RwysagnalslBZDLl8yJcrMsCVi4tPrZZc4vaeCsIWK4X dan@x1carbon"
];
programs.ssh.startAgent = true;
# programs.x2goserver.enable = true;
}
{ config, pkgs, ... }:
let
homeDir = builtins.getEnv "HOME";
syncDir = builtins.toPath("${homeDir}/Sync");
sources = import ./nix/sources.nix;
nixos20_03 = import sources."nixpkgs-20.03" { };
emacs-overlay = import (import ./nix/sources.nix)."emacs-overlay";
in {
imports = [
./settings.nix
];
home.stateVersion = "20.03";
nixpkgs.config = {
allowUnfree = true;
packageOverrides = pkgs: { stable = nixos20_03; };
};
nixpkgs.overlays = [ emacs-overlay ];
home.sessionVariables = {
EDITOR = "emacsclient --create-frame --alternate-editor emacs";
PASSWORD_STORE_DIR = "${syncDir}/.password-store";
GNUPGHOME = "${syncDir}/.gnupg/";
# GTK2_RC_FILES="${homeDir}/.gtkrc-2.0";
# https://github.com/xmonad/xmonad/issues/126
_JAVA_AWT_WM_NONREPARENTING = "1";
};
# gtk = {
# enable = true;
# iconTheme = {
# name = "Adwaita";
# package = pkgs.gnome3.adwaita-icon-theme;
# };
# theme = {
# name = "Adwaita-dark";
# package = pkgs.gnome3.gnome_themes_standard;
# };
# };
xdg.enable = true;
home.packages = with pkgs; [
rofi
gnupg
(pass.withExtensions (exts: [
exts.pass-otp
exts.pass-genphrase
]))
xtrlock-pam # screen locking
maim # screenshots
rofi-pass # interface to password manager
xclip # programmatic access to clipbaord
arandr # gui for xrandr (monitor layout)
# direnv
# Upstream failing :(
# julia_13
## Doom dependencies
(ripgrep.override {withPCRE2 = true;})
gnutls # for TLS connectivity
## Optional dependencies
fd # faster projectile indexing
imagemagick # for image-dired
pinentry_emacs
## Module dependencies
# :tools lookup & :lang org +roam
sqlite
# :lang latex & :lang org (latex previews)
texlive.combined.scheme-tetex
firefox-beta-bin
];
programs = {
# Let Home Manager install and manage itself.
home-manager.enable = true;
emacs = {
enable = true;
# Compile with imagemagick support so I can resize images.
package = pkgs.emacsGit.override { inherit (pkgs) imagemagick; };
};
bash = {
enable = true;
historyFile = "${syncDir}/.config/bash/.bash_history";
# FIXME: Document and reduce these
shellOptions = [
"autocd" "cdspell" "dirspell" "globstar" # bash >= 4
"cmdhist" "nocaseglob" "histappend" "extglob"];
# TODO: Test this
# https://github.com/akermu/emacs-libvterm#directory-tracking-and-prompt-tracking
initExtra = [
''
vterm_prompt_end(){
vterm_printf \"51;A$(whoami)@$(hostname):$(pwd)\"
}
PS1=$PS1'\\[$(vterm_prompt_end)\\]'
''
]
};
git = {
enable = true;
userName = "${config.settings.name}";
userEmail = "${config.settings.email}";
};
# direnv.enable = true;
ssh = {
enable = true;
controlMaster = "auto";
controlPath = "/tmp/ssh-%u-%r@%h:%p";
controlPersist = "1800";
forwardAgent = true;
serverAliveInterval = 60;
hashKnownHosts = true;
userKnownHostsFile = "${homeDir}/.ssh/known_hosts";
matchBlocks = {
droplet = {
hostname = "45.55.5.197";
identityFile = "${homeDir}/.ssh/id_rsa";
user = "dgirsh";
};
dangirsh = {
host = "dangirsh.org";
hostname = "ssh.phx.nearlyfreespeech.net";
identityFile = "${homeDir}/.ssh/id_rsa";
user = "dangirsh_dangirsh";
};
nixos-dev = {
hostname = "45.79.58.229";
identityFile = "${homeDir}/.ssh/id_rsa";
user = "dan";
};
};
};
};
services = {
emacs.enable = true;
# redshift = {
# enable = true;
# latitude = "33";
# longitude = "-97";
# temperature.day = 6500;
# temperature.night = 3000;
# };
# https://www.reddit.com/r/emacsporn/comments/euf7m8/doomoutrunelectric_theme_xmonad_nixos/
# https://github.com/willbush/system/blob/371cfa9933f24bca585a3c6c952c41c864d97aa0/nixos/home.nix#L178
# compton = {
# enable = true;
# fade = true;
# backend = "xrender";
# fadeDelta = 1;
# # I only want transparency for a couple of applications.
# opacityRule = [
# "90:class_g ?= 'emacs' && focused"
# "75:class_g ?= 'emacs' && !focused"
# "90:class_g ?= 'alacritty' && focused"
# "75:class_g ?= 'alacritty' && !focused"
# ];
# };
# lorri.enable = true;
};
}
- [ ] xtrlock-pam
- [ ] maim
- [ ] rofi-pass (see Floating Emacs popup for quick commands)
- [ ] xclip
- [ ] arandr
- keyboard config: currently requires xset & setxbmap
- [ ] Messenging
- unified messenger (if it exists) for dealing with the madness of:
- sms
- signal
- fb
keybase- slack
- irc
- riot
- To try
- [X] pidgin - just bad. no hidpi, things like signal don’t sync with mobile state, clunky ui.
- Otherwise:
- Browser tabs for everything sans signal
- Signal-destop
- maybe slack desktop
- caprine for fb is nice on ubuntu
- unified messenger (if it exists) for dealing with the madness of:
{config, pkgs, lib, ...}:
with lib;
{
options = {
settings = {
name = mkOption {
default = "Dan Girshovich";
type = with types; uniq str;
};
username = mkOption {
default = "dan";
type = with types; uniq str;
};
email = mkOption {
default = "[email protected]";
type = with types; uniq str;
};
};
};
}
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, ... }:
{
imports =
[ <nixpkgs/nixos/modules/profiles/qemu-guest.nix>
];
boot.initrd.availableKernelModules = [ "virtio_pci" "ahci" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
nix.maxJobs = lib.mkDefault 1;
From Chapter 8. File Systems: “Mount points are created automatically if they don’t already exist.”
fileSystems."/" =
{ device = "/dev/disk/by-uuid/bf38bdde-34dd-4d57-9bfe-07de465f0f29";
fsType = "ext4";
};
# Linode Volume "bkp". Targetted by syncthing.
fileSystems."/bkp" =
{ device = "/dev/disk/by-id/scsi-0Linode_Volume_bkp";
fsType = "ext4";
};
swapDevices =
[ { device = "/dev/disk/by-uuid/7596d600-d2c6-4d77-b138-7f595283af00"; }
];
}
These are generated via niv.
{
"emacs-overlay": {
"branch": "master",
"description": "Bleeding edge emacs overlay [maintainer=@adisbladis] ",
"homepage": "",
"owner": "nix-community",
"repo": "emacs-overlay",
"rev": "0feda8b31b52f3ea008555dfe79dba3989d3e585",
"sha256": "1ijr9pl0czzbgj35vj8kq4xvcana6w24ljcmzriz7cyxln4pgvln",
"type": "tarball",
"url": "https://github.com/nix-community/emacs-overlay/archive/0feda8b31b52f3ea008555dfe79dba3989d3e585.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"ghcide-nix": {
"branch": "master",
"description": "Nix installation for ghcide",
"homepage": "https://github.com/digital-asset/ghcide",
"owner": "cachix",
"repo": "ghcide-nix",
"rev": "f940ec611cc6914693874ee5e024eba921cab19e",
"sha256": "0vri0rivdzjvxrh6lzlwwkh8kzxsn82jp1c2w5rqzhp87y6g2k8z",
"type": "tarball",
"url": "https://github.com/cachix/ghcide-nix/archive/f940ec611cc6914693874ee5e024eba921cab19e.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs-20.03": {
"branch": "release-20.03",
"description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
"homepage": "https://github.com/NixOS/nixpkgs",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7829e5791ba1f6e6dbddbb9b43dda72024dd2bd1",
"sha256": "0hs9swpz0kibjc8l3nx4m10kig1fcjiyy35qy2zgzm0a33pj114w",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/7829e5791ba1f6e6dbddbb9b43dda72024dd2bd1.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}
# This file has been generated by Niv.
# A record, from name to path, of the third-party packages
with rec
{
pkgs =
if hasNixpkgsPath
then
if hasThisAsNixpkgsPath
then import (builtins_fetchTarball { inherit (sources_nixpkgs) url sha256; }) {}
else import <nixpkgs> {}
else
import (builtins_fetchTarball { inherit (sources_nixpkgs) url sha256; }) {};
sources_nixpkgs =
if builtins.hasAttr "nixpkgs" sources
then sources.nixpkgs
else abort
''
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
add a package called "nixpkgs" to your sources.json.
'';
# fetchTarball version that is compatible between all the versions of Nix
builtins_fetchTarball =
{ url, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchTarball;
in
if lessThan nixVersion "1.12" then
fetchTarball { inherit url; }
else
fetchTarball attrs;
# fetchurl version that is compatible between all the versions of Nix
builtins_fetchurl =
{ url, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchurl;
in
if lessThan nixVersion "1.12" then
fetchurl { inherit url; }
else
fetchurl attrs;
# A wrapper around pkgs.fetchzip that has inspectable arguments,
# annoyingly this means we have to specify them
fetchzip = { url, sha256 }@attrs: pkgs.fetchzip attrs;
# A wrapper around pkgs.fetchurl that has inspectable arguments,
# annoyingly this means we have to specify them
fetchurl = { url, sha256 }@attrs: pkgs.fetchurl attrs;
hasNixpkgsPath = (builtins.tryEval <nixpkgs>).success;
hasThisAsNixpkgsPath =
(builtins.tryEval <nixpkgs>).success && <nixpkgs> == ./.;
sources = builtins.fromJSON (builtins.readFile ./sources.json);
mapAttrs = builtins.mapAttrs or
(f: set: with builtins;
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)));
# borrowed from nixpkgs
functionArgs = f: f.__functionArgs or (builtins.functionArgs f);
callFunctionWith = autoArgs: f: args:
let auto = builtins.intersectAttrs (functionArgs f) autoArgs;
in f (auto // args);
getFetcher = spec:
let fetcherName =
if builtins.hasAttr "type" spec
then builtins.getAttr "type" spec
else "builtin-tarball";
in builtins.getAttr fetcherName {
"tarball" = fetchzip;
"builtin-tarball" = builtins_fetchTarball;
"file" = fetchurl;
"builtin-url" = builtins_fetchurl;
};
};
# NOTE: spec must _not_ have an "outPath" attribute
mapAttrs (_: spec:
if builtins.hasAttr "outPath" spec
then abort
"The values in sources.json should not have an 'outPath' attribute"
else
if builtins.hasAttr "url" spec && builtins.hasAttr "sha256" spec
then
spec //
{ outPath = callFunctionWith spec (getFetcher spec) { }; }
else spec
) sources
It’s usually most convenient to use/implement functions in Emacs than other tools. This was a huge draw towards EXWM, and I got used to that workflow.
For example, generating / getting passwords stored in pass
has a nice Emacs interface. Currently, this often means switching from Firefox to Emacs to run a command, then back to Firefox. In this situation, a common solution seems to be eschewing Emacs for things like rofi
(e.g. rofi-pass
).
However, if I could popup a fast, floating Emacs window (similar to Rofi), I’d be able to leverage Elisp for most tasks like this. This might fully obviate Rofi
and the XMonad prompt.
The floating window would default to a counsel-M-x
fuzzy search over all incremental commands, and be bound to s-x
in XMonad.
Examples:
- screenshotting
- pass interface
- redshift / brightness controls
- (maybe) finding windows / launching programs
- clipboard management (helm kill ring)
As a small added benefit, I’d have the full Emacs bindings available in the input area.
I’m occasionally lucky enough to plug into a 4k screen, which is not yet a seamless experience in linux.
For now I manually do the following on HiDPI screens:
export GDK_SCALE=2
and change layout.css.devPixelsPerPx
in Firefox about:config from -1 to 2.
tweak font size in Firefox and Emacs.
Per keybase/client#5797 increase font size in client, edit the ExecStart line to have --force-device-scale-factor=2
. Then, reload with:
systemctl --user daemon-reload
systemctl --user restart keybase.gui.service
In EXWM, I used the simulation keys to have consistent Emacs copy/paste bindings everywhere. Need a solution for XMonad. Setting the GTK bindings to “emacs” didn’t seem to affect for Firefox, which is (by far) my primary non-Emacs window.
Ideally, XMonad could manage all windows, including Emacs windows.
Possible solutions:
- frames-only-mode
- frame-mode
These seemed to cause more problems than they fixed for me.
Even with org-src-preserve-indentation
set to t
, files like home.nix aren’t properly indented. This is because they are split across several org blocks, and in each on I use the nix-mode
auto-indent to fixup the indentation within the block. This removes the leading whitespace, so each block is tangled without leading indentation. Thankfully, Nix doesn’t care, so this is purely for the aesthetics of the generated files.
Quickfix is to auto-indent the tangled files, then detangle.
Using noweb references seems to be the best option: https://orgmode.org/manual/Noweb-Reference-Syntax.html. See “This feature can also be used for management of indentation in exported code snippets”.