initial commit

This commit is contained in:
L-Nafaryus 2023-06-06 23:18:09 +05:00
commit beb5071a7a
94 changed files with 4578 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2023 George Kusayko [L-Nafaryus] <l.nafaryus@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

8
bin/autoclicker Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
while true; do
xdotool mousedown 1
sleep 0.01
xdotool mouseup 1
sleep 0.01
done

9
bin/gitinfo Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env cached-nix-shell
#! nix-shell -p nix-prefetch-git -i bash
for repo in $@; do
if [[ "$repo" != https://* ]]; then
repo="https://github.com/$repo"
fi
nix-prefetch-git --quiet "$repo"
done

72
bin/mov2gif Executable file
View File

@ -0,0 +1,72 @@
#!/usr/bin/env cached-nix-shell
#! nix-shell -i bash -p ffmpeg gifsicle
# Uses ffmpeg to convert a video file to a gif file. Optimizes the final result
# with gifsicle.
#
# Requires: ffmpeg gifsicle
#
# Example:
# mov2gif some-vid.mp4 output.gif
# mov2gif -f 10 -s 00:00:10 -t 00:00:05 some-vid.mp4 output.gif
set -e
PALETTE="/tmp/palette.png"
usage() {
cat <<EOL
Usage: ${0##*/} [-fsSth] SOURCE_FILE [destfile]
-f [FPS] set frames per second
-s [hh:mm:ss] set starting time (like -ss in ffmpeg)
-S [W:H] set width/height (either can be -1 for auto)
-t [hh:mm:ss] set the duration to capture (like -t in ffmpeg)
-h this help
EOL
}
cleanup() { rm -f "$PALETTE"; }
trap cleanup EXIT
#
fps=30
while getopts hf:s:t:S: opt; do
case $opt in
f) fps="$OPTARG" ;;
s) start="-ss $OPTARG" ;;
S) scale=",scale=$OPTARG:flags=lanczos" ;;
t) duration="-t $OPTARG" ;;
h) usage
exit
;;
:) >&2 echo "$OPTARG requires an argument"
usage
exit 1
;;
*) >&2 echo "Not a valid arg: $opt"
usage
exit 1
;;
esac
done
shift $((OPTIND-1))
#
if (($# == 0)); then
>&2 echo "No movie file specified"
exit
elif [[ ! -f $1 ]]; then
>&2 echo "$1 does not exist"
exit
fi
src="$1"
dest="${2:-${src%.*}.gif}"
flags="fps=${fps}$scale"
# stats_mode=full favors motion, causing the resulting palette to better
# accomodate fades and transitions.
ffmpeg -v warning $start $duration -i "file:$src" -vf "$flags,palettegen=stats_mode=full" -y "$PALETTE"
ffmpeg -v warning $start $duration -i "file:$src" -i "$PALETTE" -lavfi "$flags [x]; [x][1:v] paletteuse" -y "$dest"
gifsicle -O3 "$dest" -o "$dest"

21
bin/myip Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env zsh
# Echos your local or WAN IP
if [[ $1 == -w ]]; then
wan=1
shift
fi
if [[ -n $wan ]]; then
dig +short myip.opendns.com @resolver1.opendns.com
else
IF=$(netstat -rn | awk '/^0.0.0.0/ {thif=substr($0,74,10); print thif;} /^default.*UG/ {thif=substr($0,65,10); print thif;}')
if command -v ifconfig >/dev/null; then
ifconfig ${NET_IF} | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'
elif command -v ip >/dev/null; then
ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/'
else
>&2 echo "No easy way to grab your IP"
exit 1
fi
fi

86
bin/optimimg Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env zsh
# Optimize image files (losslessly by default)
#
# Examples:
# imgoptim image.jpg image.png image.gif
# imgoptim directory_of_images/
# imgoptim directory_of_images/*.png
#
# Requires:
# PNGs: optipng, pngquant (lossy)
# JPGs: jpegtran, jpegoptim (lossy)
# GIFs: gifsicle
#
# Packages (same name on homebrew & arch linux)
# optipng [pngquant] libjpeg-turbo [jpegoptim] gifsicle
set -e
unset CDPATH
_usage() {
cat <<EOL
Usage: ${0:A:t} [-lh] IMAGE [IMAGE2 [IMAGE3 [...]]]
-l enable lossy compression
-h this help
EOL
}
_filesize() {
case $OSTYPE in
darwin*) stat -c%s "$1" ;;
*) stat --printf="%s" "$1" ;;
esac
}
#
while getopts hl opt; do
case $opt in
h) _usage; exit;;
l) lossy=1;;
:) >&2 echo "$OPTARG requires an argument"; _usage; exit 1;;
*) >&2 echo "Not a valid arg: $opt"; _usage; exit 1;;
esac
done
shift $((OPTIND-1))
cmds=( optipng jpegtran gifsicle )
[[ -n $lossy ]] && cmds=( $cmds pngquant jpegoptim )
for cmd in ${cmds[@]}; do
if ! command -v $cmd >/dev/null; then
>&2 echo "$cmd isn't installed"
error=1
fi
done
if [[ -n $error ]]; then
>&2 echo "There were errors, aborting"
exit 1
fi
for file in $@; do
if [[ -d $file ]]; then
imgoptim $file/*
elif [[ -f $file ]]; then
pre_size=$(_filesize "$file")
case ${file##*.} in
png)
[[ -n $lossy ]] && pngquant $file
optipng -nc -nb -o7 $file
;;
gif)
gifsicle --batch --optimize=3 "$file"
;;
jpg|jpeg)
[[ -n $lossy ]] && jpegoptim --max=90 "$file"
jpegtran -copy none -optimize -progressive -outfile "$file" "$file"
;;
*)
printf "Unrecognized file '$file': ignored"
;;
esac
post_size=$(_filesize "$file")
perc=$(echo "((${pre_size} - ${post_size}) / ${pre_size}) * 100" | bc -l)
printf "* %s: %d => %d (%.2f%% reduction)\n" "$file" "${pre_size}" "${post_size}" "$perc"
fi
done

36
bin/optimpdf Executable file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Compress pdf files using ghostscript.
#
# Defaults to 72 dpi.
#
# Usage:
# pdfoptim SRC [TARGET] [DPI]
#
# Requires: ghostscript (gs)
optimize() {
# Adapted from Alfred Klomp's shrinkpdf script
# <http://alfredklomp.com/programming/shrinkpdf/>
gs -q -dNOPAUSE -dBATCH -dSAFER \
-sDEVICE=pdfwrite \
-dPDFSETTINGS=/screen \
-dCompatibilityLevel=1.3 \
-dEmbedAllFonts=true \
-dSubsetFonts=true \
-dAutoRotatePages=/None \
-dMonoImageResolution=$3 \
-dMonoImageDownsampleType=/Bicubic \
-dGrayImageResolution=$3 \
-dGrayImageDownsampleType=/Bicubic \
-dColorImageResolution=$3 \
-dColorImageDownsampleType=/Bicubic \
-sOutputFile="$2" \
"$1"
}
src="$1"
dest="${2:--}"
dpi="${3:-72}"
optimize "$src" "$dest" "$dpi" || exit $?

22
bin/zzz Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
# If -f, then put computer to sleep.
# Otherwise, lock screen and turn off monitor.
if [[ $1 == -h ]]; then
bin=${0##*/}
echo "Usage: $bin [-f]"
echo
echo " $bin # put display to sleep"
echo " $bin -f # put computer to sleep"
elif [[ $1 == -f ]]; then
echo "Going to sleep..."
systemctl suspend
else
echo "Shutting my eyes..."
if command -v slock >/dev/null; then
pgrep slock >/dev/null || slock &
fi
sleep 1
xset dpms force off
fi

6
config/emacs/aliases.zsh Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env zsh
e() { pgrep emacs && emacsclient -n "$@" || emacs -nw "$@" }
ediff() { emacs -nw --eval "(ediff-files \"$1\" \"$2\")"; }
eman() { emacs -nw --eval "(switch-to-buffer (man \"$1\"))"; }
ekill() { emacsclient --eval '(kill-emacs)'; }

View File

