Hi there! That’s my dotfiles.
This repository contains configuration for three hosts:
- omicron — my main laptop which runs NixOS
- pie — my home server RPi running NixOS (see pie.org)
- AlexeyShmalko — my work laptop running Ubuntu (ugh, corporate policies) with home-manager on top
Most of config files are generated by org-babel from org files in this repository (yes, including this very same README.org
). That’s literate programming applied to dotfiles.
This file contains NixOS configuration for omicron, and common home-manager configuration between omicron and AlexeyShmalko. (I try to keep repetition to minimum, but some is inevitable.)
work.org file contains home-manager configuration specific for AlexeyShmalko.
pie.org is a separate NixOS config for pie host.
For Emacs configuration, see emacs.org.
To generate actual nix files, you can open this file in Emacs, and execute M-x org-babel-tangle
. Or from command line with the following command.
emacs README.org --batch -f org-babel-tangle
Note that you need to patch org-babel to correctly generate configs. See Patch ob-tangle in Emacs config.
I keep generated files in sync with org files (so this repo is a valid Nix Flake), but they are not worth looking at—you’ll have much better time reading this doc instead.
Pieces not (yet) covered in org files are:
- awesome wm configuration at
.config/awesome/
- scripts at
bin/
This repository is nix flakes–compatible.
The following goes to flake.nix
file.
#
# This file is auto-generated from "README.org"
#
{
description = "rasendubi's packages and NixOS/home-manager configurations";
inputs = {
nixpkgs = {
type = "github";
owner = "NixOS";
repo = "nixpkgs-channels";
ref = "nixpkgs-unstable";
};
<<flake-inputs>>
};
outputs = { self, ... }@inputs:
let
# Flakes are evaluated hermetically, thus are unable to access
# host environment (including looking up current system).
#
# That's why flakes must explicitly export sets for each system
# supported.
systems = ["x86_64-linux" "aarch64-linux"];
# genAttrs applies f to all elements of a list of strings, and
# returns an attrset { name -> result }
#
# Useful for generating sets for all systems or hosts.
genAttrs = list: f: inputs.nixpkgs.lib.genAttrs list f;
# Generate pkgs set for each system. This takes into account my
# nixpkgs config (allowUnfree) and my overlays.
pkgsBySystem =
let mkPkgs = system: import inputs.nixpkgs {
inherit system;
overlays = self.overlays.${system};
config = { allowUnfree = true; };
};
in genAttrs systems mkPkgs;
# genHosts takes an attrset { name -> options } and calls mkHost
# with options+name. The result is accumulated into an attrset
# { name -> result }.
#
# Used in NixOS and Home Manager configurations.
genHosts = hosts: mkHost:
genAttrs (builtins.attrNames hosts) (name: mkHost ({ inherit name; } // hosts.${name}));
# merges a list of attrsets into a single attrset
mergeSections = inputs.nixpkgs.lib.foldr inputs.nixpkgs.lib.mergeAttrs {};
in mergeSections [
<<flake-outputs-nixos>>
<<flake-outputs-home-manager>>
<<flake-outputs-packages>>
<<flake-outputs-overlays>>
];
}
Nix flakes are still an experimental feature, so you need the following in NixOS configuration to enable it.
{
nix = {
package = pkgs.nixFlakes;
extraOptions = ''
experimental-features = nix-command flakes
'';
};
}
For non-NixOS system, install nixFlakes
and put the following into ~/.config/nix/nix.conf
.
experimental-features = nix-command flakes
Expose NixOS configurations.
(let
nixosHosts = {
omicron = { system = "x86_64-linux"; config = ./nixos-config.nix; };
# pie uses a separate config as it is very different
# from other hosts.
pie = { system = "aarch64-linux"; config = ./pie.nix; };
};
mkNixosConfiguration = { name, system, config }:
let pkgs = pkgsBySystem.${system};
in inputs.nixpkgs.lib.nixosSystem {
inherit system;
modules = [
{ nixpkgs = { inherit pkgs; }; }
(import config)
];
specialArgs = { inherit name inputs; };
};
in {
nixosConfigurations = genHosts nixosHosts mkNixosConfiguration;
})
Add home-manager to flake inputs.
home-manager = {
type = "github";
owner = "rycee";
repo = "home-manager";
ref = "bqv-flakes";
inputs.nixpkgs.follows = "nixpkgs";
};
Expose home-manager configurations.
(let
homeManagerHosts = {
AlexeyShmalko = {
system = "x86_64-linux";
config = ./work.nix;
username = "rasen";
homeDirectory = "/home/rasen";
};
};
mkHomeManagerConfiguration = { system, name, config, username, homeDirectory }:
let pkgs = pkgsBySystem.${system};
in inputs.home-manager.lib.homeManagerConfiguration {
inherit system pkgs username homeDirectory;
configuration = { ... }: {
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = self.overlays.${system};
imports = [
self.lib.home-manager-common
(import config)
];
};
};
in {
# Re-export common home-manager configuration to be reused between
# NixOS module and standalone home-manager config.
lib.home-manager-common = { lib, pkgs, config, ... }: {
imports = [
<<home-manager-section>>
];
};
homeManagerConfigurations = genHosts homeManagerHosts mkHomeManagerConfiguration;
})
Integrate home-manager module into NixOS.
{
imports = [inputs.home-manager.nixosModules.home-manager];
home-manager = {
useUserPackages = true;
useGlobalPkgs = true;
users.rasen = inputs.self.lib.home-manager-common;
};
}
Generate packages set for each supported system.
(let
mkPackages = system:
let
pkgs = pkgsBySystem.${system};
in
mergeSections [
<<flake-packages>>
];
in {
packages = genAttrs systems mkPackages;
})
Generate overlays for all supported systems.
(let
mkOverlays = system: [
# mix-in all local packages, so they are available as pkgs.${packages-name}
(final: prev: self.packages.${system})
<<flake-overlays>>
];
in {
overlays = genAttrs systems mkOverlays;
})
<<flake-overlays>>
are defined elsewhere.
I’m a NixOS user. What’s cool about it is that I can describe all my system configuration in one file (almost). I can execute a single command and have a system with the same software, system settings, etc.
An outline of configuration looks like this:
#
# This file is auto-generated from "README.org"
#
{ name, config, pkgs, lib, inputs, ... }:
let
machine-config = lib.getAttr name {
omicron = [
<<machine-omicron>>
];
};
in
{
imports = [
{
nixpkgs.config.allowUnfree = true;
# The NixOS release to be compatible with for stateful data such as databases.
system.stateVersion = "19.09";
}
<<nixos-section>>
] ++ machine-config;
}
This <<nixos-section>>
is replaced by other parts of this doc.
{
# for compatibility with nix-shell, nix-build, etc.
environment.etc.nixpkgs.source = inputs.nixpkgs;
nix.nixPath = ["nixpkgs=/etc/nixpkgs"];
# register self and nixpkgs as flakes for quick access
nix.registry = {
self.flake = inputs.self;
nixpkgs = {
from = { id = "nixpkgs"; type = "indirect"; };
flake = inputs.nixpkgs;
};
};
}
Same but for Home Manager–managed host.
{
home.file."nixpkgs".source = inputs.nixpkgs;
systemd.user.sessionVariables.NIX_PATH = lib.mkForce "nixpkgs=$HOME/nixpkgs\${NIX_PATH:+:}$NIX_PATH";
xdg.configFile."nix/registry.json".text = builtins.toJSON {
version = 2;
flakes = [
{
from = { id = "self"; type = "indirect"; };
to = ({
type = "path";
path = inputs.self.outPath;
} // lib.filterAttrs
(n: v: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash")
inputs.self);
}
{
from = { id = "nixpkgs"; type = "indirect"; };
to = ({
type = "path";
path = inputs.nixpkgs.outPath;
} // lib.filterAttrs
(n: v: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash")
inputs.nixpkgs);
}
];
};
}
I’m the only user of the system:
{
users.extraUsers.rasen = {
isNormalUser = true;
uid = 1000;
extraGroups = [ "users" "wheel" "input" ];
initialPassword = "HelloWorld";
};
nix.trustedUsers = ["rasen"];
}
initialPassword
is used only first time when user is created. It must be changed as soon as possible with passwd
.
I currently have only one machine.
This is my small Dell XPS 13.
{
imports = [
(import "${inputs.nixos-hardware}/dell/xps/13-9360")
inputs.nixpkgs.nixosModules.notDetected
];
boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
nix.maxJobs = lib.mkDefault 4;
# powerManagement.cpuFreqGovernor = "powersave";
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
}
inputs.nixos-hardware
comes from the following flake input.
nixos-hardware = {
type = "github";
owner = "NixOS";
repo = "nixos-hardware";
flake = false;
};
LVM on LUKS setup for disk encryption.
{
boot.initrd.luks.devices = {
root = {
device = "/dev/disk/by-uuid/8b591c68-48cb-49f0-b4b5-2cdf14d583dc";
preLVM = true;
};
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/BA72-5382";
fsType = "vfat";
};
fileSystems."/" = {
device = "/dev/disk/by-uuid/434a4977-ea2c-44c0-b363-e7cf6e947f00";
fsType = "ext4";
options = [ "noatime" "nodiratime" "discard" ];
};
fileSystems."/home" = {
device = "/dev/disk/by-uuid/8bfa73e5-c2f1-424e-9f5c-efb97090caf9";
fsType = "ext4";
options = [ "noatime" "nodiratime" "discard" ];
};
swapDevices = [
{ device = "/dev/disk/by-uuid/26a19f99-4f3a-4bd5-b2ed-359bed344b1e"; }
];
}
Clickpad:
{
services.xserver.libinput = {
enable = true;
accelSpeed = "0.7";
};
}
I have a bluetooth headset, so this enables bluetooth audio in NixOS.
{
hardware.bluetooth.enable = true;
hardware.pulseaudio = {
enable = true;
# NixOS allows either a lightweight build (default) or full build
# of PulseAudio to be installed. Only the full build has
# Bluetooth support, so it must be selected here.
package = pkgs.pulseaudioFull;
};
}
Install ntfs-3g to mount ntfs volumes in read-write mode.
{
environment.systemPackages = [
pkgs.ntfs3g
];
}
As a responsible NixOS user, I refuse to install software blindly with sudo make install
. That’s why I must write my own nix-expressions.
Build all packages in sandbox:
{
nix.useSandbox = true;
}
This is an integration package for Razer Naga Chroma and my awesome wm setup.
{
naga = pkgs.callPackage ./naga { };
}
Go install it right away:
{
home.packages = [ pkgs.naga ];
}
I like the following settings more than defaults. I also need a custom four-style family because Emacs confuses regular/medium weight otherwise. Use link specified in requireFile
to download the font.
{
# note it's a new attribute and does not override old one
input-mono = (pkgs.input-fonts.overrideAttrs (old: {
src = pkgs.requireFile {
name = "Input-Font.zip";
url = "https://input.fontbureau.com/download/index.html?customize&fontSelection=fourStyleFamily®ular=InputMonoNarrow-Regular&italic=InputMonoNarrow-Italic&bold=InputMonoNarrow-Bold&boldItalic=InputMonoNarrow-BoldItalic&a=0&g=0&i=topserif&l=serifs_round&zero=0&asterisk=height&braces=straight&preset=default&line-height=1.2&email=";
sha256 = "0nn41w2b6jvsbr3r4lfy4p8w2ssjmgdjzd1pbj7p0vmawjpvx2w8";
};
outputHash = "1w2i660dg04nyc6fc6r6sd3pw53h8dh8yx4iy6ccpii9gwjl9val";
}));
}
My bank uses a two-part websigner. The first part is a browser extension (does not require additional setup) and the second part is a native host application companion (it is installed here).
Pack native messaging host:
(let
websigner =
{ stdenv
, fetchurl
, autoPatchelfHook
, gtk2
, glib
, pcsclite
}:
stdenv.mkDerivation {
pname = "procreditbank-websigner";
version = "2020-01-20";
src = fetchurl {
url = "https://ibank.procreditbank.com.ua/websigner-linux.bin";
sha256 = "1bm88jg7nhgrmc0q5hv35hgv4nc0d15ihl0acrhf6x5f7wv4pszv";
};
nativeBuildInputs = [ autoPatchelfHook ];
buildInputs = [ gtk2 glib pcsclite ];
unpackCmd = ''
sh $src --extract
'';
dontConfigure = true;
dontBuild = true;
installPhase = ''
mkdir -p $out/bin
mkdir -p $out/lib/websigner/hosts/firefox
mkdir -p $out/lib/websigner/hosts/chromium
install -m 555 x86_64-linux/npwebsigner.so $out/lib/websigner
install -m 777 x86_64-linux/nmwebsigner $out/lib/websigner
sed "s|PLUGIN_PATH|$out/lib/websigner/nmwebsigner|" com.bifit.websigner-mozilla.json > $out/lib/websigner/hosts/firefox/com.bifit.websigner.json
sed "s|PLUGIN_PATH|$out/lib/websigner/nmwebsigner|" com.bifit.websigner-chrome.json > $out/lib/websigner/hosts/chromium/com.bifit.websigner.json
mkdir -p $out/lib/mozilla/native-messaging-hosts
ln -s $out/lib/websigner/hosts/firefox/*.json $out/lib/mozilla/native-messaging-hosts
'';
};
in {
procreditbank-websigner = pkgs.callPackage websigner { };
})
Override Firefox to use websigner.
(final: prev: {
firefox = prev.firefox.override {
extraNativeMessagingHosts = [ final.procreditbank-websigner ];
};
})
I use emacs-27 from emacs-overlay.
emacs-overlay = {
type = "github";
owner = "nix-community";
repo = "emacs-overlay";
};
Use overlay (goes to flake-overlays
section).
inputs.emacs-overlay.overlay
Expose Emacs with my packages as a top-level package.
(let
emacs-base = pkgs.emacsGit;
# emacs = pkgs.emacsUnstable;
# emacs = pkgs.emacs.override {
# # Build emacs with proper imagemagick support.
# # See https://github.com/NixOS/nixpkgs/issues/70631#issuecomment-570085306
# imagemagick = pkgs.imagemagickBig;
# };
emacs-packages = (epkgs:
(with epkgs.melpaPackages; [
aggressive-indent
atomic-chrome
avy
beacon
blacken
cider
clojure-mode
cmake-mode
color-identifiers-mode
company
company-box
company-lsp
company-org-roam
counsel
counsel-projectile
diff-hl
diminish
direnv
dockerfile-mode
doom-modeline
dtrt-indent
edit-indirect
el-patch
elpy
epresent
evil
evil-collection
evil-magit
evil-numbers
evil-org
evil-surround
evil-swap-keys
fish-mode
flycheck
flycheck-inline
flycheck-jest
flycheck-rust
forth-mode
gcmh
general
gitconfig-mode
go-mode
google-translate
graphviz-dot-mode
groovy-mode
haskell-mode
imenu-list
ivy
ivy-bibtex
jinja2-mode
js2-mode
json-mode
ledger-mode
lispyville
lsp-haskell
lsp-mode
lsp-ui
lua-mode
magit
markdown-mode
mbsync
modus-operandi-theme
monokai-theme
nix-mode
nix-sandbox
notmuch
org-cliplink
org-download
org-drill
org-ref
org-roam
org-roam-bibtex
org-super-agenda
paren-face
php-mode
pip-requirements
plantuml-mode
prettier-js
projectile
protobuf-mode
psc-ide
purescript-mode
py-autopep8
racer
restclient
rjsx-mode
rust-mode
smex
spaceline
terraform-mode
tide
typescript-mode
use-package
visual-fill-column
vue-mode
w3m
web-mode
wgrep
which-key
whitespace-cleanup-mode
writegood-mode
yaml-mode
yasnippet
]) ++
[
epkgs.orgPackages.org-plus-contrib
epkgs.elpaPackages.adaptive-wrap
pkgs.ycmd
pkgs.notmuch
pkgs.w3m
pkgs.imagemagick
pkgs.shellcheck
(pkgs.python3.withPackages (pypkgs: [
pypkgs.autopep8
pypkgs.black
pypkgs.flake8
pypkgs.mypy
pypkgs.pylint
pypkgs.virtualenv
]))
(pkgs.aspellWithDicts (dicts: with dicts; [en en-computers en-science ru uk]))
# latex for displaying fragments in org-mode
(pkgs.texlive.combine {
inherit (pkgs.texlive) scheme-small dvipng dvisvgm mhchem ;
})
]
);
emacs-final = (pkgs.emacsPackagesGen emacs-base).emacsWithPackages emacs-packages;
in {
my-emacs = emacs-final // {
base = emacs-base;
packages = emacs-packages;
};
})
Install Emacs with Home manager
{
programs.emacs = {
enable = true;
package = pkgs.my-emacs.base;
extraPackages = pkgs.my-emacs.packages;
};
services.emacs.enable = true;
# fonts used by emacs
home.packages = [
pkgs.input-mono
pkgs.libertine
];
}
For the main emacs configuration, check emacs.org file.
{
services.openvpn.servers.nano-vpn = {
config = ''
config /root/openvpn/nano-vpn.ovpn
'';
};
}
{
networking = {
hostName = name;
networkmanager.enable = true;
# disable wpa_supplicant
wireless.enable = false;
};
users.extraUsers.rasen.extraGroups = [ "networkmanager" ];
}
Install network manager applet for user.
{
home.packages = [pkgs.networkmanagerapplet];
}
{
services.avahi = {
enable = true;
interfaces = [];
openFirewall = false;
};
}
Use pulseaudio (multiple sound sinks, skype calls).
Also, Pulseaudio is a requirement for Firefox Quantum.
{
hardware.pulseaudio = {
enable = true;
support32Bit = true;
};
}
pavucontrol
is PulseAudio Volume Control—a nice utility for controlling pulseaudio settings.
{
home.packages = [ pkgs.pavucontrol ];
}
Update locate database daily.
{
services.locate = {
enable = true;
localuser = "rasen";
};
}
{
services.openssh = {
enable = true;
passwordAuthentication = false;
};
}
Mosh (mobile shell) is a cool addition to ssh.
{
programs.mosh.enable = true;
}
{
services.gitolite = {
enable = true;
user = "git";
adminPubkey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHH15uiQw3jBbrdlcRb8wOr8KVltuwbHP/JOFAzXFO1l/4QxnKs6Nno939ugULM7Lu0Vx5g6FreuCOa2NMWk5rcjIwOzjrZnHZ7aoAVnE7H9scuz8NGnrWdc1Oq0hmcDxdZrdKdB6CPG/diGWNZy77nLvz5JcX1kPLZENPeApCERwR5SvLecA4Es5JORHz9ssEcf8I7VFpAebfQYDu+VZZvEu03P2+5SXv8+5zjiuxM7qxzqRmv0U8eftii9xgVNC7FaoRBhhM7yKkpbnqX7IeSU3WeVcw4+d1d8b9wD/sFOyGc1xAcvafLaGdgeCQGU729DupRRJokpw6bBRQGH29 rasen@omicron";
};
}
Use dnsmasq as a DNS cache.
{
services.dnsmasq = {
enable = true;
# These are used in addition to resolv.conf
servers = [
"8.8.8.8"
"8.8.4.4"
];
extraConfig = ''
listen-address=127.0.0.1
cache-size=1000
no-negcache
'';
};
}
I use Syncthing to sync my org-mode files to my phone.
{
services.syncthing = {
enable = true;
user = "rasen";
dataDir = "/home/rasen/.config/syncthing";
configDir = "/home/rasen/.config/syncthing";
openDefaultPorts = true;
};
}
Enable firewall. This blocks all ports (for ingress traffic) and pings.
{
networking.firewall = {
enable = true;
allowPing = false;
connectionTrackingModules = [];
autoLoadConntrackHelpers = false;
};
}
{
virtualisation.docker.enable = true;
}
I use borg for backups.
(let
commonOptions = {
repo = "[email protected]:.";
encryption.mode = "keyfile-blake2";
encryption.passCommand = "cat /root/secrets/borg";
compression = "auto,lzma,9";
doInit = false;
environment = { BORG_RSH = "ssh -i /root/.ssh/borg"; };
# UTC timestamp
dateFormat = "-u +%Y-%m-%dT%H:%M:%S";
};
in {
services.borgbackup.jobs."all" = commonOptions // {
archiveBaseName = "${config.networking.hostName}";
paths = [
"/var/lib/gitolite/"
"/home/rasen/backup/"
"/home/rasen/.ssh/"
"/home/rasen/.gnupg/"
"/home/rasen/.password-store/"
"/home/rasen/dotfiles/"
"/home/rasen/org/"
# Mail
"/home/rasen/Mail/"
"/home/rasen/.mbsync/"
];
exclude = [
# Scanning notmuch takes too much time and doesn't make much
# sense as it is easily replicable
"/home/rasen/Mail/.notmuch"
];
};
# Start backup on boot if missed one while laptop was off
systemd.timers.borgbackup-job-all.timerConfig = {
Persistent = true;
};
# Require VPN connection for repo to be reachable
systemd.services.borgbackup-job-all = {
requires = ["openvpn-nano-vpn.service"];
};
})
I need to access my Android device.
{
services.udev.packages = [ pkgs.android-udev-rules ];
programs.adb.enable = true;
users.users.rasen.extraGroups = ["adbusers"];
}
fwupd is a service that allows applications to update firmware.
{
services.fwupd.enable = true;
}
Execute the following command to update firmware.
fwupdmgr get-updates
{
services.lorri.enable = true;
programs.direnv.enable = true;
}
{
accounts.email = {
maildirBasePath = "Mail";
};
programs.mbsync = {
enable = true;
extraConfig = lib.mkBefore ''
MaildirStore local
Path ~/Mail/
Inbox ~/Mail/INBOX
SubFolders Verbatim
'';
};
programs.notmuch = {
enable = true;
new.ignore = [
".mbsyncstate"
".mbsyncstate.lock"
".mbsyncstate.new"
".mbsyncstate.journal"
".uidvalidity"
"dovecot-uidlist"
"dovecot-keywords"
"dovecot.index"
"dovecot.index.log"
"dovecot.index.log.2"
"dovecot.index.cache"
"/^archive/"
];
};
# My Maildir layout predates home-manager configuration, so I do not
# use mbsync config generation from home-manager, to keep layout
# compatible.
imports =
let
emails = [
{ name = "gmail"; email = "[email protected]"; path = "Personal"; primary = true; }
{ name = "ps"; email = "[email protected]"; path = "protocolstandard"; }
{ name = "egoless"; email = "[email protected]"; path = "egoless"; }
];
mkGmailBox = { name, email, path, ... }@all: {
accounts.email.accounts.${name} = {
realName = "Alexey Shmalko";
address = email;
flavor = "gmail.com";
passwordCommand = "pass imap.gmail.com/${email}";
maildir.path = path;
msmtp.enable = true;
notmuch.enable = true;
} // (removeAttrs all ["name" "email" "path"]);
programs.mbsync.extraConfig = ''
IMAPAccount ${name}
Host imap.gmail.com
User ${email}
PassCmd "pass imap.gmail.com/${email}"
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt
IMAPStore ${name}-remote
Account ${name}
Channel sync-${name}-all
Master :${name}-remote:"[Gmail]/All Mail"
Slave :local:${path}/all
Create Both
SyncState *
Channel sync-${name}-spam
Master :${name}-remote:"[Gmail]/Spam"
Slave :local:${path}/spam
Create Both
SyncState *
Channel sync-${name}-sent
Master :${name}-remote:"[Gmail]/Sent Mail"
Slave :local:${path}/sent
Create Both
SyncState *
Group sync-${name}
Channel sync-${name}-all
Channel sync-${name}-spam
Channel sync-${name}-sent
'';
};
in map mkGmailBox emails;
}
I definitely use X server:
{
services.xserver.enable = true;
}
Use English as my only supported locale:
{
i18n.supportedLocales = [ "en_US.UTF-8/UTF-8" ];
}
Setup timezone:
{
time.timeZone = "Europe/Kiev";
}
{
services.xserver.displayManager.lightdm.enable = true;
}
I use awesome wm:
{
services.xserver.windowManager = {
awesome = {
enable = true;
luaModules = [ pkgs.luaPackages.luafilesystem pkgs.luaPackages.cjson ];
};
};
services.xserver.displayManager.defaultSession = "none+awesome";
}
Disabling xterm makes awesome wm a default choice in slim:
{
services.xserver.desktopManager.xterm.enable = false;
}
These packages are used by my awesome wm setup:
{
home.packages = [
pkgs.wmname
pkgs.xclip
pkgs.escrotum
];
}
I use English and Ukrainian layouts. I also use Russian symbols, but they are on the third level.
{
services.xserver.layout = "us,ua";
services.xserver.xkbVariant = "workman,";
# Use same config for linux console
console.useXkbConfig = true;
}
Map left Caps Lock to Ctrl, and left Ctrl to switch between layout. (Shift-Ctrl triggers Caps Lock function.)
I toggle between them with either Caps Lock, or Menu key—I have two different keyboards, and one doesn’t have Menu when Caps Lock is too far on the second. I never use Caps Lock–the feature, so it’s nice to have Caps LED indicate alternate layouts.
{
services.xserver.xkbOptions = "grp:lctrl_toggle,grp_led:caps,ctrl:nocaps";
}
{
home.keyboard = {
layout = "us,ua";
variant = "workman,";
};
}
Use a slightly customized Workman keyboard layout (more keys on 3rd level).
{
xsession.initExtra = ''
xkbcomp ${./Xkeymap} $DISPLAY
'';
}
I use built-in awesome layout indicator. See .config/awesome/rc.lua for more details.
Redshift adjusts the color temperature of the screen according to the position of the sun.
Blue light blocks melatonin (sleep harmone) secretion, so you feel less sleepy when you stare at computer screen. Redshift blocks some blue light (making screen more red), which should improve melatonin secretion and restore sleepiness (which is a good thing).
{
services.redshift = {
enable = true;
};
location.provider = "geoclue2";
}
xbacklight
stopped working recently. acpilight
is a drop-in replacement.
{
hardware.acpilight.enable = true;
environment.systemPackages = [
pkgs.acpilight
];
users.extraUsers.rasen.extraGroups = [ "video" ];
}
For Home Manager–managed hosts.
{
home.packages = [pkgs.acpilight];
}
I’m not a font guru, so I just stuffed a bunch of random fonts in here.
{
fonts = {
fontconfig.enable = true;
enableFontDir = true;
enableGhostscriptFonts = false;
fonts = with pkgs; [
pkgs.inconsolata
pkgs.dejavu_fonts
pkgs.source-code-pro
pkgs.ubuntu_font_family
pkgs.unifont
pkgs.powerline-fonts
pkgs.terminus_font
];
};
}
For home-manager.
{
fonts.fontconfig.enable = true;
home.packages = [
pkgs.inconsolata
pkgs.dejavu_fonts
pkgs.source-code-pro
pkgs.ubuntu_font_family
pkgs.unifont
pkgs.powerline-fonts
pkgs.terminus_font
];
}
These are for omicron-only.
{
xresources.properties = {
"Xft.dpi" = 276;
"Xcursor.size" = 64;
};
}
{
console.packages = [
pkgs.terminus_font
];
console.font = "ter-132n";
}
{
services.xserver.dpi = 276;
}
Here go applications (almost) every normal user needs.
{
programs.gnupg.agent = {
enable = true;
enableSSHSupport = true;
pinentryFlavor = "qt";
};
## is it no longer needed?
#
# systemd.user.sockets.gpg-agent-ssh = {
# wantedBy = [ "sockets.target" ];
# listenStreams = [ "%t/gnupg/S.gpg-agent.ssh" ];
# socketConfig = {
# FileDescriptorName = "ssh";
# Service = "gpg-agent.service";
# SocketMode = "0600";
# DirectoryMode = "0700";
# };
# };
services.pcscd.enable = true;
}
{
environment.systemPackages = [
pkgs.yubikey-manager
pkgs.yubikey-personalization
pkgs.yubikey-personalization-gui
];
services.udev.packages = [
pkgs.yubikey-personalization
pkgs.libu2f-host
];
}
Install password-store along with one-time password extension.
{
home.packages = [
(pkgs.pass.withExtensions (exts: [ exts.pass-otp ]))
];
}
Install browserpass firefox extension backend.
{
programs.browserpass = {
enable = true;
browsers = ["firefox" "chrome"];
};
}
I don’t use full KDE but some apps are definitely nice.
{
home.packages = [
pkgs.gwenview
pkgs.dolphin
pkgs.kdeFrameworks.kfilemetadata
pkgs.filelight
pkgs.shared_mime_info
];
}
KDE apps might have issues with mime types without this:
{
environment.pathsToLink = [ "/share" ];
}
Firefox is default; Chrome for backup.
{
home.packages = [
pkgs.firefox
pkgs.google-chrome
];
}
Zathura is a cool document viewer with Vim-like bindings.
{
programs.zathura = {
enable = true;
options = {
incremental-search = true;
};
# Swap j/k (for Workman layout)
extraConfig = ''
map j scroll up
map k scroll down
'';
};
}
Slock is a simple X display locker and should probably not crash as xscreensaver does.
Slock tries to disable OOM killer (so the locker is not killed when memory is low) and this requires a suid flag for executable. Otherwise, you get the following message:
slock: unable to disable OOM killer. Make sure to suid or sgid slock.
{
programs.slock.enable = true;
}
xss-lock is a small utility to plug a screen locker into screen saver extension for X. This automatically activates selected screensaver after a period of user inactivity, or when system goes to sleep.
{
home.packages = [
pkgs.xss-lock
];
}
{
home.packages = [
pkgs.google-play-music-desktop-player
pkgs.tdesktop # Telegram
pkgs.mplayer
pkgs.smplayer
# Used by naga-awesome wm setup
pkgs.xdotool
];
}
I’m a seasoned Vim user, but I’ve switched to emacs.
{
environment.systemPackages = [
(pkgs.vim_configurable.override { python3 = true; })
pkgs.neovim
];
}
For Home Manager–managed hosts.
{
home.packages = [
(pkgs.vim_configurable.override { python3 = true; })
pkgs.neovim
];
}
I use urxvt as my terminal emulator.
{
programs.urxvt = {
enable = true;
iso14755 = false;
fonts = [
"-*-terminus-medium-r-normal-*-32-*-*-*-*-*-iso10646-1"
];
scroll = {
bar.enable = false;
lines = 65535;
scrollOnOutput = false;
scrollOnKeystroke = true;
};
extraConfig = {
"loginShell" = "true";
"urgentOnBell" = "true";
"secondaryScroll" = "true";
# Molokai color theme
"background" = "#101010";
"foreground" = "#d0d0d0";
"color0" = "#101010";
"color1" = "#960050";
"color2" = "#66aa11";
"color3" = "#c47f2c";
"color4" = "#30309b";
"color5" = "#7e40a5";
"color6" = "#3579a8";
"color7" = "#9999aa";
"color8" = "#303030";
"color9" = "#ff0090";
"color10" = "#80ff00";
"color11" = "#ffba68";
"color12" = "#5f5fee";
"color13" = "#bb88dd";
"color14" = "#4eb4fa";
"color15" = "#d0d0d0";
};
};
}
Urxvt gets its setting from .Xresources
file. If you ever want to reload it on-the-fly, type the following (or press C-c C-c
if you’re reading this document in emacs now):
xrdb ~/.Xresources
I use Terminus font.
{
fonts = {
fonts = [
pkgs.powerline-fonts
pkgs.terminus_font
];
};
}
fish is a cool shell, I use it as my default for day-to-day work.
{
programs.fish.enable = true;
users.defaultUserShell = pkgs.fish;
}
For home-manager:
{
programs.fish = {
enable = true;
shellAliases = {
g = "git";
rm = "rm -r";
ec = "emacsclient";
};
functions = {
# old stuff
screencast = ''
function screencast
# key-mon --meta --nodecorated --theme=big-letters --key-timeout=0.05 &
ffmpeg -probesize 3000000000 -f x11grab -framerate 25 -s 3840x3960 -i :0.0 -vcodec libx264 -threads 2 -preset ultrafast -crf 0 ~/tmp/record/record-(date +"%FT%T%:z").mkv
# killall -r key-mon
end
'';
reencode = ''
function reencode
ffmpeg -i file:$argv[1] -c:v libx264 -crf 0 -preset veryslow file:(basename $argv[1] .mkv).crf-0.min.mkv
end
'';
};
};
# manage other shells as well
programs.bash.enable = true;
}
{
programs.fish.functions.fish_user_key_bindings = ''
function fish_user_key_bindings
fish_vi_key_bindings
bind -s j up-or-search
bind -s k down-or-search
bind -s -M visual j up-line
bind -s -M visual k down-line
bind -s '.' repeat-jump
end
'';
}
home-manager-section
{
programs.git = {
enable = true;
package = pkgs.gitAndTools.gitFull;
userName = "Alexey Shmalko";
userEmail = "[email protected]";
signing = {
key = "EB3066C3";
signByDefault = true;
};
extraConfig = {
sendemail = {
smtpencryption = "ssl";
smtpserver = "smtp.gmail.com";
smtpuser = "[email protected]";
smtpserverport = 465;
};
color.ui = true;
core.editor = "vim";
push.default = "simple";
pull.rebase = true;
rebase.autostash = true;
rerere.enabled = true;
advice.detachedHead = false;
};
};
}
I have LOTS of aliases:
{
programs.git.aliases = {
cl = "clone";
gh-cl = "gh-clone";
cr = "cr-fix";
p = "push";
pl = "pull";
f = "fetch";
fa = "fetch --all";
a = "add";
ap = "add -p";
d = "diff";
dl = "diff HEAD~ HEAD";
ds = "diff --staged";
l = "log --show-signature";
l1 = "log -1";
lp = "log -p";
c = "commit";
ca = "commit --amend";
co = "checkout";
cb = "checkout -b";
cm = "checkout origin/master";
de = "checkout --detach";
fco = "fetch-checkout";
br = "branch";
s = "status";
re = "reset --hard";
r = "rebase";
rc = "rebase --continue";
ri = "rebase -i";
m = "merge";
t = "tag";
su = "submodule update --init --recursive";
bi = "bisect";
};
}
Always push to github with ssh keys instead of login/password.
{
programs.git.extraConfig = {
url."[email protected]:".pushInsteadOf = "https://github.com";
};
}
Also, install git for the rest of the system.
{
environment.systemPackages = [
pkgs.git
];
}
{
environment.systemPackages = [
pkgs.tmux
];
}
For home-manager.
{
programs.tmux = {
enable = true;
keyMode = "vi";
# Use C-a as prefix
shortcut = "a";
# To make vim work properly
terminal = "screen-256color";
# start numbering from 1
baseIndex = 1;
# Allows for faster key repetition
escapeTime = 0;
historyLimit = 10000;
reverseSplit = true;
clock24 = true;
extraConfig = ''
bind-key S-left swap-window -t -1
bind-key S-right swap-window -t +1
bind h select-pane -L
bind k select-pane -D
bind j select-pane -U
bind l select-pane -R
bind r source-file ~/.tmux.conf \; display-message "Config reloaded..."
set-window-option -g automatic-rename
'';
};
}
{
environment.systemPackages = [
pkgs.wget
pkgs.htop
pkgs.psmisc
pkgs.zip
pkgs.unzip
pkgs.unrar
pkgs.bind
pkgs.file
pkgs.which
pkgs.utillinuxCurses
pkgs.ripgrep
pkgs.patchelf
pkgs.python3
];
# environment.variables.NPM_CONFIG_PREFIX = "$HOME/.npm-global";
# environment.variables.PATH = "$HOME/.npm-global/bin:$PATH";
}
This install a number of default man pages for the linux/posix system.
{
documentation = {
man.enable = true;
dev.enable = true;
};
environment.systemPackages = [
pkgs.man-pages
pkgs.stdman
pkgs.posix_man_pages
pkgs.stdmanpages
];
}
{
home.file = {
".vim".source = ./.vim;
".nvim".source = ./.vim;
".nethackrc".source = ./.nethackrc;
};
programs.fish.shellInit = ''
set -x PATH ${./bin} $PATH
'';
xdg.configFile."awesome".source = ./.config/awesome;
}