Introduction
This repo uses Lilac to extract the code/configuration from Org files. Not all parts have been migrated over to use Lilac yet, and until that's done there will be many incomplete sections in the docs.
Warning: I will force-push to this repo rather frequently. Sorry!
1 Installation
Each subdirectory is responsible for one component, and is also the name of a build rule in the Makefile.
E.g., to set up Emacs and Vim configurations, do:
make emacs vim2 Known Issues
The default repository name, syscfg, is hardcoded in some places.
3.1 Lilac project configuration
name = "Linus Arver's Dotfiles"
homepage = "https://git.sr.ht/~listx/syscfg"
repo = "https://git.sr.ht/~listx/syscfg"
version = ""
nonTangledPathspecs = [ # 1
":(exclude,top).gitmodules",
":(exclude,top).lilac.json",
":(exclude,top)README.md",
":(exclude,top)LICENSE",
":(exclude,top)clojure",
":(exclude,top)doc/*.org",
":(exclude,top)emacs/doom-cfg/snippets/.gitkeep",
":(exclude,top)emacs/doom-upstream",
":(exclude,top)Cargo.lock",
":(exclude,top)gpg",
":(exclude,top)jjui",
":(exclude,top)karabiner",
":(exclude,top)lesskey",
":(exclude,top)melby",
":(exclude,top)mpd",
":(exclude,top)mpv",
":(exclude,top)nix",
":(exclude,top)nixos",
":(exclude,top)nixpkgs",
":(exclude,top)notmuch",
":(exclude,top)nvim",
":(exclude,top)openvpn",
":(exclude,top)pulse",
":(exclude,top)qutebrowser",
":(exclude,top)rtorrent",
":(exclude,top)ssh",
":(exclude,top)terminfo",
":(exclude,top)tig",
":(exclude,top)tmux",
":(exclude,top)vimpc",
":(exclude,top)wezterm",
":(exclude,top)nixos",
":(exclude,top)script",
":(exclude,top)uim",
":(exclude,top)vim",
":(exclude,top)xmonad",
":(exclude,top)xorg",
":(exclude,top)zathura",
":(exclude,top)zsh"
]
custom-html-headCurrently we exclude most paths in 1, because we haven't migrated existing code to literate style yet.
3.2 Literate Makefile
The literate programming configuration is inside the doc folder. It houses all Org files which we feed into Lilac to tangle the code and also weave HTML output.
org_files := $(shell find . -type f -name "*.org")
obj_files := $(org_files:%.org=%.lobj)
archive_file := syscfg.larc
all: tangle weave lint
.PHONY: all
$(obj_files) &: $(org_files)
lilac compile $?
touch $(obj_files)
$(archive_file): $(obj_files)
lilac archive $^ --out-file $@
tangle: $(archive_file)
lilac tangle $< --out-dir ..
touch tangle
weave: $(archive_file)
lilac weave $< --out-dir site --write-css --write-js
touch weave
Makefile:publish
lint: $(archive_file)
cd .. && lilac --project-conf doc/Lilac.toml lint doc/$<
prek run --all-files
touch lint
gitconfig:
cd .. && git config diff.orderfile .git-orderfile
.PHONY: gitconfig
update:
cd .. && niv update nixpkgs --branch Nixpkgs version
.PHONY: update
clean:
rm -rf \
$(archive_file) \
$(obj_files)
.PHONY: cleannixos-25.113.3 Makefile for installing dotfiles
# Configuration directory.
C := $(shell pwd)
# Home directory.
H := ${HOME}
# Platform. E.g., "Darwin", "Linux".
P := $(shell uname)
# Long hostname, without the trailing domain name, if any.
T := $(shell hostname | cut -d. -f1)
# Short (custom) hostname.
S := $(shell cat ${H}/.hostname-short)
# Add the -n flag for directories, as otherwise, stray symlinks will be created
# inside the C (config) directory itself.
Makefile-bash
Makefile-clojure
Makefile-emacs
Makefile-git
gpg:
ln -fns ${C}/gpg ${H}/.gnupg
ln -fs ${C}/gpg/gpg-agent.nixos.conf ${H}/.gnupg/gpg-agent.conf
jj:
ln -fns ${C}/jj ${H}/.config/jj
jjui:
ln -fns ${C}/jjui ${H}/.config/jjui
karabiner:
mkdir -p ${H}/.config/karabiner
ln -fns ${C}/karabiner/karabiner.json ${H}/.config/karabiner
lesskey:
ln -fs ${C}/lesskey/cfg ${H}/.lesskey
lesskey
melby:
ln -fns ${C}/melby ${H}/.melby
set -e && \
melby_location=$$(readlink $$(which melbyd)) && \
cp -f $${melby_location%/bin/melbyd}/share/melby/sample/* ${H}/.melby
mpd:
ln -fns ${C}/mpd ${H}/.config/mpd
mpv:
ln -fns ${C}/mpv ${H}/.config/mpv
ifeq ('${T}','k0')
ln -fs mpv.${T}.conf mpv/mpv.conf
else ifeq ('${P}','Darwin')
ln -fs mpv.osx.conf mpv/mpv.conf
else
ln -fs mpv.linux.conf mpv/mpv.conf
endif
nix:
ln -fns ${C}/nix ${H}/.config/nix
nixos:
ifeq ('${T}','w0')
ln -fs ${C}/nixos/${T}/configuration.nix /etc/nixos
ln -fs ${C}/nixos/${T}/syschdemd.nix /etc/nixos
ln -fs ${C}/nixos/${T}/syschdemd.sh /etc/nixos
ln -fs ${C}/nixos/${T}/wsl.conf /etc/nixos
ln -fs ${C}/nixos/${T}/hosts /etc
cp -f ${C}/nixos/${T}/resolv.conf /etc
else
ln -fs ${C}/nixos/${T}/configuration.nix /etc/nixos
ln -fs ${C}/nixos/${T}/hardware-configuration.nix /etc/nixos
endif
nixpkgs:
ln -fns ${C}/nixpkgs ${H}/.nixpkgs
notmuch:
ln -fs ${C}/notmuch/notmuch-config ${H}/.notmuch-config
nvim:
ln -fns ${C}/nvim ${H}/.config/nvim
pulse:
rm -rf ${H}/.config/pulse
rm -rf ${H}/.pulse
mkdir -p ${H}/.config/pulse
mkdir ${H}/.pulse
ifeq ('${T}','k0')
cp ${C}/pulse/daemon.conf.k0 ${H}/.config/pulse/daemon.conf
cp ${C}/pulse/default.pa.k0 ${H}/.pulse/default.pa
else
cp ${C}/pulse/default.pa ${H}/.pulse/default.pa
endif
qutebrowser:
ifeq ('${P}','Darwin')
ln -fns ${C}/qutebrowser ${H}/.qutebrowser
else
ln -fns ${C}/qutebrowser ${H}/.config
endif
rtorrent:
ln -fs ${C}/rtorrent/cfg ${H}/.rtorrent.rc
ssh:
ifeq ($(wildcard ~/.ssh/.),)
ln -fns ${C}/ssh ${H}/.ssh
endif
ln -fs ${C}/ssh/config.home.conf ${H}/.ssh/config
terminfo:
git -C ${C} submodule update --init ${C}/wezterm/upstream
tic -x -o ~/.terminfo ${C}/wezterm/upstream/termwiz/data/wezterm.terminfo
tic -x -o ~/.terminfo ${C}/terminfo/xterm-24bit.terminfo
tig:
ln -fs ${C}/tig/.tigrc ${H}
tmux:
ln -fs ${C}/tmux/.tmux.conf ${H}/.tmux.conf
ln -fns ${C}/tmux ${H}/.tmux
uim:
ln -fns ${C}/uim/.uim ${H}/.uim
ln -fns ${C}/uim ${H}/.uim.d
vim:
ln -fns ${C}/vim ${H}/.vim
ln -fs ${C}/vim/cfg ${H}/.vimrc
ln -fs ${C}/vim/cfg ${H}/.gvimrc
vimpc:
ln -fs ${C}/vimpc/.vimpcrc ${H}
wezterm:
ln -fs ${C}/wezterm/.wezterm.lua ${H}
xmonad:
ln -fns ${C}/xmonad ${H}/.xmonad
# xsession is relied on by NixOS hosts that use xmonad (basically the
# default) to start xmonad.
ln -fs ${C}/xmonad/.xsession ${H}/.xsession
zathura:
ln -fns ${C}/zathura ${H}/.config/zathura
zsh:
ln -fns ${C}/zsh ${H}/.zsh
ln -fs ${C}/zsh/.zshenv ${H}
ln -fs ${C}/zsh/.zshrc ${H}
test -f ${C}/zsh/zprofile-${T} \
&& ln -fs ${C}/zsh/zprofile-${T} ${H}/.zprofile || true
test -f ${C}/zsh/zprofile-${S} \
&& ln -fs ${C}/zsh/zprofile-${S} ${H}/.zprofile || true
test -f ${C}/zsh/zlogin-${T} \
&& ln -fs ${C}/zsh/zlogin-${T} ${H}/.zlogin || true
mkdir -p ${H}/.zsh-untracked
git -C ${C} submodule update --init ${C}/zsh/zcomet-upstream
mkdir -p ${C}/zsh/zcomet
ln -fns ${C}/zsh/zcomet ${H}/.zcomet
.PHONY: \
bash \
clojure \
emacs \
git \
gpg \
jj \
jjui \
karabiner \
lesskey \
melby \
mpd \
mpv \
nix \
nixos \
nixpkgs \
notmuch \
nvim \
pulse \
qutebrowser \
rtorrent \
ssh \
terminfo \
tig \
tmux \
uim \
vim \
vimpc \
wezterm \
xmonad \
xorg \
zathura \
zsh3.4 Dependencies via Nix
let
sources = import ./nix/sources.nix;
rust-overlay = import sources.rust-overlay;
pkgs = import sources.nixpkgs {
overlays = [ rust-overlay ];
};
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
extensions = [ "rust-src" "rust-analyzer" "clippy" ];
};
git-hooks = import sources."git-hooks.nix";
# 3. Configure the pre-commit checks
pre-commit-check = git-hooks.run {
src = ./.;
hooks = {
shellcheck = {
enable = true;
excludes = [
"script/aex.sh"
"nixos/w0/syschdemd.sh"
"\\.(zsh|zshrc|zprofile|zshenv)$"
"zsh/*"
];
};
editorconfig-checker.enable = true;
clippy = {
enable = true;
package = rustToolchain;
};
};
package = pkgs.prek;
};
in
pkgs.mkShell {
name = "syscfg-dev-shell";
buildInputs = with pkgs; [
editorconfig-checker
pikchr
shellcheck
nixfmt
niv
ormolu
parinfer-rust
shfmt
vale
pkgs.prek
rustToolchain
] ++ pre-commit-check.enabledPackages;
nativeBuildInputs = with pkgs; [
pkg-config
gcc
];
propagatedBuildInputs = with pkgs; [
openssl
zlib
];
shellHook = ''
echo -e "\n$(tput setaf 4)"
echo Syscfg | ${pkgs.figlet}/bin/figlet
echo -e "$(tput sgr0)\n"
echo "Using nixpkgs commit: ${sources.nixpkgs.rev} ${pkgs.lib.version}"
echo "Rust compiler profile: $(rustc --version)"
echo
${pre-commit-check.shellHook}
'';
}The pre-commit-check.shellHook generates the YAML at .pre-commit-config.yaml for us.
use nix4 Publish to SourceHut
The woven contents are published to lilac.funloop.org. When Lilac is available on Nixpkgs, we can invoke the publishing step as part of CI on SourceHut.
Makefile:create-tarball
SRHT_TOKEN != cat .srht-pages-token 2>/dev/null || echo ""
publish: weave site.tar.gz
@if [ -z "$(SRHT_TOKEN)" ]; then \
echo "Error: .srht-pages-token is empty or missing." >&2; \
exit 1; \
fi
@echo "Uploading site to SourceHut Pages..."
@curl --oauth2-bearer "$(SRHT_TOKEN)" \
-Fcontent=@site.tar.gz \
https://pages.sr.ht/publish/syscfg.funloop.org
touch publishThe tarball is mainly composed of the site (woven contents) plus the vendored stuff.
site.tar.gz: $(archive_file) weave vendor/mathjax vendor/mathjax-newcm-font vendor/source-fonts
rm -f site.tar site.tar.gz
tar cvf site.tar -C site .
tar rvf site.tar vendor
gzip site.tarThe vendoring is needed because SourceHut does not allow us to pull in scripts from CDNs. We have to be self-contained. Lilac has a lilac init --only-local-imports command which gives us some scripts to download MathJax and also Source fonts.
set -euo pipefail
MAIN_PACKAGE="mathjax"
FONT_PACKAGE="mathjax-newcm-font"
VERSION="4.1.2"
mkdir -p vendor
pushd vendor
download_tarball()
{
local package
local version
local url_prefix
local tarball
package="${1:-}"
version="${2:-}"
tarball="${package}-${version}.tgz"
url_prefix="${3:-}"
if [[ -d "${package}" ]]; then
echo "${package} directory already exists"
return 1
fi
curl -OL "${url_prefix}/-/${tarball}"
tar xzvf "${tarball}"
mv package "${package}"
rm "${tarball}"
}
download_tarball \
"${MAIN_PACKAGE}" \
"${VERSION}" \
"https://registry.npmjs.org/mathjax"
download_tarball \
"${FONT_PACKAGE}" \
"${VERSION}" \
"https://registry.npmjs.org/@mathjax/${FONT_PACKAGE}"set -euo pipefail
url_sans="https://raw.githubusercontent.com/adobe-fonts/source-sans/3.052R"
url_serif="https://raw.githubusercontent.com/adobe-fonts/source-serif/4.005R"
url_code="https://raw.githubusercontent.com/adobe-fonts/source-code-pro/2.042R-u%2F1.062R-i%2F1.026R-vf"
mkdir -p vendor/source-fonts
pushd vendor/source-fonts
curl -OL "${url_sans}/WOFF2/VF/SourceSans3VF-Italic.otf.woff2"
curl -OL "${url_sans}/WOFF2/VF/SourceSans3VF-Upright.otf.woff2"
curl -OL "${url_serif}/WOFF2/VAR/SourceSerif4Variable-Italic.otf.woff2"
curl -OL "${url_serif}/WOFF2/VAR/SourceSerif4Variable-Roman.otf.woff2"
curl -OL "${url_code}/WOFF2/VF/SourceCodeVF-Italic.otf.woff2"
curl -OL "${url_code}/WOFF2/VF/SourceCodeVF-Upright.otf.woff2"
cat << EOF > source-fonts.css
@font-face{
font-family: 'Source Code Pro';
font-weight: 200 900;
font-style: normal;
font-stretch: normal;
src: url('SourceCodeVF-Upright.otf.woff2') format('woff2');
}
@font-face{
font-family: 'Source Code Pro';
font-weight: 200 900;
font-style: italic;
font-stretch: normal;
src: url('SourceCodeVF-Italic.otf.woff2') format('woff2');
}
@font-face{
font-family: 'Source Sans 3';
font-weight: 200 900;
font-style: normal;
font-stretch: normal;
src: url('SourceSans3VF-Upright.otf.woff2') format('woff2');
}
@font-face{
font-family: 'Source Sans 3';
font-weight: 200 900;
font-style: italic;
font-stretch: normal;
src: url('SourceSans3VF-Italic.otf.woff2') format('woff2');
}
@font-face{
font-family: 'Source Serif 4';
font-weight: 200 900;
font-style: normal;
font-stretch: normal;
src: url('SourceSerif4Variable-Roman.otf.woff2') format('woff2');
}
@font-face{
font-family: 'Source Serif 4';
font-weight: 200 900;
font-style: italic;
font-stretch: normal;
src: url('SourceSerif4Variable-Italic.otf.woff2') format('woff2');
}
EOFFinally we need to actually use these vendored assets by referring to them in every woven HTML file. That's what we do in custom-html-head.
[htmlHead]
onlyLocalImports = true
injection = """
<link rel="stylesheet" href="/vendor/source-fonts/source-fonts.css">
<script>
window.MathJax = {
loader: { paths: { "mathjax-newcm": "/vendor/mathjax-newcm-font" } },
output: { font: "mathjax-newcm" },
tex: {
tags: 'ams'
},
options: {
ignoreHtmlClass: 'verbatim|code'
}
};
</script>
<script id="MathJax-script" async="" src="/vendor/mathjax/tex-mml-chtml.js"></script>
"""5.1 .gitignore file
*#
*.aes
*.backup
.clj-kondo
.direnv
*.elc
*.log
*.hi
.lsp
.nrepl-port
*.o
*.pyc
*.swp
*.DS_Store
*~
*.zwc
cache
cmus/*
emacs/doom-cfg/custom.el
emacs/spell-fu/*.data
emacs/spell-fu/*.txt
gpg
karabiner/assets
karabiner/automatic_backups
lh/target
melby/*
mpv/mpv.conf
nvim/.netrwhist
openvpn/*.ovpn
qutebrowser/autoconfig.yml
qutebrowser/bookmarks
qutebrowser/quickmarks
qutebrowser/qsettings
doc/.srht-pages-token
doc/site/
doc/site.tar.gz
doc/vendor/
ssh/*
target/
tmux/resurrect
vim/.VimballRecord
vim/.netrwhist
vim/colors
vim/sessions
wezterm/upstream
xmonad/.cabal-sandbox
xmonad/cabal.sandbox.config
xmonad/dist
xmonad/dist-newstyle
xmonad/.stack-work
xmonad/xmonad
xmonad/xmonad-x86_64-linux
xmonad/xmonad.errors
xmonad/xmonad.state
xmonad/xmonad-session-rc
zsh/zcomet
!.gitattributes
!.git-orderfile
*.lobj
*.larc
*.html
*.js
*.css
lint
publish
tangle
weave
.pre-commit-config.yaml5.2 Git attributes
*.html -diff
doc/css/default.css -diff
doc/js/lilac.js -diff5.4 .rgignore file
bash/
clojure/
emacs/doom-upstream
zsh/zcomet-upstream5.5 EditorConfig
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{sh},Makefile]
indent_style = tab
tab_width = 8
[qutebrowser.conf]
trim_trailing_whitespace = false
[zsh/.zshrc]
end_of_line = unset
[COMMIT_EDITMSG]
max_line_length = 726.5 TODO migrate everything (at least superficially) to lilac
This basically means chipping away at 1 to make it much leaner. That is, the only reason that section is so long is because most of those paths are not tangled from Org files.