@ -0,0 +1,140 @@
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
;; Place your private configuration here! Remember, you do not need to run 'doom
;; sync' after modifying this file!
;; Some functionality uses this to identify you, e.g. GPG configuration, email
;; clients, file templates and snippets. It is optional.
(setq user-full-name "L-Nafaryus"
user-mail-address "l.nafaryus@gmail.com")
;; Doom exposes five (optional) variables for controlling fonts in Doom:
;;
;; - `doom-font' -- the primary font to use
;; - `doom-variable-pitch-font' -- a non-monospace font (where applicable)
;; - `doom-big-font' -- used for `doom-big-font-mode'; use this for
;; presentations or streaming.
;; - `doom-unicode-font' -- for unicode glyphs
;; - `doom-serif-font' -- for the `fixed-pitch-serif' face
;;
;; See 'C-h v doom-font' for documentation and more examples of what they
;; accept. For example:
;;
;;(setq doom-font (font-spec :family "Fira Code" :size 12 :weight 'semi-light)
;; doom-variable-pitch-font (font-spec :family "Fira Sans" :size 13))
;;
;; If you or Emacs can't find your font, use 'M-x describe-font' to look them
;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to
;; refresh your font settings. If Emacs still can't find your font, it likely
;; wasn't installed correctly. Font issues are rarely Doom issues!
;; There are two ways to load a theme. Both assume the theme is installed and
;; available. You can either set `doom-theme' or manually load a theme with the
;; `load-theme' function. This is the default:
(setq doom-theme 'doom-one)
;; This determines the style of line numbers in effect. If set to `nil', line
;; numbers are disabled. For relative line numbers, set this to `relative'.
(setq display-line-numbers-type t)
;; If you use `org' and don't want your org files in the default location below,
;; change `org-directory'. It must be set before org loads!
(setq org-directory "~/org/")
;; Whenever you reconfigure a package, make sure to wrap your config in an
;; `after!' block, otherwise Doom's defaults may override your settings. E.g.
;;
;; (after! PACKAGE
;; (setq x y))
;;
;; The exceptions to this rule:
;;
;; - Setting file/directory variables (like `org-directory')
;; - Setting variables which explicitly tell you to set them before their
;; package is loaded (see 'C-h v VARIABLE' to look up their documentation).
;; - Setting doom variables (which start with 'doom-' or '+').
;;
;; Here are some additional functions/macros that will help you configure Doom.
;;
;; - `load!' for loading external *.el files relative to this one
;; - `use-package!' for configuring packages
;; - `after!' for running code after a package has loaded
;; - `add-load-path!' for adding directories to the `load-path', relative to
;; this file. Emacs searches the `load-path' when you load packages with
;; `require' or `use-package'.
;; - `map!' for binding new keys
;;
;; To get information about any of these functions/macros, move the cursor over
;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k').
;; This will open documentation for it, including demos of how they are used.
;; Alternatively, use `C-h o' to look up a symbol (functions, variables, faces,
;; etc).
;;
;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how
;; they are implemented.
(setq confirm-kill-emacs nil)
(after! mu4e
(setq +mu4e-gmail-accounts '(("l.nafaryus@gmail.com" . "/gmail-main")))
(auth-source-pass-enable)
(setq auth-source-debug t)
(setq auth-source-do-cache nil)
(setq auth-sources '(password-store))
;; don't need to run cleanup after indexing for gmail
(setq mu4e-index-cleanup nil)
;; because gmail uses labels as folders we can use lazy check since
;; messages don't really "move"
(setq mu4e-index-lazy-check t)
(set-email-account! "l.nafaryus@gmail.com"
'((mu4e-sent-folder . "/gmail-main/[Gmail]/Sent Mail")
(mu4e-drafts-folder . "/gmail-main/[Gmail]/Drafts")
(mu4e-trash-folder . "/gmail-main/[Gmail]/Trash")
(mu4e-refile-folder . "/gmail-main/[Gmail]/All Mail")
(smtpmail-smtp-user . "l.nafaryus@gmail.com")
(smtpmail-local-domain . "gmail.com")
(smtpmail-default-smtp-server . "smtp.gmail.com")
(smtpmail-smtp-server . "smtp.gmail.com")
(smtpmail-smtp-service . 587)
(mu4e-compose-signature . "---\nL-Nafaryus"))
t)
(setq mu4e-context-policy 'ask-if-none)
(setq mu4e-compose-context-policy 'always-ask)
;; viewing options
(setq mu4e-view-show-addresses t)
;; Do not leave message open after it has been sent
(setq message-kill-buffer-on-exit t)
;; Don't ask for a 'context' upon opening mu4e
(setq mu4e-context-policy 'pick-first)
;; Don't ask to quit
(setq mu4e-confirm-quit nil)
(setq mu4e-attachment-dir "~/.mail/.attachments")
(require 'mu4e-alert)
(setq mu4e-alert-interesting-mail-query "flag:unread AND maildir:/gmail-main/Inbox")
(mu4e-alert-enable-mode-line-display)
(defun refresh-mu4e-alert-mode-line ()
(interactive)
(mu4e~proc-kill)
(async-shell-command "mbsync -a")
(mu4e-alert-enable-mode-line-display)
(mu4e-alert-enable-notifications)
)
(run-with-timer 0 60 'refresh-mu4e-alert-mode-line)
)
(setq projectile-require-project-root nil)
(setq projectile-project-search-path '("~/projects"))
(after! meson-mode
(add-hook 'meson-mode-hook 'company-mode))

View File

@ -0,0 +1,194 @@
;;; init.el -*- lexical-binding: t; -*-
;; This file controls what Doom modules are enabled and what order they load
;; in. Remember to run 'doom sync' after modifying it!
;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
;; documentation. There you'll find a link to Doom's Module Index where all
;; of our modules are listed, including what flags they support.
;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
;; 'C-c c k' for non-vim users) to view its documentation. This works on
;; flags as well (those symbols that start with a plus).
;;
;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its
;; directory (for easy access to its source code).
(doom! :input
;;bidi ; (tfel ot) thgir etirw uoy gnipleh
;;chinese
;;japanese
;;layout ; auie,ctsrnm is the superior home row
:completion
company ; the ultimate code completion backend
;;helm ; the *other* search engine for love and life
;;ido ; the other *other* search engine...
;;ivy ; a search engine for love and life
vertico ; the search engine of the future
:ui
;;deft ; notational velocity for Emacs
doom ; what makes DOOM look the way it does
doom-dashboard ; a nifty splash screen for Emacs
;;doom-quit ; DOOM quit-message prompts when you quit Emacs
(emoji +unicode) ; 🙂
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
;;hydra
;;indent-guides ; highlighted indent columns
ligatures ; ligatures and symbols to make your code pretty again
;;minimap ; show a map of the code on the side
modeline ; snazzy, Atom-inspired modeline, plus API
;;nav-flash ; blink cursor line after big motions
;;neotree ; a project drawer, like NERDTree for vim
ophints ; highlight the region an operation acts on
(popup +defaults) ; tame sudden yet inevitable temporary windows
;;tabs ; a tab bar for Emacs
treemacs ; a project drawer, like neotree but cooler
unicode ; extended unicode support for various languages
(vc-gutter +pretty) ; vcs diff in the fringe
vi-tilde-fringe ; fringe tildes to mark beyond EOB
window-select ; visually switch windows
workspaces ; tab emulation, persistence & separate workspaces
;;zen ; distraction-free coding or writing
:editor
(evil +everywhere); come to the dark side, we have cookies
file-templates ; auto-snippets for empty files
fold ; (nigh) universal code folding
;;(format +onsave) ; automated prettiness
;;god ; run Emacs commands without modifier keys
;;lispy ; vim for lisp, for people who don't like vim
;;multiple-cursors ; editing in many places at once
;;objed ; text object editing for the innocent
;;parinfer ; turn lisp into python, sort of
;;rotate-text ; cycle region at point between text candidates
snippets ; my elves. They type so I don't have to
;;word-wrap ; soft wrapping with language-aware indent
:emacs
dired ; making dired pretty [functional]
electric ; smarter, keyword-based electric-indent
;;ibuffer ; interactive buffer management
undo ; persistent, smarter undo for your inevitable mistakes
vc ; version-control and Emacs, sitting in a tree
:term
;;eshell ; the elisp shell that works everywhere
;;shell ; simple shell REPL for Emacs
;;term ; basic terminal emulator for Emacs
vterm ; the best terminal emulation in Emacs
:checkers
syntax ; tasing you for every semicolon you forget
(spell +flyspell) ; tasing you for misspelling mispelling
grammar ; tasing grammar mistake every you make
:tools
;;ansible
biblio ; Writes a PhD for you (citation needed)
;;debugger ; FIXME stepping through code, to help you add bugs
;;direnv
;;docker
;;editorconfig ; let someone else argue about tabs vs spaces
;;ein ; tame Jupyter notebooks with emacs
(eval +overlay) ; run code, run (also, repls)
;;gist ; interacting with github gists
lookup ; navigate your code and its documentation
lsp ; M-x vscode
magit ; a git porcelain for Emacs
make ; run make tasks from Emacs
pass ; password manager for nerds
pdf ; pdf enhancements
;;prodigy ; FIXME managing external services & code builders
;;rgb ; creating color strings
;;taskrunner ; taskrunner for all your projects
;;terraform ; infrastructure as code
;;tmux ; an API for interacting with tmux
;;tree-sitter ; syntax and parsing, sitting in a tree...
;;upload ; map local to remote projects via ssh/ftp
:os
(:if IS-MAC macos) ; improve compatibility with macOS
;;tty ; improve the terminal Emacs experience
:lang
;;agda ; types of types of types of types...
;;beancount ; mind the GAAP
(cc +lsp) ; C > C++ == 1
;;clojure ; java with a lisp
common-lisp ; if you've seen one lisp, you've seen them all
;;coq ; proofs-as-programs
;;crystal ; ruby at the speed of c
;;csharp ; unity, .NET, and mono shenanigans
;;data ; config/data formats
;;(dart +flutter) ; paint ui and not much else
;;dhall
;;elixir ; erlang done right
;;elm ; care for a cup of TEA?
emacs-lisp ; drown in parentheses
;;erlang ; an elegant language for a more civilized age
;;ess ; emacs speaks statistics
;;factor
;;faust ; dsp, but you get to keep your soul
;;fortran ; in FORTRAN, GOD is REAL (unless declared INTEGER)
;;fsharp ; ML stands for Microsoft's Language
;;fstar ; (dependent) types and (monadic) effects and Z3
;;gdscript ; the language you waited for
;;(go +lsp) ; the hipster dialect
;;(graphql +lsp) ; Give queries a REST
;;(haskell +lsp) ; a language that's lazier than I am
;;hy ; readability of scheme w/ speed of python
;;idris ; a language you can depend on
;;json ; At least it ain't XML
;;(java +lsp) ; the poster child for carpal tunnel syndrome
;;javascript ; all(hope(abandon(ye(who(enter(here))))))
;;julia ; a better, faster MATLAB
;;kotlin ; a better, slicker Java(Script)
latex ; writing papers in Emacs has never been so fun
;;lean ; for folks with too much to prove
;;ledger ; be audit you can be
;;lua ; one-based indices? one-based indices
markdown ; writing docs for people to ignore
;;nim ; python + lisp at the speed of c
;;nix ; I hereby declare "nix geht mehr!"
;;ocaml ; an objective camel
org ; organize your plain life in plain text
;;php ; perl's insecure younger brother
;;plantuml ; diagrams for confusing people more
;;purescript ; javascript, but functional
python ; beautiful is better than ugly
;;qt ; the 'cutest' gui framework ever
;;racket ; a DSL for DSLs
;;raku ; the artist formerly known as perl6
;;rest ; Emacs as a REST client
rst ; ReST in peace
;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
(rust +lsp) ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
;;scala ; java, but good
;;(scheme +guile) ; a fully conniving family of lisps
sh ; she sells {ba,z,fi}sh shells on the C xor
;;sml
;;solidity ; do you need a blockchain? No.
;;swift ; who asked for emoji variables?
;;terra ; Earth and Moon in alignment for performance.
;;web ; the tubes
yaml ; JSON, but readable
;;zig ; C, but simpler
:email
(mu4e +org +gmail)
;;notmuch
;;(wanderlust +gmail)
:app
calendar
;;emms
;;everywhere ; *leave* Emacs!? You must be joking
;;irc ; how neckbeards socialize
;;(rss +org) ; emacs as an RSS reader
;;twitter ; twitter client https://twitter.com/vnought
:config
;;literate
(default +bindings +smartparens))

View File

@ -0,0 +1,52 @@
;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el
;; To install a package with Doom you must declare them here and run 'doom sync'
;; on the command line, then restart Emacs for the changes to take effect -- or
;; use 'M-x doom/reload'.
;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror:
;(package! some-package)
;; To install a package directly from a remote git repo, you must specify a
;; `:recipe'. You'll find documentation on what `:recipe' accepts here:
;; https://github.com/radian-software/straight.el#the-recipe-format
;(package! another-package
; :recipe (:host github :repo "username/repo"))
;; If the package you are trying to install does not contain a PACKAGENAME.el
;; file, or is located in a subdirectory of the repo, you'll need to specify
;; `:files' in the `:recipe':
;(package! this-package
; :recipe (:host github :repo "username/repo"
; :files ("some-file.el" "src/lisp/*.el")))
;; If you'd like to disable a package included with Doom, you can do so here
;; with the `:disable' property:
;(package! builtin-package :disable t)
;; You can override the recipe of a built in package without having to specify
;; all the properties for `:recipe'. These will inherit the rest of its recipe
;; from Doom or MELPA/ELPA/Emacsmirror:
;(package! builtin-package :recipe (:nonrecursive t))
;(package! builtin-package-2 :recipe (:repo "myfork/package"))
;; Specify a `:branch' to install a package from a particular branch or tag.
;; This is required for some packages whose default branch isn't 'master' (which
;; our package manager can't deal with; see radian-software/straight.el#279)
;(package! builtin-package :recipe (:branch "develop"))
;; Use `:pin' to specify a particular commit to install.
;(package! builtin-package :pin "1a2b3c4d5e")
;; Doom's packages are pinned to a specific commit and updated from release to
;; release. The `unpin!' macro allows you to unpin single packages...
;(unpin! pinned-package)
;; ...or multiple packages
;(unpin! pinned-package another-pinned-package)
;; ...Or *all* packages (NOT RECOMMENDED; will likely break things)
;(unpin! t)
(package! meson-mode)

68
config/git/aliases.zsh Normal file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env zsh
g() { [[ $# = 0 ]] && git status --short . || git $*; }
alias cdg='cd `git rev-parse --show-toplevel`'
alias git='noglob git'
alias ga='git add'
alias gap='git add --patch'
alias gb='git branch -av'
alias gop='git open'
alias gbl='git blame'
alias gc='git commit'
alias gcm='git commit -m'
alias gca='git commit --amend'
alias gcf='git commit --fixup'
alias gcl='git clone'
alias gco='git checkout'
alias gcoo='git checkout --'
alias gf='git fetch'
alias gi='git init'
alias gl='git log --graph --pretty="format:%C(yellow)%h%Creset %C(red)%G?%Creset%C(green)%d%Creset %s %Cblue(%cr) %C(bold blue)<%aN>%Creset"'
alias gll='git log --pretty="format:%C(yellow)%h%Creset %C(red)%G?%Creset%C(green)%d%Creset %s %Cblue(%cr) %C(bold blue)<%aN>%Creset"'
alias gL='gl --stat'
alias gp='git push'
alias gpl='git pull --rebase --autostash'
alias gs='git status --short .'
alias gss='git status'
alias gst='git stash'
alias gr='git reset HEAD'
alias gv='git rev-parse'
# fzf
if (( $+commands[fzf] )); then
__git_log () {
# format str implies:
# --abbrev-commit
# --decorate
git log \
--color=always \
--graph \
--all \
--date=short \
--format="%C(bold blue)%h%C(reset) %C(green)%ad%C(reset) | %C(white)%s %C(red)[%an] %C(bold yellow)%d"
}
_fzf_complete_git() {
ARGS="$@"
# these are commands I commonly call on commit hashes.
# cp->cherry-pick, co->checkout
if [[ $ARGS == 'git cp'* || \
$ARGS == 'git cherry-pick'* || \
$ARGS == 'git co'* || \
$ARGS == 'git checkout'* || \
$ARGS == 'git reset'* || \
$ARGS == 'git show'* || \
$ARGS == 'git log'* ]]; then
_fzf_complete "--reverse --multi" "$@" < <(__git_log)
else
eval "zle ${fzf_default_completion:-expand-or-complete}"
fi
}
_fzf_complete_git_post() {
sed -e 's/^[^a-z0-9]*//' | awk '{print $1}'
}
fi

3
config/git/attributes Normal file
View File

@ -0,0 +1,3 @@
*.lisp diff=lisp
*.el diff=lisp
*.org diff=org

58
config/git/config Normal file
View File

@ -0,0 +1,58 @@
[user]
name = Henrik Lissner
email = git@henrik.io
signingKey = FA1FADD9440B688CAA75A057B60957CA074D39A3
[commit]
gpgSign = true
[tag]
gpgSign = true
[core]
whitespace = trailing-space
[init]
defaultBranch = main
[github]
user = hlissner
[gitlab]
user = hlissner
[push]
autoSquash = true
[push]
default = current
gpgSign = if-asked
[pull]
rebase = true
[alias]
unadd = reset HEAD
# data analysis
ranked-authors = !git authors | sort | uniq -c | sort -n
emails = !git log --format="%aE" | sort -u
email-domains = !git log --format="%aE" | awk -F'@' '{print $2}' | sort -u
[filter "lfs"]
required = true
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
clean = git-lfs clean -- %f
[url "https://github.com/"]
insteadOf = gh:
[url "git@github.com:"]
insteadOf = ssh+gh:
[url "git@github.com:hlissner/"]
insteadOf = gh:/
[url "https://gitlab.com/"]
insteadOf = gl:
[url "https://gist.github.com/"]
insteadOf = gist:
[url "https://bitbucket.org/"]
insteadOf = bb:
[url "https://git.henrik.io"]
insteadOf = my:
[diff "lisp"]
xfuncname = "^(((;;;+ )|\\(|([ \t]+\\(((cl-|el-patch-)?def(un|var|macro|method|custom)|gb/))).*)$"
[diff "org"]
xfuncname = "^(\\*+ +.*)$"
[credential "https://github.com"]
helper =
helper = !gh auth git-credential
[credential "https://gist.github.com"]
helper =
helper = !gh auth git-credential

36
config/git/ignore Normal file
View File

@ -0,0 +1,36 @@
# For emacs:
*~
*.*~
\#*
.\#*
# For vim:
*.swp
.*.sw[a-z]
*.un~
.netrwhist
# OS generated files #
######################
.DS_Store?
.DS_Store
.CFUserTextEncoding
.Trash
.Xauthority
thumbs.db
Thumbs.db
Icon?
# Code stuffs #
###############
.ccls-cache/
.sass-cache/
__pycache__/
# Compiled thangs #
###################
*.class
*.exe
*.o
*.pyc
*.elc

View File

@ -0,0 +1,3 @@
alias rate=mpd-rate
alias mpcs='mpc search any'
alias mpcsp='mpc searchplay any'

424
config/ncmpcpp/bindings Normal file
View File

@ -0,0 +1,424 @@
def_key "k"
scroll_up
def_key "j"
scroll_down
def_key "K"
select_item
scroll_up
def_key "J"
select_item
scroll_down
def_key "h"
previous_column
def_key "l"
next_column
def_key "L"
show_lyrics
def_key "up"
volume_up
def_key "down"
volume_down
#def_key "right"
# next_column
#
#def_key "left"
# previous_column
#
#def_key "mouse"
# mouse_event
#
#def_key "up"
# scroll_up
#
#def_key "shift-up"
# select_item
# scroll_up
#
#def_key "down"
# scroll_down
#
#def_key "shift-down"
# select_item
# scroll_down
#
#def_key "["
# scroll_up_album
#
#def_key "]"
# scroll_down_album
#
#def_key "{"
# scroll_up_artist
#
#def_key "}"
# scroll_down_artist
#
#def_key "page_up"
# page_up
#
#def_key "page_down"
# page_down
#
#def_key "home"
# move_home
#
#def_key "end"
# move_end
#
#def_key "insert"
# select_item
#
#def_key "enter"
# enter_directory
#
#def_key "enter"
# toggle_output
#
#def_key "enter"
# run_action
#
#def_key "enter"
# play_item
#
#def_key "space"
# add_item_to_playlist
#
#def_key "space"
# toggle_lyrics_update_on_song_change
#
#def_key "space"
# toggle_visualization_type
#
#def_key "delete"
# delete_playlist_items
#
#def_key "delete"
# delete_browser_items
#
#def_key "delete"
# delete_stored_playlist
#
#def_key "right"
# next_column
#
#def_key "right"
# slave_screen
#
#def_key "right"
# volume_up
#
#def_key "+"
# volume_up
#
#def_key "left"
# previous_column
#
#def_key "left"
# master_screen
#
#def_key "left"
# volume_down
#
#def_key "-"
# volume_down
#
#def_key ":"
# execute_command
#
#def_key "tab"
# next_screen
#
#def_key "shift-tab"
# previous_screen
#
#def_key "f1"
# show_help
#
#def_key "1"
# show_playlist
#
#def_key "2"
# show_browser
#
#def_key "2"
# change_browse_mode
#
#def_key "3"
# show_search_engine
#
#def_key "3"
# reset_search_engine
#
#def_key "4"
# show_media_library
#
#def_key "4"
# toggle_media_library_columns_mode
#
#def_key "5"
# show_playlist_editor
#
#def_key "6"
# show_tag_editor
#
#def_key "7"
# show_outputs
#
#def_key "8"
# show_visualizer
#
#def_key "="
# show_clock
#
#def_key "@"
# show_server_info
#
#def_key "s"
# stop
#
#def_key "p"
# pause
#
#def_key ">"
# next
#
#def_key "<"
# previous
#
#def_key "ctrl-h"
# jump_to_parent_directory
#
#def_key "ctrl-h"
# replay_song
#
#def_key "backspace"
# jump_to_parent_directory
#
#def_key "backspace"
# replay_song
#
#def_key "f"
# seek_forward
#
#def_key "b"
# seek_backward
#
#def_key "r"
# toggle_repeat
#
#def_key "z"
# toggle_random
#
#def_key "y"
# save_tag_changes
#
#def_key "y"
# start_searching
#
#def_key "y"
# toggle_single
#
#def_key "R"
# toggle_consume
#
#def_key "Y"
# toggle_replay_gain_mode
#
#def_key "T"
# toggle_add_mode
#
#def_key "|"
# toggle_mouse
#
#def_key "#"
# toggle_bitrate_visibility
#
#def_key "Z"
# shuffle
#
#def_key "x"
# toggle_crossfade
#
#def_key "X"
# set_crossfade
#
#def_key "u"
# update_database
#
#def_key "ctrl-s"
# sort_playlist
#
#def_key "ctrl-s"
# toggle_browser_sort_mode
#
#def_key "ctrl-s"
# toggle_media_library_sort_mode
#
#def_key "ctrl-r"
# reverse_playlist
#
#def_key "ctrl-_"
# select_found_items
#
#def_key "/"
# find
#
#def_key "/"
# find_item_forward
#
#def_key "?"
# find
#
#def_key "?"
# find_item_backward
#
#def_key "."
# next_found_item
#
#def_key ","
# previous_found_item
#
#def_key "w"
# toggle_find_mode
#
#def_key "e"
# edit_song
#
#def_key "e"
# edit_library_tag
#
#def_key "e"
# edit_library_album
#
#def_key "e"
# edit_directory_name
#
#def_key "e"
# edit_playlist_name
#
#def_key "e"
# edit_lyrics
#
#def_key "i"
# show_song_info
#
#def_key "I"
# show_artist_info
#
#def_key "g"
# jump_to_position_in_song
#
#def_key "l"
# show_lyrics
#
#def_key "ctrl-v"
# select_range
#
#def_key "v"
# reverse_selection
#
#def_key "V"
# remove_selection
#
#def_key "B"
# select_album
#
#def_key "a"
# add_selected_items
#
#def_key "c"
# clear_playlist
#
#def_key "c"
# clear_main_playlist
#
#def_key "C"
# crop_playlist
#
#def_key "C"
# crop_main_playlist
#
#def_key "m"
# move_sort_order_up
#
#def_key "m"
# move_selected_items_up
#
#def_key "m"
# set_visualizer_sample_multiplier
#
#def_key "n"
# move_sort_order_down
#
#def_key "n"
# move_selected_items_down
#
#def_key "M"
# move_selected_items_to
#
#def_key "A"
# add
#
#def_key "S"
# save_playlist
#
#def_key "o"
# jump_to_playing_song
#
#def_key "G"
# jump_to_browser
#
#def_key "G"
# jump_to_playlist_editor
#
#def_key "~"
# jump_to_media_library
#
#def_key "E"
# jump_to_tag_editor
#
#def_key "U"
# toggle_playing_song_centering
#
#def_key "P"
# toggle_display_mode
#
#def_key "\\"
# toggle_interface
#
#def_key "!"
# toggle_separators_between_albums
#
#def_key "L"
# toggle_lyrics_fetcher
#
#def_key "F"
# toggle_fetching_lyrics_in_background
#
#def_key "ctrl-l"
# toggle_screen_lock
#
#def_key "`"
# toggle_library_tag_type
#
#def_key "`"
# refetch_lyrics
#
#def_key "`"
# add_random_items
#
#def_key "ctrl-p"
# set_selected_items_priority
#
#def_key "q"
# quit
#

433
config/ncmpcpp/config Normal file
View File

@ -0,0 +1,433 @@
##### directories ######
ncmpcpp_directory = ~/.config/ncmpcpp
## Directory for storing downloaded lyrics.
lyrics_directory = ~/music/.db/lyrics
##### connection settings #####
mpd_host = "~/.config/mpd/mpd.sock"
#mpd_host = "127.0.0.1"
#mpd_port = 6600
#mpd_connection_timeout = 5
## Needed for tag editor and file operations to work.
mpd_music_dir = ~/music
mpd_crossfade_time = 5
##### music visualizer #####
##
## Note: In order to make music visualizer work you'll
## need to use mpd fifo output, whose format parameter
## has to be set to 44100:16:1 for mono visualization
## or 44100:16:2 for stereo visualization. Example
## configuration (it has to be put into mpd.conf):
##
## audio_output {
## type "fifo"
## name "Visualizer feed"
## path "/tmp/mpd.fifo"
## format "44100:16:2"
## }
##
#visualizer_fifo_path = /tmp/mpd.fifo
##
## Note: Below parameter is needed for ncmpcpp
## to determine which output provides data for
## visualizer and thus allow syncing between
## visualization and sound as currently there
## are some problems with it.
##
#visualizer_output_name = Visualizer feed
##
## If you set format to 44100:16:2, make it 'yes'.
##
visualizer_in_stereo = no
##
## Multiply received samples by given value. Very
## useful for proper visualization of quiet music.
##
#visualizer_sample_multiplier = 1.0
##
## Note: Below parameter defines how often ncmpcpp
## has to "synchronize" visualizer and audio outputs.
## 30 seconds is optimal value, but if you experience
## synchronization problems, set it to lower value.
## Keep in mind that sane values start with >=10.
##
visualizer_sync_interval = 30
##
## Note: To enable spectrum frequency visualization
## you need to compile ncmpcpp with fftw3 support.
##
#
## Available values: spectrum, wave, wave_filled, ellipse.
visualizer_type = spectrum
## Alternative subset of 256 colors for terminals that support it.
#visualizer_color = 41, 83, 119, 155, 185, 215, 209, 203, 197, 161
visualizer_color = blue, cyan, green, yellow, magenta, red
#visualizer_look = ●▮
#
##### system encoding #####
##
## ncmpcpp should detect your charset encoding
## but if it failed to do so, you can specify
## charset encoding you are using here.
##
## Note: You can see whether your ncmpcpp build
## supports charset detection by checking output
## of `ncmpcpp --version`.
##
## Note: Since MPD uses UTF-8 by default, setting
## this option makes sense only if your encoding
## is different.
##
#system_encoding = ""
#
##### delays #####
#
## Time of inactivity (in seconds) after playlist
## highlighting will be disabled (0 = always on).
##
#playlist_disable_highlight_delay = 5
#
## Defines how long messages are supposed to be visible.
##
message_delay_time = 2
#
##### song format #####
##
## For a song format you can use:
##
## %l - length
## %f - filename
## %D - directory
## %a - artist
## %A - album artist
## %t - title
## %b - album
## %y - date
## %n - track number (01/12 -> 01)
## %N - full track info (01/12 -> 01/12)
## %g - genre
## %c - composer
## %p - performer
## %d - disc
## %C - comment
## %P - priority
## $R - begin right alignment
##
## If you want to make sure that a part of the format is displayed
## only when certain tags are present, you can archieve it by
## grouping them with brackets, e.g. '{%a - %t}' will be evaluated
## to 'ARTIST - TITLE' if both tags are present or '' otherwise.
## It is also possible to define a list of alternatives by providing
## several groups and separating them with '|', e.g. '{%t}|{%f}'
## will be evaluated to 'TITLE' or 'FILENAME' if the former is not
## present.
##
## Note: If you want to set limit on maximal length of a tag, just
## put the appropriate number between % and character that defines
## tag type, e.g. to make album take max. 20 terminal cells, use '%20b'.
##
## In addition, formats support markers used for text attributes.
## They are followed by character '$'. After that you can put:
##
## - 0 - default window color (discards all other colors)
## - 1 - black
## - 2 - red
## - 3 - green
## - 4 - yellow
## - 5 - blue
## - 6 - magenta
## - 7 - cyan
## - 8 - white
## - 9 - end of current color
## - b - bold text
## - u - underline text
## - r - reverse colors
## - a - use alternative character set
##
## If you don't want to use a non-color attribute anymore, just put it
## again, but this time insert character '/' between '$' and attribute
## character, e.g. {$b%t$/b}|{$r%f$/r} will display bolded title tag
## or filename with reversed colors.
##
## If you want to use 256 colors and/or background colors in formats
## (the naming scheme is described below in section about color
## definitions), it can be done with the syntax $(COLOR), e.g. to set
## the artist tag to one of the non-standard colors and make it have
## yellow background, you need to write $(197_yellow)%a$(end). Note
## that for standard colors this is interchangable with attributes
## listed above.
##
## Note: colors can be nested.
##
#
# song_list_format = {%a }$2%t$9 %C $R{%b }$2%25l$9
#song_list_format = {{$5%a$9 }{$7%A$9 }}{%n }$(16)%t$(end) $R{$8%l$9}
# song_status_format = {{%a{ $3%b{ (%y)}$9} }{$8%t$9}}|{%f}
#song_library_format = {%n - }{%t}|{%f}
song_list_format = "{$2%a$9} {$5%t$9} $R {$3%b$3} $9({$9%l$9})"
song_library_format = "%n %t"
song_status_format = "$b{$6%a$9 $1|$9} {$7%t$9} $1|$9 {$2%b$9} $1|$9 {$6%y$9} $1|$9"
#
#
#alternative_header_first_line_format = $b$1$aqqu$/a$9 {%t}|{%f} $1$atqq$/a$9$/b
#alternative_header_second_line_format = {{$4$b%a$/b$9}{ - $7%b$9}{ ($4%y$9)}}|{%D}
#
now_playing_prefix = "$(3_236)> "
now_playing_suffix = $0
#
#browser_playlist_prefix = "$2playlist$9 "
#
selected_item_prefix = "$(6_237)+ "
selected_item_suffix = $9
#
# modified_item_prefix = $3> $9
#
##
## Note: attributes are not supported for the following variables.
##
#song_window_title_format = {%a - }{%t}|{%f}
##
## Note: Below variables are used for sorting songs in browser.
## The sort mode determines how songs are sorted, and can be used
## in combination with a sort format to specify a custom sorting format.
## Available values for browser_sort_mode are "name", "mtime", "format"
## and "noop".
##
#
#browser_sort_mode = name
#browser_sort_format = {%a - }{%t}|{%f} {(%l)}
#
##### columns settings #####
##
## syntax of song columns list format is "column column etc."
##
## - syntax for each column is:
##
## (width of the column)[color of the column]{displayed tag}
##
## Note: Width is by default in %, if you want a column to
## have fixed size, add 'f' after the value, e.g. (10)[white]{a}
## will be the column that take 10% of screen (so the real width
## will depend on actual screen size), whereas (10f)[white]{a}
## will take 10 terminal cells, no matter how wide the screen is.
##
## - color is optional (if you want the default one,
## leave the field empty).
##
## Note: You can give a column additional attributes by putting appropriate
## character after displayed tag character. Available attributes are:
##
## - r - column will be right aligned
## - E - if tag is empty, empty tag marker won't be displayed
##
## You can also:
##
## - give a column custom name by putting it after attributes,
## separated with character ':', e.g. {lr:Length} gives you
## right aligned column of lengths named "Length".
##
## - define sequence of tags, that have to be displayed in case
## predecessor is empty in a way similar to the one in classic
## song format, i.e. using '|' character, e.g. {a|c|p:Owner}
## creates column named "Owner" that tries to display artist
## tag and then composer and performer if previous ones are
## not available.
##
song_columns_list_format = (3f)[241]{NEr:#} (8f)[5]{l} (22)[6]{a|A:Artist} (40)[9]{t|f:Title} (30)[13]{b}
#
##### various settings #####
#
##
## Note: Custom command that will be executed each
## time song changes. Useful for notifications etc.
##
execute_on_song_change = "mpd-notify-song"
#playlist_show_mpd_host = no
playlist_show_remaining_time = yes
playlist_shorten_total_times = yes
#playlist_separate_albums = no
#
##
## Note: Possible display modes: classic, columns.
##
playlist_display_mode = classic
browser_display_mode = columns
#search_engine_display_mode = classic
#playlist_editor_display_mode = classic
discard_colors_if_item_is_selected = yes
incremental_seeking = yes
seek_time = 2
volume_change_step = 10
#autocenter_mode = no
#centered_cursor = no
#
##
## Note: You can specify third character which will
## be used to build 'empty' part of progressbar.
##
progressbar_look = "─╼ "
#progressbar_boldness
progressbar_color = 1
progressbar_elapsed_color = 4
#
## Available values: database, playlist.
##
#default_place_to_search_in = database
#
## Available values: classic, alternative.
##
user_interface = alternative
#data_fetching_delay = yes
#
## Available values: artist, album_artist, date, genre, composer, performer.
##
#media_library_primary_tag = artist
#
## Available values: wrapped, normal.
##
#default_find_mode = wrapped
#default_tag_editor_pattern = %n - %t
header_visibility = yes
statusbar_visibility = yes
titles_visibility = no
#header_text_scrolling = yes
#cyclic_scrolling = no
#lines_scrolled = 2
#follow_now_playing_lyrics = no
#fetch_lyrics_for_current_song_in_background = no
#store_lyrics_in_song_dir = no
#generate_win32_compatible_filenames = yes
allow_for_physical_item_deletion = yes
#
##
## Note: If you set this variable, ncmpcpp will try to
## get info from last.fm in language you set and if it
## fails, it will fall back to english. Otherwise it will
## use english the first time.
##
## Note: Language has to be expressed as an ISO 639 alpha-2 code.
##
#lastfm_preferred_language = en
#show_hidden_files_in_local_browser = no
#
##
## How shall screen switcher work?
##
## - "previous" - switch between the current and previous screen.
## - "screen1,...,screenN" - switch between given sequence of screens.
##
## Screens available for use: help, playlist, browser, search_engine,
## media_library, playlist_editor, tag_editor, outputs, visualizer, clock.
##
#screen_switcher_mode = playlist, browser
#
##
## Note: You can define startup screen
## by choosing screen from the list above.
##
#startup_screen = playlist
#
##
## Note: You can define startup slave screen
## by choosing screen from the list above or
## an empty value for no slave screen.
##
#startup_slave_screen = ""
#startup_slave_screen_focus = no
#
##
## Default width of locked screen (in %).
## Acceptable values are from 20 to 80.
##
#
#locked_screen_width_part = 50
#ask_for_locked_screen_width_part = yes
jump_to_now_playing_song_at_start = yes
#ask_before_clearing_playlists = yes
#clock_display_seconds = no
#display_volume_level = no
#display_bitrate = yes
display_remaining_time = no
#
## Available values: none, basic, extended, perl.
##
#regular_expressions = perl
#
##
## Note: If below is enabled, ncmpcpp will ignore leading
## "The" word while sorting items in browser, tags in
## media library, etc.
##
#ignore_leading_the = no
#block_search_constraints_change_if_items_found = yes
#mouse_support = yes
#mouse_list_scroll_whole_page = yes
empty_tag_marker = <empty>
#tags_separator = " | "
tag_editor_extended_numeration = yes
#media_library_sort_by_mtime = no
enable_window_title = yes
#
##
## Note: You can choose default search mode for search
## engine. Available modes are:
##
## - 1 - use mpd built-in searching (no regexes, pattern matching)
## - 2 - use ncmpcpp searching (pattern matching with support for regexes,
## but if your mpd is on a remote machine, downloading big database
## to process it can take a while
## - 3 - match only exact values (this mode uses mpd function for searching
## in database and local one for searching in current playlist)
##
search_engine_default_search_mode = 2
external_editor = vim
## Note: set to yes if external editor is a console application.
use_console_editor = yes
##### colors definitions #####
##
## It is possible to set a background color by setting a color
## value "<foreground>_<background>", e.g. red_black will set
## foregound color to red and background color to black.
##
## In addition, for terminals that support 256 colors it
## is possible to set one of them by using a number in range
## [1, 256] instead of color name, e.g. numerical value
## corresponding to red_black is 2_1. To find out if the
## terminal supports 256 colors, run ncmpcpp and check out
## the bottom of the help screen for list of available colors
## and their numerical values.
##
## Note: due to technical limitations of ncurses, if 256 colors
## are used, it is possible to either use only the colors with
## default background color, or all pairs from 1_1 up to 254_127,
## depending on the ncurses version used.
##
colors_enabled = yes
empty_tag_color = 13
header_window_color = 241
volume_color = 239
state_line_color = 13
state_flags_color = 13
main_window_color = green
color1 = white
color2 = blue
# main_window_highlight_color = yellow
statusbar_color = 13
statusbar_time_color = 6
player_state_color = 14
alternative_ui_separator_color = 2
current_item_prefix = $(9_238)
current_item_suffix = $(end)
# active_column_color = red
window_border_color = 13
active_window_border = 13

27
config/tmux/aliases.zsh Normal file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env zsh
alias ta='tmux attach'
alias tl='tmux ls'
if [[ -n $TMUX ]]; then # From inside tmux
alias tf='tmux find-window'
# Detach all other clients to this session
alias mine='tmux detach -a'
# Send command to other tmux window
tt() {
tmux send-keys -t .+ C-u && \
tmux set-buffer "$*" && \
tmux paste-buffer -t .+ && \
tmux send-keys -t .+ Enter;
}
# Create new session (from inside one)
tn() {
local name="${1:-`basename $PWD`}"
TMUX= tmux new-session -d -s "$name"
tmux switch-client -t "$name"
tmux display-message "Session #S created"
}
else # From outside tmux
# Start grouped session so I can be in two different windows in one session
tdup() { tmux new-session -t "${1:-`tmux display-message -p '#S'`}"; }
fi

23
config/tmux/swap-pane.sh Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
CONF="$TMUX_PLUGINS_PATH/lastpane"
swap() { tmux swap-pane -s"$1" -t"$2"; }
target=
case $1 in
up) target="U" ;;
down) target="D" ;;
left) target="L" ;;
right) target="R" ;;
master) target="M" ;;
*) exit 1 ;;
esac
src_pane=$(tmux display-message -p "#P")
tmux select-pane -${target}
dst_pane=$(tmux display-message -p "#P")
tmux select-pane -${src_pane}
[[ "$target" == M ]] && dst_pane=0
swap "$src_pane" "$dst_pane"
tmux select-pane -t"$dst_pane"

123
config/tmux/tmux.conf Normal file
View File

@ -0,0 +1,123 @@
# tmux.conf
########################################
set -s default-terminal "xterm-256color"
setw -g automatic-rename on # rename window after current program
set -g renumber-windows on # renumber windows when one is closed
# Zero-based indexing is fine in programming languages, but not so much in a
# multiplexer when zero is on the other side of the keyboard.
set -g base-index 1
setw -g pane-base-index 1
# display tmux messages longer
set -g display-time 1500
set -g display-panes-time 800
# Address vim-mode switching delay (http://superuser.com/a/252717/65504)
set -s escape-time 0
set -sg repeat-time 600
set -g history-limit 50000
# Update status-{left,right} more often (default: 15)
set -g status-interval 5
# Rather than constraining window size to the maximum size of any client
# connected to the *session*, constrain window size to the maximum size of any
# client connected to *that window*. Much more reasonable.
setw -g aggressive-resize off
# For terminals that support them, propagate these events to programs that
# understand them.
set -s focus-events on
# Enable mouse + mouse wheel
set -g mouse on
########################################
# Keybinds #
########################################
# Rebind prefix to C-c. Press twice to send literal C-c.
unbind C-b
set -g prefix C-c
bind C-c send-prefix
# Vi-style keybinds
set -g status-keys vi
set -g mode-keys vi
bind c new-window -c "#{pane_current_path}"
bind v split-window -h -c "#{pane_current_path}"
bind s split-window -v -c "#{pane_current_path}"
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind H run '$TMUX_HOME/swap-pane.sh left'
bind J run '$TMUX_HOME/swap-pane.sh down'
bind K run '$TMUX_HOME/swap-pane.sh up'
bind L run '$TMUX_HOME/swap-pane.sh right'
bind M run '$TMUX_HOME/swap-pane.sh master'
bind o resize-pane -Z
bind S choose-session
bind W choose-window
bind / choose-session
bind . choose-window
# bind = select-layout tiled
bind | select-layout even-horizontal
bind _ select-layout even-vertical
# Disable confirmation
bind x kill-pane
bind X kill-window
bind q kill-session
bind Q kill-server
# Smart pane switching with awareness of vim splits
# See: https://github.com/christoomey/vim-tmux-navigator
is_vim='echo "#{pane_current_command}" | grep -iqE "(^|\/)g?(view|n?vim?x?)(diff)?$"'
bind -n C-h if-shell "$is_vim" "send-keys C-h" "select-pane -L"
bind -n C-j if-shell "$is_vim" "send-keys C-j" "select-pane -D"
bind -n C-k if-shell "$is_vim" "send-keys C-k" "select-pane -U"
bind -n C-l if-shell "$is_vim" "send-keys C-l" "select-pane -R"
bind -n C-\\ if-shell "$is_vim" "send-keys C-\\" "select-pane -l"
bind C-w last-pane
bind C-n next-window
bind C-p previous-window
# break pane into a window
bind = select-layout even-vertical
bind + select-layout even-horizontal
bind - break-pane
bind _ join-pane
# reload config without killing server
bind r source-file $DOTFILES/config/tmux/tmux.conf \; display-message " Config reloaded..".
bind ^r refresh-client
########################################
# Copy mode #
########################################
bind Enter copy-mode # enter copy mode
bind b list-buffers # list paster buffers
bind B choose-buffer # choose which buffer to paste from
bind p paste-buffer # paste from the top paste buffer
bind P run "xclip -selection clipboard -o | tmux load-buffer - ; tmux paste-buffer"
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind -T copy-mode-vi Escape send-keys -X cancel
bind -T copy-mode-vi C-g send-keys -X cancel
bind -T copy-mode-vi H send-keys -X start-of-line
bind -T copy-mode-vi L send-keys -X end-of-line
########################################
# Local config #
########################################
set -g @open-editor 'C-e'
set -g @open-S 'https://www.duckduckgo.com/'
set -g @resurrect-processes 'ssh sqlite3 "git log"'
run-shell $TMUX_HOME/extraInit
if '[ -f ~/.tmux.conf ]' 'source-file ~/.tmux.conf'

34
config/zsh/.zshenv Normal file
View File

@ -0,0 +1,34 @@
function _cache {
(( $+commands[$1] )) || return 1
local cache_dir="$XDG_CACHE_HOME/${SHELL##*/}"
local cache="$cache_dir/$1"
if [[ ! -f $cache || ! -s $cache ]]; then
echo "Caching $1"
mkdir -p $cache_dir
"$@" >$cache
chmod 600 $cache
fi
if [[ -o interactive ]]; then
source $cache || rm -f $cache
fi
}
function _source {
for file in "$@"; do
[ -r $file ] && source $file
done
}
# Be more restrictive with permissions; no one has any business reading things
# that don't belong to them.
if (( EUID != 0 )); then
umask 027
else
# Be even less permissive if root.
umask 077
fi
# Auto-generated by my nix config
_source ${0:a:h}/extra.zshenv
# If you have host-local configuration, this is where you'd put it
_source $ZDOTDIR/local.zshenv

52
config/zsh/.zshrc Normal file
View File

@ -0,0 +1,52 @@
#!/usr/bin/env zsh
source $ZDOTDIR/config.zsh
# NOTE ZGEN_DIR and ZGEN_SOURCE are forward-declared in modules/shell/zsh.nix
# NOTE Using zgenom because zgen is no longer maintained
if [ ! -d "$ZGEN_DIR" ]; then
echo "Installing jandamm/zgenom"
git clone https://github.com/jandamm/zgenom "$ZGEN_DIR"
fi
source $ZGEN_DIR/zgenom.zsh
# Check for plugin and zgenom updates every 7 days
# This does not increase the startup time.
zgenom autoupdate
if ! zgenom saved; then
echo "Initializing zgenom"
rm -f $ZDOTDIR/*.zwc(N) \
$XDG_CACHE_HOME/zsh/*(N) \
$ZGEN_INIT.zwc
# NOTE Be extra careful about plugin load order, or subtle breakage can
# emerge. This is the best order I've sussed out for these plugins.
zgenom load junegunn/fzf shell
zgenom load jeffreytse/zsh-vi-mode
zgenom load zdharma-continuum/fast-syntax-highlighting
zgenom load zsh-users/zsh-completions src
zgenom load zsh-users/zsh-autosuggestions
zgenom load zsh-users/zsh-history-substring-search
zgenom load romkatv/powerlevel10k powerlevel10k
zgenom load hlissner/zsh-autopair autopair.zsh
zgenom save
zgenom compile $ZDOTDIR
fi
## Bootstrap interactive sessions
if [[ $TERM != dumb ]]; then
autoload -Uz compinit && compinit -u -d $ZSH_CACHE/zcompdump
source $ZDOTDIR/keybinds.zsh
source $ZDOTDIR/completion.zsh
source $ZDOTDIR/aliases.zsh
# Auto-generated by nixos
_source $ZDOTDIR/extra.zshrc
# If you have host-local configuration, put it here
_source $ZDOTDIR/local.zshrc
_cache fasd --init posix-alias zsh-{hook,{c,w}comp{,-install}}
autopair-init
fi

84
config/zsh/aliases.zsh Normal file
View File

@ -0,0 +1,84 @@
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias -- -='cd -'
alias q=exit
alias clr=clear
alias sudo='sudo '
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias mkdir='mkdir -pv'
alias wget='wget -c'
alias path='echo -e ${PATH//:/\\n}'
alias ports='netstat -tulanp'
alias mk=make
alias gurl='curl --compressed'
alias shutdown='sudo shutdown'
alias reboot='sudo reboot'
# An rsync that respects gitignore
rcp() {
# -a = -rlptgoD
# -r = recursive
# -l = copy symlinks as symlinks
# -p = preserve permissions
# -t = preserve mtimes
# -g = preserve owning group
# -o = preserve owner
# -z = use compression
# -P = show progress on transferred file
# -J = don't touch mtimes on symlinks (always errors)
rsync -azPJ \
--include=.git/ \
--filter=':- .gitignore' \
--filter=":- $XDG_CONFIG_HOME/git/ignore" \
"$@"
}; compdef rcp=rsync
alias rcpd='rcp --delete --delete-after'
alias rcpu='rcp --chmod=go='
alias rcpdu='rcpd --chmod=go='
alias y='xclip -selection clipboard -in'
alias p='xclip -selection clipboard -out'
alias jc='journalctl -xe'
alias sc=systemctl
alias ssc='sudo systemctl'
if (( $+commands[exa] )); then
alias exa="exa --group-directories-first --git";
alias l="exa -blF";
alias ll="exa -abghilmu";
alias llm='ll --sort=modified'
alias la="LC_COLLATE=C exa -ablF";
alias tree='exa --tree'
fi
if (( $+commands[fasd] )); then
# fuzzy completion with 'z' when called without args
unalias z 2>/dev/null
function z {
[ $# -gt 0 ] && _z "$*" && return
cd "$(_z -l 2>&1 | fzf --height 40% --nth 2.. --reverse --inline-info +s --tac --query "${*##-* }" | sed 's/^[0-9,.]* *//')"
}
fi
autoload -U zmv
function take {
mkdir "$1" && cd "$1";
}; compdef take=mkdir
function zman {
PAGER="less -g -I -s '+/^ "$1"'" man zshall;
}
# Create a reminder with human-readable durations, e.g. 15m, 1h, 40s, etc
function r {
local time=$1; shift
sched "$time" "notify-send --urgency=critical 'Reminder' '$@'; ding";
}; compdef r=sched

97
config/zsh/completion.zsh Normal file
View File

@ -0,0 +1,97 @@
fpath+=( $ZDOTDIR/completions )
# Don't offer history completion; we have fzf, C-r, and
# zsh-history-substring-search for that.
ZSH_AUTOSUGGEST_STRATEGY=(completion)
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=30
# Expand partial paths, e.g. cd f/b/z == cd foo/bar/baz (assuming no ambiguity)
zstyle ':completion:*:paths' path-completion yes
# Fix slow one-by-one character pasting when bracketed-paste-magic is on. See
# zsh-users/zsh-syntax-highlighting#295
zstyle ':bracketed-paste-magic' active-widgets '.self-*'
# Options
setopt COMPLETE_IN_WORD # Complete from both ends of a word.
setopt PATH_DIRS # Perform path search even on command names with slashes.
setopt AUTO_MENU # Show completion menu on a successive tab press.
setopt AUTO_LIST # Automatically list choices on ambiguous completion.
# setopt AUTO_PARAM_SLASH # If completed parameter is a directory, add a trailing slash.
# setopt AUTO_PARAM_KEYS
# setopt FLOW_CONTROL # Disable start/stop characters in shell editor.
unsetopt MENU_COMPLETE # Do not autoselect the first completion entry.
unsetopt COMPLETE_ALIASES # Completion for aliases
# unsetopt ALWAYS_TO_END # Move cursor to the end of a completed word.
unsetopt CASE_GLOB
# Fuzzy match mistyped completions.
zstyle ':completion:*' completer _complete _list _match _approximate
zstyle ':completion:*:match:*' original only
zstyle ':completion:*:approximate:*' max-errors 1 numeric
# Increase the number of errors based on the length of the typed word.
zstyle -e ':completion:*:approximate:*' max-errors 'reply=($((($#PREFIX+$#SUFFIX)/3))numeric)'
# Don't complete unavailable commands.
zstyle ':completion:*:functions' ignored-patterns '(_*|.*|pre(cmd|exec))'
# Group matches and describe.
zstyle ':completion:*:corrections' format '%B%F{green}%d (errors: %e)%f%b'
zstyle ':completion:*:messages' format '%B%F{yellow}%d%f%b'
zstyle ':completion:*:warnings' format '%B%F{red}No such %d%f%b'
zstyle ':completion:*:errors' format '%B%F{red}No such %d%f%b'
zstyle ':completion:*:descriptions' format $'%{\e[35;1m%}%d%{\e[0m%}'
zstyle ':completion:*:default' list-prompt '%S%M matches%s'
# Omit parent and current directories from completion results when they are
# already named in the input.
zstyle ':completion:*:*:cd:*' ignore-parents parent pwd
# Merge multiple, consecutive slashes in paths
zstyle ':completion:*' squeeze-slashes true
# Don't wrap around when navigating to either end of history
zstyle ':completion:*:history-words' stop yes
zstyle ':completion:*:history-words' remove-all-dups yes
zstyle ':completion:*:history-words' list false
zstyle ':completion:*:history-words' menu yes
# Exclude internal/fake envvars
zstyle ':completion::*:(-command-|export):*' fake-parameters ${${${_comps[(I)-value-*]#*,}%%,*}:#-*-}
# Sory array completion candidates
zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
# Complete hostnames from ssh files too
zstyle -e ':completion:*:hosts' hosts 'reply=(
${=${=${=${${(f)"$(cat {/etc/ssh_,~/.ssh/known_}hosts(|2)(N) 2>/dev/null)"}%%[#| ]*}//\]:[0-9]*/ }//,/ }//\[/ }
${=${${${${(@M)${(f)"$(cat ~/.ssh/config 2>/dev/null)"}:#Host *}#Host }:#*\**}:#*\?*}}
)'
# Don't complete uninteresting users
zstyle ':completion:*:users' ignored-patterns \
adm amanda apache avahi beaglidx bin cacti canna clamav daemon \
dbus distcache dovecot fax ftp games gdm gkrellmd gopher \
hacluster haldaemon halt hsqldb ident junkbust ldap lp mail \
mailman mailnull mldonkey mysql nagios \
named netdump news nfsnobody nobody 'nixbld*' nscd ntp nut nx openvpn \
operator pcap postfix postgres privoxy pulse pvm quagga radvd \
rpc rpcuser rpm shutdown squid sshd sync 'systemd-*' uucp vcsa xfs '_*'
# ... unless we really want to.
zstyle '*' single-ignored show
# Ignore multiple entries.
zstyle ':completion:*:(rm|kill|diff):*' ignore-line other
zstyle ':completion:*:rm:*' file-patterns '*:all-files'
# PID completion for kill
zstyle ':completion:*:*:*:*:processes' command 'ps -u $LOGNAME -o pid,user,command -w'
zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#) ([0-9a-z-]#)*=01;36=0=01'
zstyle ':completion:*:*:kill:*' menu yes select
zstyle ':completion:*:*:kill:*' force-list always
zstyle ':completion:*:*:kill:*' insert-ids single
# Man
zstyle ':completion:*:manuals' separate-sections true
zstyle ':completion:*:manuals.(^1*)' insert-sections true
# Media Players
zstyle ':completion:*:*:mpg123:*' file-patterns '*.(mp3|MP3):mp3\ files *(-/):directories'
zstyle ':completion:*:*:mpg321:*' file-patterns '*.(mp3|MP3):mp3\ files *(-/):directories'
zstyle ':completion:*:*:ogg123:*' file-patterns '*.(ogg|OGG|flac):ogg\ files *(-/):directories'
zstyle ':completion:*:*:mocp:*' file-patterns '*.(wav|WAV|mp3|MP3|ogg|OGG|flac):ogg\ files *(-/):directories'
# SSH/SCP/RSYNC
zstyle ':completion:*:(scp|rsync):*' tag-order 'hosts:-host:host hosts:-domain:domain hosts:-ipaddr:ip\ address *'
zstyle ':completion:*:(scp|rsync):*' group-order users files all-files hosts-domain hosts-host hosts-ipaddr
zstyle ':completion:*:ssh:*' tag-order 'hosts:-host:host hosts:-domain:domain hosts:-ipaddr:ip\ address *'
zstyle ':completion:*:ssh:*' group-order users hosts-domain hosts-host users hosts-ipaddr
zstyle ':completion:*:(ssh|scp|rsync):*:hosts-host' ignored-patterns '*(.|:)*' loopback ip6-loopback localhost ip6-localhost broadcasthost
zstyle ':completion:*:(ssh|scp|rsync):*:hosts-domain' ignored-patterns '<->.<->.<->.<->' '^[-[:alnum:]]##(.[-[:alnum:]]##)##' '*@*'
zstyle ':completion:*:(ssh|scp|rsync):*:hosts-ipaddr' ignored-patterns '^(<->.<->.<->.<->|(|::)([[:xdigit:].]##:(#c,2))##(|%*))' '127.0.0.<->' '255.255.255.255' '::1' 'fe80::*'

36
config/zsh/completions/_hey Executable file
View File

@ -0,0 +1,36 @@
#compdef hey
_hey_dispatch () {
local cmd="$@"
local offset=$#
CURRENT=$((CURRENT-$offset))
words=($cmd "${words[$((2 + offset)),-1]}")
_$cmd
}
_hey_command_list () {
hey | sed '1,/Available commands:/d' | awk '{ print $1 }'
}
_hey () {
local -a commands
IFS=$'\n' commands=($(_hey_command_list))
if (( CURRENT == 2 )); then
_describe -t commands "hey commands" commands
return
fi
integer ret=1
case ${words[2]} in
ch|channel) _hey_dispatch nix-channel ;;
b|build) _hey_dispatch nix-build ;;
ch|check) _hey_dispatch nix flake check ;;
sh|show) _hey_dispatch nix flake show ;;
s|search) _hey_dispatch nix search nixpkgs ;;
-*) _hey_dispatch nix-env ;;
*) _message "Command not found: ${words[2]}" ;;
esac
return ret
}
_hey

84
config/zsh/config.zsh Normal file
View File

@ -0,0 +1,84 @@
# Stop TRAMP (in Emacs) from hanging or term/shell from echoing back commands
if [[ $TERM == dumb || -n $INSIDE_EMACS ]]; then
unsetopt zle prompt_cr prompt_subst
whence -w precmd >/dev/null && unfunction precmd
whence -w preexec >/dev/null && unfunction preexec
PS1='$ '
fi
## Plugins
# zgen
# we handle compinit ourselves...
export ZGEN_AUTOLOAD_COMPINIT=0
# zsh-vi-mode
export ZVM_INIT_MODE=sourcing
export ZVM_VI_INSERT_ESCAPE_BINDKEY=jk
# fasd
export _FASD_DATA="$XDG_CACHE_HOME/fasd"
export _FASD_VIMINFO="$XDG_CACHE_HOME/viminfo"
# fzf
if (( $+commands[fd] )); then
export FZF_DEFAULT_OPTS="--reverse --ansi"
export FZF_DEFAULT_COMMAND="fd ."
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND="fd -t d . $HOME"
fi
## ZSH configuration
# Treat these characters as part of a word.
WORDCHARS='_-*?[]~&.;!#$%^(){}<>'
unsetopt BRACE_CCL # Allow brace character class list expansion.
setopt COMBINING_CHARS # Combine zero-length punc chars (accents) with base char
setopt RC_QUOTES # Allow 'Henry''s Garage' instead of 'Henry'\''s Garage'
setopt HASH_LIST_ALL
unsetopt CORRECT_ALL
unsetopt NOMATCH
unsetopt MAIL_WARNING # Don't print a warning message if a mail file has been accessed.
unsetopt BEEP # Hush now, quiet now.
setopt IGNOREEOF
## Jobs
setopt LONG_LIST_JOBS # List jobs in the long format by default.
setopt AUTO_RESUME # Attempt to resume existing job before creating a new process.
setopt NOTIFY # Report status of background jobs immediately.
unsetopt BG_NICE # Don't run all background jobs at a lower priority.
unsetopt HUP # Don't kill jobs on shell exit.
unsetopt CHECK_JOBS # Don't report on jobs when shell exit.
## History
HISTFILE="$XDG_CACHE_HOME/zhistory"
HISTSIZE=100000 # Max events to store in internal history.
SAVEHIST=100000 # Max events to store in history file.
setopt BANG_HIST # Don't treat '!' specially during expansion.
setopt EXTENDED_HISTORY # Include start time in history records
setopt APPEND_HISTORY # Appends history to history file on exit
setopt INC_APPEND_HISTORY # Write to the history file immediately, not when the shell exits.
setopt SHARE_HISTORY # Share history between all sessions.
setopt HIST_EXPIRE_DUPS_FIRST # Expire a duplicate event first when trimming history.
setopt HIST_IGNORE_DUPS # Do not record an event that was just recorded again.
setopt HIST_IGNORE_ALL_DUPS # Remove old events if new event is a duplicate
setopt HIST_FIND_NO_DUPS # Do not display a previously found event.
setopt HIST_IGNORE_SPACE # Do not record an event starting with a space.
setopt HIST_SAVE_NO_DUPS # Do not write a duplicate event to the history file.
setopt HIST_REDUCE_BLANKS # Minimize unnecessary whitespace
setopt HIST_VERIFY # Do not execute immediately upon history expansion.
setopt HIST_BEEP # Beep when accessing non-existent history.
## Directories
DIRSTACKSIZE=9
unsetopt AUTO_CD # Implicit CD slows down plugins
setopt AUTO_PUSHD # Push the old directory onto the stack on cd.
setopt PUSHD_IGNORE_DUPS # Do not store duplicates in the stack.
setopt PUSHD_SILENT # Do not print the directory stack after pushd or popd.
setopt PUSHD_TO_HOME # Push to home directory when no argument is given.
setopt CDABLE_VARS # Change directory to a path stored in a variable.
setopt MULTIOS # Write to multiple descriptors.
setopt EXTENDED_GLOB # Use extended globbing syntax.
unsetopt GLOB_DOTS
unsetopt AUTO_NAME_DIRS # Don't add variable-stored paths to ~ list

65
config/zsh/keybinds.zsh Normal file
View File

@ -0,0 +1,65 @@
# Other conveniences
bindkey -M viins '^a' beginning-of-line
bindkey -M viins '^d' push-line-or-edit
# Up arrow:
bindkey '\e[A' history-substring-search-up
bindkey '\eOA' history-substring-search-up
# Down arrow:
bindkey '\e[B' history-substring-search-down
bindkey '\eOB' history-substring-search-down
# C-z to toggle current process (background/foreground)
fancy-ctrl-z () {
if [[ $#BUFFER -eq 0 ]]; then
BUFFER="fg"
zle accept-line
else
zle push-input
zle clear-screen
fi
}
zle -N fancy-ctrl-z
bindkey '^Z' fancy-ctrl-z
if (( $+commands[fzf] )); then
bindkey '^R' fzf-history-widget
fi
# Omni-Completion
if (( $+commands[fasd] )); then
bindkey -M viins '^x^f' fasd-complete-f # C-x C-f to do fasd-complete-f (only files)
bindkey -M viins '^x^d' fasd-complete-d # C-x C-d to do fasd-complete-d (only directories)
fi
# Completing words in buffer in tmux
if [ -n "$TMUX" ]; then
_tmux_pane_words() {
local expl
local -a w
if [[ -z "$TMUX_PANE" ]]; then
_message "not running inside tmux!"
return 1
fi
w=( ${(u)=$(tmux capture-pane \; show-buffer \; delete-buffer)} )
_wanted values expl 'words from current tmux pane' compadd -a w
}
zle -C tmux-pane-words-prefix complete-word _generic
zle -C tmux-pane-words-anywhere complete-word _generic
bindkey -M viins '^x^n' tmux-pane-words-prefix
bindkey -M viins '^x^o' tmux-pane-words-anywhere
zstyle ':completion:tmux-pane-words-(prefix|anywhere):*' completer _tmux_pane_words
zstyle ':completion:tmux-pane-words-(prefix|anywhere):*' ignore-line current
zstyle ':completion:tmux-pane-words-anywhere:*' matcher-list 'b:=* m:{A-Za-z}={a-zA-Z}'
fi
# Vim's C-x C-l in zsh
history-beginning-search-backward-then-append() {
zle history-beginning-search-backward
zle vi-add-eol
}
zle -N history-beginning-search-backward-then-append
bindkey -M viins '^x^l' history-beginning-search-backward-then-append

80
default.nix Normal file
View File

@ -0,0 +1,80 @@
{ inputs, config, lib, pkgs, ... }:
with lib;
with lib.custom;
{
imports = [
inputs.home-manager.nixosModules.home-manager
] ++ (mapModulesRec' (toString ./modules) import);
# Common config for all nixos machines
environment.variables = {
DOTFILES = config.dotfiles.dir;
DOTFILES_BIN = config.dotfiles.binDir;
};
# Configure nix and nixpkgs
environment.variables.NIXPKGS_ALLOW_UNFREE = "1";
nix =
let
filteredInputs = filterAttrs (n: _: n != "self") inputs;
nixPathInputs = mapAttrsToList (n: v: "${n}=${v}") filteredInputs;
registryInputs = mapAttrs (_: v: { flake = v; }) filteredInputs;
in {
package = pkgs.nixFlakes;
extraOptions = "experimental-features = nix-command flakes";
nixPath = nixPathInputs ++ [
"nixpkgs-overlays=${config.dotfiles.dir}/overlays"
"dotfiles=${config.dotfiles.dir}"
];
registry = registryInputs // { dotfiles.flake = inputs.self; };
settings = {
substituters = [
"https://nix-community.cachix.org"
];
trusted-public-keys = [
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
auto-optimise-store = true;
};
gc = {
automatic = mkDefault true;
dates = mkDefault "weekly";
options = mkDefault "--delete-older-than 14d";
};
};
system.configurationRevision = with inputs; mkIf (self ? rev) self.rev;
system.stateVersion = "21.05";
## Some reasonable, global defaults
# This is here to appease 'nix flake check' for generic hosts with no
# hardware-configuration.nix or fileSystem config.
fileSystems."/".device = mkDefault "/dev/disk/by-label/nixos";
# The global useDHCP flag is deprecated, therefore explicitly set to false
# here. Per-interface useDHCP will be mandatory in the future, so we enforce
# this default behavior here.
networking.useDHCP = mkDefault false;
# Use the latest kernel
boot = {
kernelPackages = mkDefault pkgs.linuxPackages_latest;
loader = {
efi.canTouchEfiVariables = mkDefault true;
systemd-boot.configurationLimit = 10;
systemd-boot.enable = mkDefault true;
};
};
environment.systemPackages = with pkgs; [
bind
cached-nix-shell
coreutils
git
vim
wget
curl
gnumake
unzip
];
}

70
flake.nix Normal file
View File

@ -0,0 +1,70 @@
{
description = "Who said nix-nix? It's a dotfiles!";
inputs = {
# Core dependencies.
nixpkgs.url = "nixpkgs/nixos-unstable";
nixpkgs-unstable.url = "nixpkgs/nixpkgs-unstable";
home-manager = {
url = "github:rycee/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs";
};
nur = {
url = "github:nix-community/NUR";
inputs.nixpkgs.follows = "nixpkgs";
};
# Extras
emacs-overlay.url = "github:nix-community/emacs-overlay";
nixos-hardware.url = "github:nixos/nixos-hardware";
devenv.url = "github:cachix/devenv/v0.6.2";
};
outputs = inputs @ {
self, nixpkgs, nixpkgs-unstable, nur,
emacs-overlay, nixos-hardware, devenv,
...
}:
let
inherit (builtins) baseNameOf;
inherit (lib) nixosSystem mkIf removeSuffix attrNames attrValues;
inherit (lib.custom) mapModules mapModulesRec mapHosts;
system = "x86_64-linux";
lib = nixpkgs.lib.extend (self: super: {
custom = import ./lib {
inherit pkgs inputs; lib = self;
};
});
mkPkgs = pkgs: extraOverlays: import pkgs {
inherit system;
config.allowUnfree = true;
overlays = extraOverlays ++ (lib.attrValues self.overlays);
};
pkgs = mkPkgs nixpkgs [ self.overlay ];
unstable = mkPkgs nixpkgs-unstable [];
in {
lib = lib.custom;
overlay = final: prev: {
inherit unstable;
user = self.packages.${system};
devenv = devenv.packages.${system}.devenv;
};
overlays = mapModules ./overlays import;
packages.${system} = mapModules ./packages (p: pkgs.callPackage p {});
nixosModules = { dotfiles = import ./.; } // mapModulesRec ./modules import;
nixosConfigurations = mapHosts ./hosts { inherit system; };
devShell.${system} = import ./shell.nix { inherit pkgs; };
};
}

32
hosts/common.nix Normal file
View File

@ -0,0 +1,32 @@
{ config, lib, ... }:
with builtins;
with lib;
let
blocklist = fetchurl https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts;
in {
networking.extraHosts = ''
192.168.156.1 router.home
# Hosts
192.168.1156.28 elnafo.home
# Block garbage
${optionalString config.services.xserver.enable (readFile blocklist)}
'';
## Location config -- since Toronto is my 127.0.0.1
time.timeZone = mkDefault "Asia/Yekaterinburg";
i18n.defaultLocale = mkDefault "en_US.UTF-8";
i18n.extraLocaleSettings = {
LC_ADDRESS = "en_US.UTF-8";
LC_IDENTIFICATION = "en_US.UTF-8";
LC_MEASUREMENT = "en_US.UTF-8";
LC_MONETARY = "en_US.UTF-8";
LC_NAME = "en_US.UTF-8";
LC_NUMERIC = "en_US.UTF-8";
LC_PAPER = "en_US.UTF-8";
LC_TELEPHONE = "en_US.UTF-8";
LC_TIME = "en_US.UTF-8";
};
}

78
hosts/elnafo/default.nix Normal file
View File

@ -0,0 +1,78 @@
{ pkgs, config, lib, ... }:
{
imports = [
../common.nix
./hardware-configuration.nix
];
## Modules
modules = {
desktop = {
gnome.enable = true;
audio.enable = true;
browsers = {
default = "firefox";
firefox.enable = true;
};
gaming = {
steam.enable = true;
};
graphics.enable = true;
media = {
recording.enable = true;
};
term = {
default = "kgx";
};
vm = {
qemu.enable = true;
};
};
dev = {
cc.enable = true;
rust.enable = true;
python.enable = true;
};
editors = {
default = "nvim";
emacs.enable = true;
vim.enable = true;
};
shell = {
direnv.enable = true;
git.enable = true;
gnupg.enable = true;
tmux.enable = true;
zsh.enable = true;
};
services = {
ssh.enable = true;
};
};
networking = {
networkmanager.enable = true;
useDHCP = lib.mkDefault true;
firewall.enable = true;
};
## Local config
programs = {
dconf.enable = true;
ssh.startAgent = true;
};
## Services
services.printing.enable = true;
services.xserver = {
layout = "us";
xkbVariant = "";
videoDrivers = [ "nvidia" ];
};
services.openssh.startWhenNeeded = true;
system.stateVersion = "22.11";
}

View File

@ -0,0 +1,90 @@
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [ "${modulesPath}/installer/scan/not-detected.nix" ];
boot = {
initrd = {
availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ];
kernelModules = [];
};
extraModulePackages = [];
kernelModules = [ "kvm-amd" "coretemp" ];
kernelParams = [];
kernelPackages = pkgs.linuxPackages_latest;
# Refuse ICMP echo requests on my desktop/laptop; nobody has any business
# pinging them, unlike my servers.
kernel.sysctl."net.ipv4.icmp_echo_ignore_broadcasts" = 1;
loader = {
systemd-boot.enable = false;
efi = {
canTouchEfiVariables = true;
efiSysMountPoint = "/boot/efi";
};
grub = {
devices = [ "nodev" ];
enable = true;
efiSupport = true;
# version = 2;
useOSProber = true;
};
};
};
# Modules
modules.hardware = {
audio.enable = true;
fs = {
enable = true;
ssd.enable = true;
};
nvidia.enable = true;
sensors.enable = true;
};
# CPU
#nix.settings.max-jobs = lib.mkDefault 16;
#powerManagement.cpuFreqGovernor = "performance";
hardware.cpu.amd.updateMicrocode = true;
# Nvidia, OpenGL
hardware = {
nvidia.nvidiaSettings = true;
nvidia.modesetting.enable = true;
opengl.enable = true;
opengl.driSupport32Bit = true;
};
# Storage
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/d53d2bcd-36c7-4273-b5b4-6563692ee16c";
fsType = "ext4";
options = [ "noatime" ];
};
"/boot/efi" = {
device = "/dev/disk/by-uuid/3117-8F91";
fsType = "vfat";
};
"/home" = {
device = "/dev/disk/by-uuid/b9e2a42a-4db9-4389-bf75-457bb4da2a30";
fsType = "ext4";
options = [ "noatime" ];
};
"/mnt/vault" = {
device = "/dev/disk/by-uuid/34cbaf1c-19c7-412f-8b51-41410f3fee2a";
fsType = "btrfs";
options = [
"nofail" "noauto" "noatime" "x-systemd.automount" "x-systemd.idle-timeout=5min"
"nodev" "nosuid" "noexec"
];
};
};
swapDevices = [];
}

21
hosts/niximg.nix Normal file
View File

@ -0,0 +1,21 @@
{ modulesPath, pkgs, config, ... }:
{
imports = [
"${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix"
];
# In case of proprietary wireless drivers
nixpkgs.config.allowUnfree = true;
hardware.enableRedistributableFirmware = true;
boot.kernelPackages = pkgs.linuxKernel.packages.linux_5_16;
boot.kernelModules = [ "wl" ];
boot.extraModulePackages = [ config.boot.kernelPackages.broadcom_sta ];
environment.systemPackages = with pkgs; [
nixFlakes
zsh
git
];
}
# nix-build '<nixpkgs/nixos>' -A config.system.build.isoImage -I nixos-config=./default.nix

22
lib/attrs.nix Normal file
View File

@ -0,0 +1,22 @@
{ lib, ... }:
with builtins;
with lib;
rec {
# attrsToList
attrsToList = attrs: mapAttrsToList (name: value: { inherit name value; }) attrs;
# mapFilterAttrs ::
# (name -> value -> bool)
# (name -> value -> { name = any; value = any; })
# attrs
mapFilterAttrs = pred: f: attrs: filterAttrs pred (mapAttrs' f attrs);
# Generate an attribute set by mapping a function over a list of values.
genAttrs' = values: f: listToAttrs (map f values);
# anyAttrs :: (name -> value -> bool) attrs
anyAttrs = pred: attrs: any (attr: pred attr.name attr.value) (attrsToList attrs);
# countAttrs :: (name -> value -> bool) attrs
countAttrs = pred: attrs: count (attr: pred attr.name attr.value) (attrsToList attrs);
}

15
lib/default.nix Normal file
View File

@ -0,0 +1,15 @@
{ inputs, lib, pkgs, ... }:
let
inherit (lib) makeExtensible attrValues foldr;
inherit (modules) mapModules;
modules = import ./modules.nix {
inherit lib;
self.attrs = import ./attrs.nix { inherit lib; self = {}; };
};
customlib = makeExtensible (self: with self;
mapModules ./. (file: import file { inherit self lib pkgs inputs; })
);
in
customlib.extend (self: super: foldr (a: b: a // b) {} (attrValues super))

52
lib/modules.nix Normal file
View File

@ -0,0 +1,52 @@
{ self, lib, ... }:
let
inherit (builtins) attrValues readDir pathExists concatLists;
inherit (lib) id mapAttrsToList filterAttrs hasPrefix hasSuffix nameValuePair removeSuffix;
inherit (self.attrs) mapFilterAttrs;
in
rec {
mapModules = dir: fn:
mapFilterAttrs
(n: v: v != null && !(hasPrefix "_" n))
(n: v:
let
path = "${toString dir}/${n}";
in
if v == "directory" && pathExists "${path}/default.nix"
then nameValuePair n (fn path)
else
if v == "regular" && n != "default.nix" && hasSuffix ".nix" n
then nameValuePair (removeSuffix ".nix" n) (fn path)
else nameValuePair "" null
)
(readDir dir);
mapModules' = dir: fn: attrValues (mapModules dir fn);
mapModulesRec = dir: fn:
mapFilterAttrs
(n: v: v != null && !(hasPrefix "_" n))
(n: v:
let
path = "${toString dir}/${n}";
in
if v == "directory"
then nameValuePair n (mapModulesRec path fn)
else
if v == "regular" && n != "default.nix" && hasSuffix ".nix" n
then nameValuePair (removeSuffix ".nix" n) (fn path)
else nameValuePair "" null
)
(readDir dir);
mapModulesRec' = dir: fn:
let
dirs = mapAttrsToList
(k: _: "${dir}/${k}")
(filterAttrs (n: v: v == "directory" && !(hasPrefix "_" n))
(readDir dir));
files = attrValues (mapModules dir id);
paths = files ++ concatLists (map (d: mapModulesRec' d id) dirs);
in
map fn paths;
}

23
lib/nixos.nix Normal file
View File

@ -0,0 +1,23 @@
{ inputs, lib, pkgs, ... }:
with lib;
with lib.custom;
let
sys = "x86_64-linux";
in {
mkHost = path: attrs @ { system ? sys, ... }:
nixosSystem {
inherit system;
specialArgs = { inherit lib inputs system; };
modules = [
{
nixpkgs.pkgs = pkgs;
networking.hostName = mkDefault (removeSuffix ".nix" (baseNameOf path));
}
(filterAttrs (n: v: !elem n [ "system" ]) attrs)
../. # /default.nix
(import path)
];
};
mapHosts = dir: attrs @ { system ? system, ... }: mapModules dir (hostPath: mkHost hostPath attrs);
}

15
lib/options.nix Normal file
View File

@ -0,0 +1,15 @@
{ lib, ... }:
let
inherit (lib) mkOption types;
in
rec {
mkOpt = type: default: mkOption { inherit type default; };
mkOpt' = type: default: description: mkOption { inherit type default description; };
mkBoolOpt = default: mkOption {
inherit default;
type = types.bool;
example = true;
};
}

View File

@ -0,0 +1,16 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.apps.godot;
in {
options.modules.desktop.apps.godot = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = with pkgs; [
godot
];
};
}

View File

@ -0,0 +1,19 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.audio;
in {
options.modules.desktop.audio = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = with pkgs; [
lollypop
vlc
beets
flacon
];
};
}

View File

@ -0,0 +1,14 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.browsers;
in {
options.modules.desktop.browsers = {
default = mkOpt (with types; nullOr str) null;
};
config = mkIf (cfg.default != null) {
env.BROWSER = cfg.default;
};
}

View File

@ -0,0 +1,226 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.browsers.firefox;
in {
options.modules.desktop.browsers.firefox = with types; {
enable = mkBoolOpt false;
profileName = mkOpt types.str config.user.name;
settings = mkOpt' (attrsOf (oneOf [ bool int str ])) {} ''
Firefox preferences to set in <filename>user.js</filename>
'';
extraConfig = mkOpt' lines "" ''
Extra lines to add to <filename>user.js</filename>
'';
userChrome = mkOpt' lines "" "CSS Styles for Firefox's interface";
userContent = mkOpt' lines "" "Global CSS Styles for websites";
};
config = mkIf cfg.enable (mkMerge [ {
user.packages = with pkgs; [
# firefox-wayland
unstable.firefox-bin
(makeDesktopItem {
name = "firefox-private";
desktopName = "Firefox (Private)";
genericName = "Open a private Firefox window";
icon = "firefox";
exec = "${unstable.firefox-bin}/bin/firefox --private-window";
categories = [ "Network" ];
})
];
# Prevent auto-creation of ~/Desktop. The trailing slash is necessary; see
# https://bugzilla.mozilla.org/show_bug.cgi?id=1082717
env.XDG_DESKTOP_DIR = "$HOME/";
modules.desktop.browsers.firefox.settings = {
# Default to dark theme in DevTools panel
"devtools.theme" = "dark";
# Enable ETP for decent security (makes firefox containers and many
# common security/privacy add-ons redundant).
"browser.contentblocking.category" = "strict";
"privacy.donottrackheader.enabled" = true;
"privacy.donottrackheader.value" = 1;
"privacy.purge_trackers.enabled" = true;
# Your customized toolbar settings are stored in
# 'browser.uiCustomization.state'. This tells firefox to sync it between
# machines. WARNING: This may not work across OSes. Since I use NixOS on
# all the machines I use Firefox on, this is no concern to me.
"services.sync.prefs.sync.browser.uiCustomization.state" = true;
# Enable userContent.css and userChrome.css for our theme modules
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
# Stop creating ~/Downloads!
"browser.download.dir" = "${config.user.home}/downloads";
# Don't use the built-in password manager. A nixos user is more likely
# using an external one (you are using one, right?).
"signon.rememberSignons" = false;
# Do not check if Firefox is the default browser
"browser.shell.checkDefaultBrowser" = false;
# Disable the "new tab page" feature and show a blank tab instead
# https://wiki.mozilla.org/Privacy/Reviews/New_Tab
# https://support.mozilla.org/en-US/kb/new-tab-page-show-hide-and-customize-top-sites#w_how-do-i-turn-the-new-tab-page-off
"browser.newtabpage.enabled" = false;
"browser.newtab.url" = "about:blank";
# Disable Activity Stream
# https://wiki.mozilla.org/Firefox/Activity_Stream
"browser.newtabpage.activity-stream.enabled" = false;
"browser.newtabpage.activity-stream.telemetry" = false;
# Disable new tab tile ads & preload
# http://www.thewindowsclub.com/disable-remove-ad-tiles-from-firefox
# http://forums.mozillazine.org/viewtopic.php?p=13876331#p13876331
# https://wiki.mozilla.org/Tiles/Technical_Documentation#Ping
# https://gecko.readthedocs.org/en/latest/browser/browser/DirectoryLinksProvider.html#browser-newtabpage-directory-source
# https://gecko.readthedocs.org/en/latest/browser/browser/DirectoryLinksProvider.html#browser-newtabpage-directory-ping
"browser.newtabpage.enhanced" = false;
"browser.newtabpage.introShown" = true;
"browser.newtab.preload" = false;
"browser.newtabpage.directory.ping" = "";
"browser.newtabpage.directory.source" = "data:text/plain,{}";
# Reduce search engine noise in the urlbar's completion window. The
# shortcuts and suggestions will still work, but Firefox won't clutter
# its UI with reminders that they exist.
"browser.urlbar.suggest.searches" = false;
"browser.urlbar.shortcuts.bookmarks" = false;
"browser.urlbar.shortcuts.history" = false;
"browser.urlbar.shortcuts.tabs" = false;
"browser.urlbar.showSearchSuggestionsFirst" = false;
"browser.urlbar.speculativeConnect.enabled" = false;
# https://bugzilla.mozilla.org/1642623
"browser.urlbar.dnsResolveSingleWordsAfterSearch" = 0;
# https://blog.mozilla.org/data/2021/09/15/data-and-firefox-suggest/
"browser.urlbar.suggest.quicksuggest.nonsponsored" = false;
"browser.urlbar.suggest.quicksuggest.sponsored" = false;
# Show whole URL in address bar
"browser.urlbar.trimURLs" = false;
# Disable some not so useful functionality.
"browser.disableResetPrompt" = true; # "Looks like you haven't started Firefox in a while."
"browser.onboarding.enabled" = false; # "New to Firefox? Let's get started!" tour
"browser.aboutConfig.showWarning" = false; # Warning when opening about:config
"media.videocontrols.picture-in-picture.video-toggle.enabled" = false;
"extensions.pocket.enabled" = false;
"extensions.shield-recipe-client.enabled" = false;
"reader.parse-on-load.enabled" = false; # "reader view"
# Security-oriented defaults
"security.family_safety.mode" = 0;
# https://blog.mozilla.org/security/2016/10/18/phasing-out-sha-1-on-the-public-web/
"security.pki.sha1_enforcement_level" = 1;
# https://github.com/tlswg/tls13-spec/issues/1001
"security.tls.enable_0rtt_data" = false;
# Use Mozilla geolocation service instead of Google if given permission
"geo.provider.network.url" = "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%";
"geo.provider.use_gpsd" = false;
# https://support.mozilla.org/en-US/kb/extension-recommendations
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr" = false;
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons" = false;
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features" = false;
"extensions.htmlaboutaddons.recommendations.enabled" = false;
"extensions.htmlaboutaddons.discover.enabled" = false;
"extensions.getAddons.showPane" = false; # uses Google Analytics
"browser.discovery.enabled" = false;
# Reduce File IO / SSD abuse
# Otherwise, Firefox bombards the HD with writes. Not so nice for SSDs.
# This forces it to write every 30 minutes, rather than 15 seconds.
"browser.sessionstore.interval" = "1800000";
# Disable battery API
# https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager
# https://bugzilla.mozilla.org/show_bug.cgi?id=1313580
"dom.battery.enabled" = false;
# Disable "beacon" asynchronous HTTP transfers (used for analytics)
# https://developer.mozilla.org/en-US/docs/Web/API/navigator.sendBeacon
"beacon.enabled" = false;
# Disable pinging URIs specified in HTML <a> ping= attributes
# http://kb.mozillazine.org/Browser.send_pings
"browser.send_pings" = false;
# Disable gamepad API to prevent USB device enumeration
# https://www.w3.org/TR/gamepad/
# https://trac.torproject.org/projects/tor/ticket/13023
"dom.gamepad.enabled" = false;
# Don't try to guess domain names when entering an invalid domain name in URL bar
# http://www-archive.mozilla.org/docs/end-user/domain-guessing.html
"browser.fixup.alternate.enabled" = false;
# Disable telemetry
# https://wiki.mozilla.org/Platform/Features/Telemetry
# https://wiki.mozilla.org/Privacy/Reviews/Telemetry
# https://wiki.mozilla.org/Telemetry
# https://www.mozilla.org/en-US/legal/privacy/firefox.html#telemetry
# https://support.mozilla.org/t5/Firefox-crashes/Mozilla-Crash-Reporter/ta-p/1715
# https://wiki.mozilla.org/Security/Reviews/Firefox6/ReviewNotes/telemetry
# https://gecko.readthedocs.io/en/latest/browser/experiments/experiments/manifest.html
# https://wiki.mozilla.org/Telemetry/Experiments
# https://support.mozilla.org/en-US/questions/1197144
# https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/internals/preferences.html#id1
"toolkit.telemetry.unified" = false;
"toolkit.telemetry.enabled" = false;
"toolkit.telemetry.server" = "data:,";
"toolkit.telemetry.archive.enabled" = false;
"toolkit.telemetry.coverage.opt-out" = true;
"toolkit.coverage.opt-out" = true;
"toolkit.coverage.endpoint.base" = "";
"experiments.supported" = false;
"experiments.enabled" = false;
"experiments.manifest.uri" = "";
"browser.ping-centre.telemetry" = false;
# https://mozilla.github.io/normandy/
"app.normandy.enabled" = false;
"app.normandy.api_url" = "";
"app.shield.optoutstudies.enabled" = false;
# Disable health reports (basically more telemetry)
# https://support.mozilla.org/en-US/kb/firefox-health-report-understand-your-browser-perf
# https://gecko.readthedocs.org/en/latest/toolkit/components/telemetry/telemetry/preferences.html
"datareporting.healthreport.uploadEnabled" = false;
"datareporting.healthreport.service.enabled" = false;
"datareporting.policy.dataSubmissionEnabled" = false;
# Disable crash reports
"breakpad.reportURL" = "";
"browser.tabs.crashReporting.sendReport" = false;
"browser.crashReports.unsubmittedCheck.autoSubmit2" = false; # don't submit backlogged reports
# Disable Form autofill
# https://wiki.mozilla.org/Firefox/Features/Form_Autofill
"browser.formfill.enable" = false;
"extensions.formautofill.addresses.enabled" = false;
"extensions.formautofill.available" = "off";
"extensions.formautofill.creditCards.available" = false;
"extensions.formautofill.creditCards.enabled" = false;
"extensions.formautofill.heuristics.enabled" = false;
};
# Use a stable profile name so we can target it in themes
home.file = let cfgPath = ".mozilla/firefox"; in {
"${cfgPath}/profiles.ini".text = ''
[Profile0]
Name=default
IsRelative=1
Path=${cfg.profileName}.default
Default=1
[General]
StartWithLastProfile=1
Version=2
'';
"${cfgPath}/${cfg.profileName}.default/user.js" = mkIf (cfg.settings != {} || cfg.extraConfig != "") {
text = ''
${concatStrings (mapAttrsToList (name: value: ''
user_pref("${name}", ${builtins.toJSON value});
'') cfg.settings)}
${cfg.extraConfig}
'';
};
"${cfgPath}/${cfg.profileName}.default/chrome/userChrome.css" = mkIf (cfg.userChrome != "") {
text = cfg.userChrome;
};
"${cfgPath}/${cfg.profileName}.default/chrome/userContent.css" = mkIf (cfg.userContent != "") {
text = cfg.userContent;
};
};
}]);
}

View File

@ -0,0 +1,62 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop;
in {
config = mkIf config.services.xserver.enable {
assertions = [
{
assertion = (countAttrs (n: v: n == "enable" && value) cfg) < 2;
message = "Can't have more than one desktop environment enabled at a time";
}
{
assertion =
let
srv = config.services;
in
srv.xserver.enable || srv.sway.enable ||
!(anyAttrs (n: v: isAttrs v && anyAttrs (n: v: isAttrs v && v.enable)) cfg);
message = "Can't enable a desktop app without a desktop environment";
}
];
user.packages = with pkgs; [
xclip
xdotool
qgnomeplatform # QPlatformTheme for a better Qt application inclusion in GNOME
libsForQt5.qtstyleplugin-kvantum # SVG-based Qt5 theme engine plus a config tool and extra theme
];
fonts = {
fontDir.enable = true;
enableGhostscriptFonts = true;
fonts = with pkgs; [
ubuntu_font_family
dejavu_fonts
symbola
nerdfonts
];
};
# Try really hard to get QT to respect my GTK theme.
env = {
GTK_DATA_PREFIX = [ "${config.system.path}" ];
QT_QPA_PLATFORMTHEME = "gnome";
QT_STYLE_OVERRIDE = "kvantum";
}
services.xserver.displayManager.sessionCommands = ''
# GTK2_RC_FILES must be available to the display manager.
export GTK2_RC_FILES="$XDG_CONFIG_HOME/gtk-2.0/gtkrc"
'';
# Clean up leftovers, as much as we can
system.userActivationScripts.cleanupHome = ''
pushd "${config.user.home}"
rm -rf .compose-cache .nv .pki .dbus .fehbg
[ -s .xsession-errors ] || rm -f .xsession-errors*
popd
'';
};
}

View File

@ -0,0 +1,17 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.documents;
in {
options.modules.desktop.documents = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = with pkgs; [
onlyoffice-bin
tectonic
];
};
}

View File

@ -0,0 +1,19 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.gaming.lutris;
in {
options.modules.desktop.gaming.lutris = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = with pkgs; [
lutris
wine
winetricks
gamemode
];
};
}

View File

@ -0,0 +1,17 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.gaming.steam;
in {
options.modules.desktop.gaming.steam = with types; {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
programs.steam.enable = true;
# better for steam proton games
systemd.extraConfig = "DefaultLimitNOFILE=1048576";
};
}

25
modules/desktop/gnome.nix Normal file
View File

@ -0,0 +1,25 @@
{ config, options, lib, pkgs, ... }:
with builtins;
with lib;
with lib.custom;
let
cfg = config.modules.desktop.gnome;
in {
options.modules.desktop.gnome = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [
gnomeExtensions.containers
gnomeExtensions.tray-icons-reloaded
];
services.xserver = {
enable = true;
displayManager.gdm.enable = true;
desktopManager.gnome.enable = true;
};
};
}

View File

@ -0,0 +1,50 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.media.graphics;
configDir = config.dotfiles.configDir;
in {
options.modules.desktop.media.graphics = {
enable = mkBoolOpt false;
tools.enable = mkBoolOpt true;
raster.enable = mkBoolOpt true;
vector.enable = mkBoolOpt true;
sprites.enable = mkBoolOpt false;
models.enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = with pkgs;
(if cfg.tools.enable then [
font-manager
imagemagick
] else []) ++
# replaces illustrator & indesign
(if cfg.vector.enable then [
unstable.inkscape
] else []) ++
# Replaces photoshop
(if cfg.raster.enable then [
krita
gimp
gimpPlugins.resynthesizer # content-aware scaling in gimp
] else []) ++
# Sprite sheets & animation
(if cfg.sprites.enable then [
aseprite-unfree
] else []) ++
# 3D modelling
(if cfg.models.enable then [
unstable.blender-hip
] else []);
home.configFile = mkIf cfg.raster.enable {
"GIMP/2.10" = { source = "${configDir}/gimp"; recursive = true; };
};
};
}

View File

@ -0,0 +1,27 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.media.recording;
in {
options.modules.desktop.media.recording = {
enable = mkBoolOpt false;
audio.enable = mkBoolOpt true;
video.enable = mkBoolOpt true;
};
config = mkIf cfg.enable {
services.pipewire.jack.enable = true;
user.packages = with pkgs;
(if cfg.audio.enable then [
unstable.audacity-gtk3
] else []) ++
(if cfg.video.enable then [
unstable.obs-studio
unstable.handbrake
ffmpeg
] else []);
};
}

View File

@ -0,0 +1,16 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.term;
in {
options.modules.desktop.term = {
default = mkOpt types.str "xterm";
};
config = {
services.xserver.desktopManager.xterm.enable = mkDefault (cfg.default == "xterm");
env.TERMINAL = cfg.default;
};
}

View File

@ -0,0 +1,21 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.desktop.vm.qemu;
in {
options.modules.desktop.vm.qemu = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [
qemu
];
};
}
# Creating an image:
# qemu-img create -f qcow2 disk.img
# Creating a snapshot (don't tamper with disk.img):
# qemu-img create -f qcow2 -b disk.img snapshot.img

29
modules/dev/cc.nix Normal file
View File

@ -0,0 +1,29 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
devCfg = config.modules.dev;
cfg = devCfg.cc;
in {
options.modules.dev.cc = {
enable = mkBoolOpt false;
xdg.enable = mkBoolOpt devCfg.xdg.enable;
};
config = mkMerge [
(mkIf cfg.enable {
user.packages = with pkgs; [
clang
gcc
bear
gdb
cmake
llvmPackages.libcxx
];
})
(mkIf cfg.xdg.enable {
# TODO
})
];
}

View File

@ -0,0 +1,25 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
devCfg = config.modules.dev;
cfg = devCfg.common-lisp;
in {
options.modules.dev.common-lisp = {
enable = mkBoolOpt false;
xdg.enable = mkBoolOpt devCfg.xdg.enable;
};
config = mkMerge [
(mkIf cfg.enable {
user.packages = with pkgs; [
sbcl
lispPackages.quicklisp
];
})
(mkIf cfg.xdg.enable {
# TODO
})
];
}

14
modules/dev/default.nix Normal file
View File

@ -0,0 +1,14 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.dev;
in {
options.modules.dev = {
xdg.enable = mkBoolOpt true;
};
config = mkIf cfg.xdg.enable {
# TODO
};
}

25
modules/dev/lua.nix Normal file
View File

@ -0,0 +1,25 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
devCfg = config.modules.dev;
cfg = devCfg.lua;
in {
options.modules.dev.lua = {
enable = mkBoolOpt false;
xdg.enable = mkBoolOpt devCfg.enableXDG;
};
config = mkMerge [
(mkIf cfg.enable {
user.packages = with pkgs; [
lua
luaPackages.moonscript
];
})
(mkIf cfg.xdg.enable {
# TODO
})
];
}

41
modules/dev/python.nix Normal file
View File

@ -0,0 +1,41 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
devCfg = config.modules.dev;
cfg = devCfg.python;
in {
options.modules.dev.python = {
enable = mkBoolOpt false;
xdg.enable = mkBoolOpt devCfg.xdg.enable;
};
config = mkMerge [
(mkIf cfg.enable {
user.packages = with pkgs; [
python310
python310Packages.pip
python310Packages.ipython
python310Packages.black
python310Packages.setuptools
python310Packages.pylint
python310Packages.poetry
];
environment.shellAliases = {
py = "python";
};
})
(mkIf cfg.xdg.enable {
env.IPYTHONDIR = "$XDG_CONFIG_HOME/ipython";
env.PIP_CONFIG_FILE = "$XDG_CONFIG_HOME/pip/pip.conf";
env.PIP_LOG_FILE = "$XDG_DATA_HOME/pip/log";
env.PYLINTHOME = "$XDG_DATA_HOME/pylint";
env.PYLINTRC = "$XDG_CONFIG_HOME/pylint/pylintrc";
env.PYTHONSTARTUP = "$XDG_CONFIG_HOME/python/pythonrc";
env.PYTHON_EGG_CACHE = "$XDG_CACHE_HOME/python-eggs";
env.JUPYTER_CONFIG_DIR = "$XDG_CONFIG_HOME/jupyter";
})
];
}

31
modules/dev/rust.nix Normal file
View File

@ -0,0 +1,31 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
devCfg = config.modules.dev;
cfg = devCfg.rust;
in {
options.modules.dev.rust = {
enable = mkBoolOpt false;
xdg.enable = mkBoolOpt devCfg.xdg.enable;
};
config = mkMerge [
(mkIf cfg.enable {
user.packages = [
pkgs.rustup
];
env.PATH = [ "$(${pkgs.yarn}/bin/yarn global bin)" ];
environment.shellAliases = {
rs = "rustc";
rsp = "rustup";
};
})
(mkIf cfg.xdg.enable {
env.RUSTUP_HOME = "$XDG_DATA_HOME/rustup";
env.CARGO_HOME = "$XDG_DATA_HOME/cargo";
env.PATH = [ "$CARGO_HOME/bin" ];
})
];
}

24
modules/dev/shell.nix Normal file
View File

@ -0,0 +1,24 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
devCfg = config.modules.dev;
cfg = devCfg.shell;
in {
options.modules.dev.shell = {
enable = mkBoolOpt false;
xdg.enable = mkBoolOpt devCfg.xdg.enable;
};
config = mkMerge [
(mkIf cfg.enable {
user.packages = with pkgs; [
shellcheck
];
})
(mkIf cfg.xdg.enable {
# TODO
})
];
}

View File

@ -0,0 +1,14 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.editors;
in {
options.modules.editors = {
default = mkOpt types.str "vim";
};
config = mkIf (cfg.default != null) {
env.EDITOR = cfg.default;
};
}

64
modules/editors/emacs.nix Normal file
View File

@ -0,0 +1,64 @@
{ config, lib, pkgs, inputs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.editors.emacs;
configDir = config.dotfiles.configDir;
in {
options.modules.editors.emacs = {
enable = mkBoolOpt false;
doom = rec {
enable = mkBoolOpt false;
forgeUrl = mkOpt types.str "https://github.com";
repoUrl = mkOpt types.str "${forgeUrl}/doomemacs/doomemacs";
configRepoUrl = mkOpt types.str "${forgeUrl}/hlissner/doom-emacs-private";
};
};
config = mkIf cfg.enable {
nixpkgs.overlays = [ inputs.emacs-overlay.overlay ];
user.packages = with pkgs; [
## Emacs itself
binutils # native-comp needs 'as', provided by this
# 28.2 + native-comp
((emacsPackagesFor emacsNativeComp).emacsWithPackages (epkgs: [ epkgs.vterm ]))
## Doom dependencies
git
(ripgrep.override {withPCRE2 = true;})
gnutls # for TLS connectivity
## Optional dependencies
fd # faster projectile indexing
imagemagick # for image-dired
(mkIf (config.programs.gnupg.agent.enable) pinentry_emacs) # in-emacs gnupg prompts
zstd # for undo-fu-session/undo-tree compression
## Module dependencies
# :checkers spell
(aspellWithDicts (ds: with ds; [ en en-computers en-science ]))
# :tools editorconfig
editorconfig-core-c # per-project style config
# :tools lookup & :lang org +roam
sqlite
# :lang latex & :lang org (latex previews)
texlive.combined.scheme-medium
];
env.PATH = [ "$XDG_CONFIG_HOME/emacs/bin" ];
modules.shell.zsh.rcFiles = [ "${configDir}/emacs/aliases.zsh" ];
fonts.fonts = [ pkgs.emacs-all-the-icons-fonts ];
system.userActivationScripts = mkIf cfg.doom.enable {
installDoomEmacs = ''
if [ ! -d "$XDG_CONFIG_HOME/emacs" ]; then
git clone --depth=1 --single-branch "${cfg.doom.repoUrl}" "$XDG_CONFIG_HOME/emacs"
git clone "${cfg.doom.configRepoUrl}" "$XDG_CONFIG_HOME/doom"
fi
'';
};
};
}

23
modules/editors/vim.nix Normal file
View File

@ -0,0 +1,23 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.editors.vim;
in {
options.modules.editors.vim = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = with pkgs; [
editorconfig-core-c
unstable.neovim
];
# env.VIMINIT = "let \\$MYVIMRC='\\$XDG_CONFIG_HOME/nvim/init.vim' | source \\$MYVIMRC";
environment.shellAliases = {
vim = "nvim";
};
};
}

View File

@ -0,0 +1,41 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.hardware.audio;
in {
options.modules.hardware.audio = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
};
security.rtkit.enable = true;
environment.systemPackages = with pkgs; [
easyeffects
];
# HACK Prevents ~/.esd_auth files by disabling the esound protocol module
# for pulseaudio, which I likely don't need. Is there a better way?
hardware.pulseaudio.configFile =
let
inherit (pkgs) runCommand pulseaudio;
paConfigFile = runCommand "disablePulseaudioEsoundModule"
{ buildInputs = [ pulseaudio ]; } ''
mkdir "$out"
cp ${pulseaudio}/etc/pulse/default.pa "$out/default.pa"
sed -i -e 's|load-module module-esound-protocol-unix|# ...|' "$out/default.pa"
'';
in
mkIf config.hardware.pulseaudio.enable "${paConfigFile}/default.pa";
user.extraGroups = [ "audio" ];
};
}

View File

@ -0,0 +1,14 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.hardware.bluetooth;
in {
options.modules.hardware.bluetooth = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
hardware.bluetooth.enable = true;
};
}

45
modules/hardware/fs.nix Normal file
View File

@ -0,0 +1,45 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.hardware.fs;
in {
options.modules.hardware.fs = {
enable = mkBoolOpt false;
zfs.enable = mkBoolOpt false;
ssd.enable = mkBoolOpt false;
# TODO automount.enable = mkBoolOpt false;
};
config = mkIf cfg.enable (mkMerge [
{
programs.udevil.enable = true;
# Support for more filesystems, mostly to support external drives
environment.systemPackages = with pkgs; [
sshfs
exfat
ntfs3g
];
}
(mkIf (!cfg.zfs.enable && cfg.ssd.enable) {
services.fstrim.enable = true;
})
(mkIf cfg.zfs.enable (mkMerge [
{
boot.loader.grub.copyKernels = true;
boot.supportedFilesystems = [ "zfs" ];
boot.zfs.devNodes = "/dev/disk/by-partuuid";
services.zfs.autoScrub.enable = true;
}
(mkIf cfg.ssd.enable {
# Will only TRIM SSDs; skips over HDDs
services.fstrim.enable = false;
services.zfs.trim.enable = true;
})
]))
]);
}

View File

@ -0,0 +1,29 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.hardware.nvidia;
in {
options.modules.hardware.nvidia = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
hardware.opengl = {
enable = true;
driSupport = true;
driSupport32Bit = true;
};
services.xserver.videoDrivers = [ "nvidia" ];
environment.systemPackages = with pkgs; [
# Respect XDG conventions, damn it!
(writeScriptBin "nvidia-settings" ''
#!${stdenv.shell}
mkdir -p "$XDG_CONFIG_HOME/nvidia"
exec ${config.boot.kernelPackages.nvidia_x11.settings}/bin/nvidia-settings --config="$XDG_CONFIG_HOME/nvidia/settings"
'')
];
};
}

View File

@ -0,0 +1,16 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custon;
let
cfg = config.modules.hardware.sensors;
in {
options.modules.hardware.sensors = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = [
pkgs.lm_sensors
];
};
}

View File

@ -0,0 +1,24 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.hardware.wacom;
in
{
options.modules.hardware.wacom = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
services.xserver.wacom.enable = true;
# TODO Move this to udev
system.userActivationScripts.wacom = ''
# lock tablet to main display
if xinput list --id-only "Wacom Intuos Pro S Pen stylus" 2>&1 >/dev/null; then
xinput map-to-output $(xinput list --id-only "Wacom Intuos Pro S Pen stylus") DVI-I-1
xinput map-to-output $(xinput list --id-only "Wacom Intuos Pro S Pen eraser") DVI-I-1
xinput map-to-output $(xinput list --id-only "Wacom Intuos Pro S Pen cursor") DVI-I-1
fi
'';
};
}

79
modules/options.nix Normal file
View File

@ -0,0 +1,79 @@
{ config, options, lib, home-manager, ... }:
with lib;
with lib.custom;
{
options = with types; {
user = mkOpt attrs {};
home = {
file = mkOpt' attrs {} "Files to place directly in $HOME";
configFile = mkOpt' attrs {} "Files to place in $XDG_CONFIG_HOME";
dataFile = mkOpt' attrs {} "Files to place in $XDG_DATA_HOME";
dconfSettings = mkOpt' attrs {} "Configuration of dconf settings";
};
dotfiles = {
dir = mkOpt path (removePrefix "/mnt" (findFirst pathExists (toString ../.) [
"/mnt/etc/dotfiles"
"/etc/dotfiles"
]));
binDir = mkOpt path "${config.dotfiles.dir}/bin";
configDir = mkOpt path "${config.dotfiles.dir}/config";
modulesDir = mkOpt path "${config.dotfiles.dir}/modules";
themesDir = mkOpt path "${config.dotfiles.modulesDir}/themes";
};
env = mkOption {
type = attrsOf (oneOf [ str path (listOf (either str path)) ]);
apply = mapAttrs (n: v: if isList v then concatMapStringsSep ":" (x: toString x) v else (toString v));
default = {};
description = "TODO";
};
};
config = {
user = {
name = let name = builtins.getEnv "USER"; in if elem user [ "" "root" ] then "nafaryus" else user;
description = "L-Nafaryus";
extraGroups = [ "wheel" ];
isNormalUser = true;
home = "/home/${name}";
group = "users";
uid = 1000;
};
# Install user packages to /etc/profiles instead. Necessary for
# nixos-rebuild build-vm to work.
home-manager = {
useUserPackages = true;
users.${config.user.name} = {
home = {
file = mkAliasDefinitions options.home.file;
# Necessary for home-manager to work with flakes, otherwise it will
# look for a nixpkgs channel.
stateVersion = config.system.stateVersion;
};
xdg = {
configFile = mkAliasDefinitions options.home.configFile;
dataFile = mkAliasDefinitions options.home.dataFile;
};
dconf = {
settings = mkAliasDefinitions options.home.dconfSettings;
};
};
};
users.users.${config.user.name} = mkAliasDefinitions options.user;
nix.settings = let users = [ "root" config.user.name ]; in {
trusted-users = users;
allowed-users = users;
};
# must already begin with pre-existing PATH. Also, can't use binDir here,
# because it contains a nix store path.
env.PATH = [ "$DOTFILES_BIN" "$XDG_BIN_HOME" "$PATH" ];
environment.extraInit = concatStringsSep "\n" (mapAttrsToList (n: v: "export ${n}=\"${v}\"") config.env);
};
}

78
modules/security.nix Normal file
View File

@ -0,0 +1,78 @@
{ config, lib, ... }:
{
## System security tweaks
# sets hidepid=2 on /proc (make process info visible only to owning user)
# NOTE Was removed on nixpkgs-unstable because it doesn't do anything
# security.hideProcessInformation = true;
# Prevent replacing the running kernel w/o reboot
security.protectKernelImage = true;
#
boot.tmp.useTmpfs = true;
# tmpfs = /tmp is mounted in ram. Doing so makes temp file management speedy
# on ssd systems, and volatile! Because it's wiped on reboot.
boot.tmpOnTmpfs = lib.mkDefault true;
# If not using tmpfs, which is naturally purged on reboot, we must clean it
# /tmp ourselves. /tmp should be volatile storage!
boot.cleanTmpDir = lib.mkDefault (!config.boot.tmpOnTmpfs);
# Fix a security hole in place for backwards compatibility. See desc in
# nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
boot.loader.systemd-boot.editor = false;
boot.kernel.sysctl = {
# The Magic SysRq key is a key combo that allows users connected to the
# system console of a Linux kernel to perform some low-level commands.
# Disable it, since we don't need it, and is a potential security concern.
"kernel.sysrq" = 0;
## TCP hardening
# Prevent bogus ICMP errors from filling up logs.
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
# Reverse path filtering causes the kernel to do source validation of
# packets received from all interfaces. This can mitigate IP spoofing.
"net.ipv4.conf.default.rp_filter" = 1;
"net.ipv4.conf.all.rp_filter" = 1;
# Do not accept IP source route packets (we're not a router)
"net.ipv4.conf.all.accept_source_route" = 0;
"net.ipv6.conf.all.accept_source_route" = 0;
# Don't send ICMP redirects (again, we're on a router)
"net.ipv4.conf.all.send_redirects" = 0;
"net.ipv4.conf.default.send_redirects" = 0;
# Refuse ICMP redirects (MITM mitigations)
"net.ipv4.conf.all.accept_redirects" = 0;
"net.ipv4.conf.default.accept_redirects" = 0;
"net.ipv4.conf.all.secure_redirects" = 0;
"net.ipv4.conf.default.secure_redirects" = 0;
"net.ipv6.conf.all.accept_redirects" = 0;
"net.ipv6.conf.default.accept_redirects" = 0;
# Protects against SYN flood attacks
"net.ipv4.tcp_syncookies" = 1;
# Incomplete protection again TIME-WAIT assassination
"net.ipv4.tcp_rfc1337" = 1;
## TCP optimization
# TCP Fast Open is a TCP extension that reduces network latency by packing
# data in the senders initial TCP SYN. Setting 3 = enable TCP Fast Open for
# both incoming and outgoing connections:
"net.ipv4.tcp_fastopen" = 3;
# Bufferbloat mitigations + slight improvement in throughput & latency
"net.ipv4.tcp_congestion_control" = "bbr";
"net.core.default_qdisc" = "cake";
};
boot.kernelModules = [ "tcp_bbr" ];
# Change me later!
user.initialPassword = "nixos";
users.users.root.initialPassword = "nixos";
# So we don't have to do this later...
security.acme.acceptTerms = true;
# Set sudo command timeout to 30 minutes
security.sudo.extraConfig = ''
Defaults timestamp_timeout=30
'';
}

View File

@ -0,0 +1,16 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.services.calibre;
in {
options.modules.services.calibre = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
services.calibre-server.enable = true;
networking.firewall.allowedTCPPorts = [ 8080 ];
};
}

View File

@ -0,0 +1,38 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.services.fail2ban;
in {
options.modules.services.fail2ban = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
services.fail2ban = {
enable = true;
ignoreIP = [ "127.0.0.1/16" "192.168.1.0/24" ];
banaction-allports = "iptables-allports";
bantime-increment = {
enable = true;
maxtime = "168h";
factor = "4";
};
jails.DEFAULT = ''
blocktype = DROP
bantime = 1h
findtime = 1h
'';
};
# Extra filters
environment.etc = {
"fail2ban/filter.d/gitea.conf".text = ''
[Definition]
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
ignoreregex =
journalmatch = _SYSTEMD_UNIT=gitea.service
'';
};
};
}

View File

@ -0,0 +1,49 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.services.gitea;
in {
options.modules.services.gitea = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
# Allows git@... clone addresses rather than gitea@...
users.users.git = {
useDefaultShell = true;
home = "/var/lib/gitea";
group = "gitea";
isSystemUser = true;
};
user.extraGroups = [ "gitea" ];
services.gitea = {
enable = true;
lfs.enable = true;
user = "git";
database.user = "git";
# We're assuming SSL-only connectivity
cookieSecure = true;
# Only log what's important, but Info is necessary for fail2ban to work
log.level = "Info";
settings = {
server.DISABLE_ROUTER_LOG = true;
database.LOG_SQL = false;
service.ENABLE_BASIC_AUTHENTICATION = false;
};
dump.interval = "daily";
};
services.fail2ban.jails.gitea = ''
enabled = true
filter = gitea
banaction = %(banaction_allports)s
maxretry = 5
'';
};
}

View File

@ -0,0 +1,21 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.services.jellyfin;
in {
options.modules.services.jellyfin = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
services.jellyfin.enable = true;
networking.firewall = {
allowedTCPPorts = [ 8096 ];
allowedUDPPorts = [ 8096 ];
};
user.extraGroups = [ "jellyfin" ];
};
}

View File

@ -0,0 +1,74 @@
{ config, options, lib, pkgs, ... }:
with builtins;
with lib;
with lib.custom;
let
cfg = config.modules.services.nginx;
in {
options.modules.services.nginx = {
enable = mkBoolOpt false;
enableCloudflareSupport = mkBoolOpt false;
};
config = mkMerge [
(mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ 80 443 ];
user.extraGroups = [ "nginx" ];
services.nginx = {
enable = true;
# Use recommended settings
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
# Reduce the permitted size of client requests, to reduce the likelihood
# of buffer overflow attacks. This can be tweaked on a per-vhost basis,
# as needed.
clientMaxBodySize = "256k"; # default 10m
# Significantly speed up regex matchers
appendConfig = ''pcre_jit on;'';
commonHttpConfig = ''
client_body_buffer_size 4k; # default: 8k
large_client_header_buffers 2 4k; # default: 4 8k
map $sent_http_content_type $expires {
default off;
text/html 10m;
text/css max;
application/javascript max;
application/pdf max;
~image/ max;
}
'';
};
})
(mkIf cfg.enableCloudflareSupport {
services.nginx.commonHttpConfig = ''
${concatMapStrings (ip: "set_real_ip_from ${ip};\n")
(filter (line: line != "")
(splitString "\n" ''
${readFile (fetchurl "https://www.cloudflare.com/ips-v4/")}
${readFile (fetchurl "https://www.cloudflare.com/ips-v6/")}
''))}
real_ip_header CF-Connecting-IP;
'';
})
];
}
# Helpful nginx snippets
#
# Set expires headers for static files and turn off logging.
# location ~* ^.+\.(js|css|swf|xml|txt|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|r ss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav |bmp|rtf)$ {
# access_log off; log_not_found off; expires 30d;
# }
#
# Deny all attempts to access PHP Files in the uploads directory
# location ~* /(?:uploads|files)/.*\.php$ {
# deny all;
# }

23
modules/services/ssh.nix Normal file
View File

@ -0,0 +1,23 @@
{ options, config, lib, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.services.ssh;
in {
options.modules.services.ssh = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
services.openssh = {
enable = true;
kbdInteractiveAuthentication = false;
passwordAuthentication = false;
};
user.openssh.authorizedKeys.keys =
if config.user.name == "nafaryus"
then [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9pBG3Ak8hO4eQFA8roajDeZkKSPv2NsgZADQoV8bNEvsqNssqvpnoBKZCCKFv+Hqvf0tcTcdkRedUJh+9f/CI8dEuYiNzRyCFjYnfyFyUlEjNh/MaTonJEFEO4QsbapxQx+Buc+/jPCdwhUEbf1jvJV0oQy7TptXOn87cYQSuqqeubv+YwBqXUfMIFbsxH+ePZ9rX+N9sLdYpW2k9W1i8g2oNPrEpa3ICW2qhf/bshUhmDLB9te+vt1qMu0jmzpllnbaJJ57rDuL6XLaWqU/PD6uC0j1axf8AMxf00YvrLvMJ+T9hWlLe0mwNsgkhRzBE2/T+PYkUfvWvzqGLtIBZ nafaryus" ]
else [];
};
}

View File

@ -0,0 +1,20 @@
{ config, options, pkgs, lib, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.services.syncthing;
in {
options.modules.services.syncthing = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
services.syncthing = rec {
enable = true;
openDefaultPorts = true;
user = config.user.name;
configDir = "${config.user.home}/.config/syncthing";
dataDir = "${config.user.home}/.local/share/syncthing";
};
};
}

View File

@ -0,0 +1,32 @@
{ config, options, pkgs, lib, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.services.transmission;
in {
options.modules.services.transmission = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
services.transmission = {
enable = true;
home = "${config.user.home}/torrents";
settings = {
incomplete-dir-enabled = true;
rpc-whitelist = "127.0.0.1,192.168.*.*";
rpc-host-whitelist = "*";
rpc-host-whitelist-enabled = true;
ratio-limit = 0;
ratio-limit-enabled = true;
};
};
networking.firewall = {
allowedTCPPorts = [ 51413 ];
allowedUDPPorts = [ 51413 ];
};
user.extraGroups = [ "transmission" ];
};
}

View File

@ -0,0 +1,22 @@
{ options, config, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.services.wireguard;
udpPorts = mapAttrs' (_: cfg: cfg.listenPort) config.networking.wireguard.interfaces;
interfaces = elem 0 (mapAttrs' (n: _: n) config.networking.interfaces);
wgInterfaces = elem 0 (mapAttrs' (n: _: n) config.networking.wireguard.interfaces);
in {
options.modules.services.wireguard = with types; {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
networking = {
firewall.allowedUDPPorts = udpPorts;
nat.enable = true;
nat.externalInterface = mkDefault interfaces;
nat.internalInterfaces = mkDefault wgInterfaces;
};
};
}

15
modules/shell/direnv.nix Normal file
View File

@ -0,0 +1,15 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.shell.direnv;
in {
options.modules.shell.direnv = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = [ pkgs.direnv ];
modules.shell.zsh.rcInit = ''eval "$(direnv hook zsh)"'';
};
}

30
modules/shell/git.nix Normal file
View File

@ -0,0 +1,30 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.shell.git;
configDir = config.dotfiles.configDir;
in {
options.modules.shell.git = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
user.packages = with pkgs; [
gitAndTools.git-annex
unstable.gitAndTools.gh
gitAndTools.git-open
gitAndTools.diff-so-fancy
(mkIf config.modules.shell.gnupg.enable gitAndTools.git-crypt)
act
];
home.configFile = {
"git/config".source = "${configDir}/git/config";
"git/ignore".source = "${configDir}/git/ignore";
"git/attributes".source = "${configDir}/git/attributes";
};
modules.shell.zsh.rcFiles = [ "${configDir}/git/aliases.zsh" ];
};
}

31
modules/shell/gnupg.nix Normal file
View File

@ -0,0 +1,31 @@
{ config, options, lib, pkgs, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.shell.gnupg;
in {
options.modules.shell.gnupg = with types; {
enable = mkBoolOpt false;
cacheTTL = mkOpt int 3600; # 1hr
};
config = mkIf cfg.enable {
environment.variables.GNUPGHOME = "$XDG_CONFIG_HOME/gnupg";
programs.gnupg.agent.enable = true;
user.packages = [
pkgs.tomb
];
# HACK Without this config file you get "No pinentry program" on 20.03.
# programs.gnupg.agent.pinentryFlavor doesn't appear to work, and this
# is cleaner than overriding the systemd unit.
home.configFile."gnupg/gpg-agent.conf" = {
text = ''
default-cache-ttl ${toString cfg.cacheTTL}
pinentry-program ${pkgs.pinentry.gtk2}/bin/pinentry
'';
};
};
}

24
modules/shell/pass.nix Normal file
View File

@ -0,0 +1,24 @@
{ config, options, pkgs, lib, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.shell.pass;
in {
options.modules.shell.pass = with types; {
enable = mkBoolOpt false;
passwordStoreDir = mkOpt str "$HOME/.secrets/password-store";
};
config = mkIf cfg.enable {
user.packages = with pkgs; [
(pass.withExtensions (exts: [
exts.pass-otp
exts.pass-genphrase
] ++
(if config.modules.shell.gnupg.enable
then [ exts.pass-tomb ]
else [])))
];
env.PASSWORD_STORE_DIR = cfg.passwordStoreDir;
};
}

46
modules/shell/tmux.nix Normal file
View File

@ -0,0 +1,46 @@
{ config, options, pkgs, lib, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.shell.tmux;
configDir = config.dotfiles.configDir;
in {
options.modules.shell.tmux = with types; {
enable = mkBoolOpt false;
rcFiles = mkOpt (listOf (either str path)) [];
};
config = mkIf cfg.enable {
user.packages = with pkgs; [ tmux ];
modules.theme.onReload.tmux = "${pkgs.tmux}/bin/tmux source-file $TMUX_HOME/extraInit";
modules.shell.zsh = {
rcInit = "_cache tmuxifier init -";
rcFiles = [ "${configDir}/tmux/aliases.zsh" ];
};
home.configFile = {
"tmux" = { source = "${configDir}/tmux"; recursive = true; };
"tmux/extraInit" = {
text = ''
#!/usr/bin/env bash
# This file is auto-generated by nixos, don't edit by hand!
${concatMapStrings (path: "tmux source-file '${path}'\n") cfg.rcFiles}
tmux run-shell '${pkgs.tmuxPlugins.copycat}/share/tmux-plugins/copycat/copycat.tmux'
tmux run-shell '${pkgs.tmuxPlugins.prefix-highlight}/share/tmux-plugins/prefix-highlight/prefix_highlight.tmux'
tmux run-shell '${pkgs.tmuxPlugins.yank}/share/tmux-plugins/yank/yank.tmux'
tmux run-shell '${pkgs.tmuxPlugins.resurrect}/share/tmux-plugins/resurrect/resurrect.tmux'
'';
executable = true;
};
};
env = {
PATH = [ "$TMUXIFIER/bin" ];
TMUX_HOME = "$XDG_CONFIG_HOME/tmux";
TMUXIFIER = "$XDG_DATA_HOME/tmuxifier";
TMUXIFIER_LAYOUT_PATH = "$XDG_DATA_HOME/tmuxifier";
};
};
}

88
modules/shell/zsh.nix Normal file
View File

@ -0,0 +1,88 @@
{ config, options, pkgs, lib, ... }:
with lib;
with lib.custom;
let
cfg = config.modules.shell.zsh;
configDir = config.dotfiles.configDir;
in {
options.modules.shell.zsh = with types; {
enable = mkBoolOpt false;
aliases = mkOpt (attrsOf (either str path)) {};
rcInit = mkOpt' lines "" ''
Zsh lines to be written to $XDG_CONFIG_HOME/zsh/extra.zshrc and sourced by
$XDG_CONFIG_HOME/zsh/.zshrc
'';
envInit = mkOpt' lines "" ''
Zsh lines to be written to $XDG_CONFIG_HOME/zsh/extra.zshenv and sourced
by $XDG_CONFIG_HOME/zsh/.zshenv
'';
rcFiles = mkOpt (listOf (either str path)) [];
envFiles = mkOpt (listOf (either str path)) [];
};
config = mkIf cfg.enable {
users.defaultUserShell = pkgs.zsh;
programs.zsh = {
enable = true;
enableCompletion = true;
# I init completion myself, because enableGlobalCompInit initializes it
# too soon, which means commands initialized later in my config won't get
# completion, and running compinit twice is slow.
enableGlobalCompInit = false;
promptInit = "";
};
user.packages = with pkgs; [
zsh
nix-zsh-completions
bat
exa
fasd
fd
fzf
jq
ripgrep
tldr
];
env = {
ZDOTDIR = "$XDG_CONFIG_HOME/zsh";
ZSH_CACHE = "$XDG_CACHE_HOME/zsh";
ZGEN_DIR = "$XDG_DATA_HOME/zgenom";
};
home.configFile = {
# Write it recursively so other modules can write files to it
"zsh" = { source = "${configDir}/zsh"; recursive = true; };
# Why am I creating extra.zsh{rc,env} when I could be using extraInit?
# Because extraInit generates those files in /etc/profile, and mine just
# write the files to ~/.config/zsh; where it's easier to edit and tweak
# them in case of issues or when experimenting.
"zsh/extra.zshrc".text =
let
aliasLines = mapAttrsToList (n: v: "alias ${n}=\"${v}\"") cfg.aliases;
in ''
# This file was autogenerated, do not edit it!
${concatStringsSep "\n" aliasLines}
${concatMapStrings (path: "source '${path}'\n") cfg.rcFiles}
${cfg.rcInit}
'';
"zsh/extra.zshenv".text = ''
# This file is autogenerated, do not edit it!
${concatMapStrings (path: "source '${path}'\n") cfg.envFiles}
${cfg.envInit}
'';
};
system.userActivationScripts.cleanupZgen = ''
rm -rf $ZSH_CACHE
rm -fv $ZGEN_DIR/init.zsh{,.zwc}
'';
};
}

48
modules/xdg.nix Normal file
View File

@ -0,0 +1,48 @@
{ config, home-manager, pkgs, ... }:
{
home-manager.users.${config.user.name}.xdg ={
enable = true;
# Until https://github.com/rycee/home-manager/issues/1213 is solved.
configFile."mimeapps.list".force = true;
mime.enable = true;
mimeApps = {
enable = true;
defaultApplications = {
"text/html" = "firefox.desktop";
"x-scheme-handler/http" = "firefox.desktop";
"x-scheme-handler/https" = "firefox.desktop";
"x-scheme-handler/about" = "firefox.desktop";
"x-scheme-handler/unknown" = "firefox.desktop";
};
};
};
environment = {
sessionVariables = {
# These are the defaults, and xdg.enable does set them, but due to load
# order, they're not set before environment.variables are set, which could
# cause race conditions.
XDG_CACHE_HOME = "$HOME/.cache";
XDG_CONFIG_HOME = "$HOME/.config";
XDG_DATA_HOME = "$HOME/.local/share";
XDG_BIN_HOME = "$HOME/.local/bin";
# Firefox really wants a desktop directory to exist
XDG_DESKTOP_DIR = "~/tmp";
# Setting this for Electon apps that do not respect mime default apps
DEFAULT_BROWSER = "${pkgs.firefox}/bin/firefox";
};
variables = {
__GL_SHADER_DISK_CACHE_PATH = "$XDG_CACHE_HOME/nv";
CUDA_CACHE_PATH = "$XDG_CACHE_HOME/nv";
HISTFILE = "$XDG_DATA_HOME/bash/history";
INPUTRC = "$XDG_CONFIG_HOME/readline/inputrc";
LESSHISTFILE = "$XDG_CACHE_HOME/lesshst";
WGETRC = "$XDG_CONFIG_HOME/wgetrc";
};
extraInit = ''
export XAUTHORITY=/tmp/Xauthority
[ -e ~/.Xauthority ] && mv -f ~/.Xauthority "$XAUTHORITY"
'';
};
}

0
overlays/.git-keep Normal file
View File

0
packages/.git-keep Normal file
View File

17
shell.nix Normal file
View File

@ -0,0 +1,17 @@
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
let
nixBin = writeShellScriptBin "nix" ''
${nixFlakes}/bin/nix --option experimental-features "nix-command flakes" "$@"
'';
in
mkShell {
buildInputs = [
git
nix-zsh-completions
];
shellHook = ''
export FLAKE="$(pwd)"
export PATH="$FLAKE/bin:${nixBin}/bin:$PATH"
'';
}

7
templates/default.nix Normal file
View File

@ -0,0 +1,7 @@
{
# Projects
#project-nodejs = {
# path = ./project/XYZ;
# description = "";
#};
}

View File

@ -0,0 +1,15 @@
{ config, options, lib, pkgs, ... }:
with builtins;
with lib;
with lib.custom;
let
cfg = config.modules.X.Y;
in {
options.modules.X.Y = {
enable = mkBoolOpt false;
};
config = mkIf cfg.enable {
};
}

View File