summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
authorLinnnus <[email protected]>2024-12-21 15:47:33 +0100
committerLinnnus <[email protected]>2024-12-21 16:19:04 +0100
commit8353554315564b89dfe27d5130080ed04a0a65ad (patch)
tree896de88b6ea2701692b3ffe977c23947a786318e /shared
parent9b7ed17b27157a25e57a6e38be3bcfeaa70ec9e8 (diff)
Move to a profile-based configuration where common
This patch makes it so common configuration is now located in shared/ and each host basically just becomes a bunch of import statements. The exception here is host-specific configuration like the `*.linus.onl` that live inside `hosts/ahmed/`. Specifically I have: - moved common configuration `shared/{nixos,home-manager,nix-darwin}`. - moved `hosts/common.nix` to `shared/nixos/common-{nix,shell}-settings.nix`. - split `hosts/muhammed/{dev-utils,neovim}` into per-language configuration. This patch was done in preparation for the arrival of a new host, which will need to share a lot of configuration with Muhammed.
Diffstat (limited to 'shared')
-rw-r--r--shared/home-manager/C/default.nix22
-rw-r--r--shared/home-manager/development-full/default.nix15
-rw-r--r--shared/home-manager/development-minimal/default.nix28
-rw-r--r--shared/home-manager/git/aliases.nix25
-rw-r--r--shared/home-manager/git/default.nix49
-rw-r--r--shared/home-manager/git/ignore.nix37
-rw-r--r--shared/home-manager/iterm2/auto_theme.py31
-rw-r--r--shared/home-manager/iterm2/default.nix22
-rw-r--r--shared/home-manager/javascript/default.nix54
-rw-r--r--shared/home-manager/neovim/completion.nix47
-rw-r--r--shared/home-manager/neovim/default.nix28
-rw-r--r--shared/home-manager/neovim/editing-plugins.nix26
-rw-r--r--shared/home-manager/neovim/init.vim274
-rw-r--r--shared/home-manager/neovim/lsp.nix59
-rw-r--r--shared/home-manager/networking-utils/default.nix10
-rw-r--r--shared/home-manager/nix/default.nix14
-rw-r--r--shared/home-manager/noweb/default.nix16
-rw-r--r--shared/home-manager/python/default.nix16
-rw-r--r--shared/home-manager/qbittorrent/default.nix5
-rw-r--r--shared/home-manager/rust/default.nix13
-rw-r--r--shared/home-manager/shell-utils/default.nix34
-rw-r--r--shared/home-manager/svelte/default.nix15
-rw-r--r--shared/home-manager/zsh/default.nix31
-rw-r--r--shared/home-manager/zsh/editing.nix43
-rw-r--r--shared/home-manager/zsh/plugins.nix47
-rw-r--r--shared/nixos/cloudflare-proxy/default.nix88
-rw-r--r--shared/nixos/common-hm-settings/default.nix27
-rw-r--r--shared/nixos/common-nix-settings/default.nix60
-rw-r--r--shared/nixos/common-shell-settings/default.nix44
29 files changed, 1180 insertions, 0 deletions
diff --git a/shared/home-manager/C/default.nix b/shared/home-manager/C/default.nix
new file mode 100644
index 0000000..b4d42a5
--- /dev/null
+++ b/shared/home-manager/C/default.nix
@@ -0,0 +1,22 @@
+# This module configures development tools for C.
+{pkgs, ...}: {
+ home.packages = with pkgs; [
+ clang
+ cscript
+ ];
+
+ programs.neovim.extraLuaConfig = ''
+ require("lspconfig")["clangd"].setup({
+ cmd = { "${pkgs.clang-tools}/bin/clangd", "--background-index", "--clang-tidy" },
+ on_attach = function(_, bufnr)
+ vim.keymap.set("n", "<leader>s", function()
+ vim.cmd [[ClangdSwitchSourceHeader]]
+ end, {
+ noremap=true,
+ silent=true,
+ buffer=bufnr,
+ })
+ end,
+ })
+ '';
+}
diff --git a/shared/home-manager/development-full/default.nix b/shared/home-manager/development-full/default.nix
new file mode 100644
index 0000000..162edff
--- /dev/null
+++ b/shared/home-manager/development-full/default.nix
@@ -0,0 +1,15 @@
+# This module pulls in everything development related. Including it will give a
+# fully featured development environment with all the bells and whistles. It
+# will also explode the closure size, so this shouldn't be included on every
+# host!
+{...}: {
+ imports = [
+ ../C
+ ../development-minimal
+ ../javascript
+ ../nix
+ ../noweb
+ ../python
+ ../rust
+ ];
+}
diff --git a/shared/home-manager/development-minimal/default.nix b/shared/home-manager/development-minimal/default.nix
new file mode 100644
index 0000000..30ef972
--- /dev/null
+++ b/shared/home-manager/development-minimal/default.nix
@@ -0,0 +1,28 @@
+# This module pulls in other HM modules which together form a minimal
+# development enviroment. It does so while taking care not to balloon the
+# closure size too much.
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ imports = [
+ ../zsh
+ ../shell-utils
+
+ ../git
+ ../neovim
+ ../networking-utils
+ ];
+
+ home.packages = with pkgs; [
+ rlwrap
+ devenv
+ ];
+
+ # Add system manual pages to the search path on Darwin.
+ home.sessionVariables.MANPATH = lib.optionalString pkgs.stdenv.isDarwin "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/share/man:/Applications/Xcode.app/Contents/Developer/usr/share/man:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/share/man:$MANPATH";
+
+ # Add local executables/scripts to path.
+ home.sessionVariables.PATH = "$HOME/.local/bin:$PATH";
+}
diff --git a/shared/home-manager/git/aliases.nix b/shared/home-manager/git/aliases.nix
new file mode 100644
index 0000000..03e586c
--- /dev/null
+++ b/shared/home-manager/git/aliases.nix
@@ -0,0 +1,25 @@
+# This module defines my personal git aliases. Some of these are
+# pseudo-subcommands which are easier to remember while others simply save me
+# some keystrokes.
+{...}: {
+ programs.git.aliases = {
+ unstage = "restore --staged"; # remove file from staging area
+ undo = "reset --soft HEAD~"; # undo last commit
+ };
+
+ home.shellAliases = {
+ gs = "git status";
+ gd = "git diff --";
+ gl = "git log --oneline HEAD~10..HEAD --";
+
+ gc = "git commit";
+ gcp = "git commit --patch";
+ gf = "git commit --amend --no-edit --";
+ gfp = "git commit --amend --no-edit --patch --";
+
+ ga = "git add --";
+ gan = "git add -N";
+ gap = "git add --patch";
+ gu = "git unstage";
+ };
+}
diff --git a/shared/home-manager/git/default.nix b/shared/home-manager/git/default.nix
new file mode 100644
index 0000000..748025d
--- /dev/null
+++ b/shared/home-manager/git/default.nix
@@ -0,0 +1,49 @@
+{
+ pkgs,
+ lib,
+ ...
+}: let
+ inherit (lib) optional;
+ inherit (pkgs.stdenv.hostPlatform) isDarwin;
+in {
+ imports = [
+ ./ignore.nix
+ ./aliases.nix
+ ];
+
+ programs.git = {
+ enable = true;
+
+ # Set privacy-respecting user information.
+ userName = "Linnnus";
+ userEmail = "[email protected]";
+
+ extraConfig = {
+ init.defaultBranch = "master";
+
+ help.autoCorrect = "prompt";
+
+ # Make sure we don't accidentally update submodules with changes that are only available locally.
+ # See: https://git-scm.com/book/en/v2/Git-Tools-Submodules
+ push.recurseSubmodules = "check";
+
+ # It seems like a de facto standard to have a file with this name in the
+ # project root containing all the commits that should be ignored when
+ # running `git blame`.
+ blame.ignoreRevsFile = ".git-blame-ignore-revs";
+
+ credential = {
+ "https://github.com/" = {
+ username = "linnnus";
+ helper = "${pkgs.gh}/bin/gh auth git-credential";
+ };
+ helper = (optional isDarwin "osxkeychain") ++ ["cache"];
+ };
+ };
+ };
+
+ home.packages = with pkgs; [
+ # Add the GitHub CLI for authentication.
+ gh
+ ];
+}
diff --git a/shared/home-manager/git/ignore.nix b/shared/home-manager/git/ignore.nix
new file mode 100644
index 0000000..8d1da2f
--- /dev/null
+++ b/shared/home-manager/git/ignore.nix
@@ -0,0 +1,37 @@
+# This module defines the contents of `~/.config/git/ignore`. It fetches the
+# templates for different gitignores and compiles them into one.
+{
+ pkgs,
+ lib,
+ ...
+}: let
+ gitignore = ignores:
+ pkgs.stdenv.mkDerivation {
+ name = (lib.concatStringsSep "+" ignores) + ".gitignore";
+
+ src = pkgs.fetchFromGitHub {
+ owner = "toptal";
+ repo = "gitignore";
+ rev = "7e72ecd8af69b39c25aedc645117f0dc261cedfd";
+ hash = "sha256-Ln3w6wx+pX4UFLY2gGJGax2/nxgp/Svrn0uctSIRdEc=";
+ };
+
+ inherit ignores;
+ buildPhase = ''
+ for i in $ignores; do
+ cat ./templates/$i.gitignore >>$out
+ done
+ '';
+ };
+
+ targets =
+ [
+ "Node"
+ "Deno"
+ "C"
+ ]
+ ++ (lib.optional pkgs.stdenv.isDarwin "MacOS")
+ ++ (lib.optional pkgs.stdenv.isLinux "Linux");
+in {
+ xdg.configFile."git/ignore".source = gitignore targets;
+}
diff --git a/shared/home-manager/iterm2/auto_theme.py b/shared/home-manager/iterm2/auto_theme.py
new file mode 100644
index 0000000..0970304
--- /dev/null
+++ b/shared/home-manager/iterm2/auto_theme.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+
+import asyncio
+import iterm2
+
+async def update(connection, theme):
+ # Themes have space-delimited attributes, one of which will be light or dark.
+ parts = theme.split(" ")
+ if "dark" in parts:
+ preset = await iterm2.ColorPreset.async_get(connection, "Dark Background")
+ else:
+ preset = await iterm2.ColorPreset.async_get(connection, "Light Background")
+
+ # Update the list of all profiles and iterate over them.
+ profiles=await iterm2.PartialProfile.async_query(connection)
+ for partial in profiles:
+ # Fetch the full profile and then set the color preset in it.
+ profile = await partial.async_get_full_profile()
+ await profile.async_set_color_preset(preset)
+
+async def main(connection):
+ app = await iterm2.async_get_app(connection)
+ await update(connection, await app.async_get_variable("effectiveTheme"))
+ async with iterm2.VariableMonitor(connection, iterm2.VariableScopes.APP, "effectiveTheme", None) as mon:
+ while True:
+ # Block until theme changes
+ theme = await mon.async_get()
+ await update(connection, theme)
+
+
+iterm2.run_forever(main)
diff --git a/shared/home-manager/iterm2/default.nix b/shared/home-manager/iterm2/default.nix
new file mode 100644
index 0000000..b6a9ecc
--- /dev/null
+++ b/shared/home-manager/iterm2/default.nix
@@ -0,0 +1,22 @@
+# This file configures iterm2. Note that the actual definition of iTerm2 for
+# home-manager is in `modules/home-manager/iterm2`. *That* file declares
+# `options.programs.iterm2.enable`.
+{pkgs, ...}: {
+ config = {
+ home.packages = with pkgs; [imgcat];
+
+ # Install a script which automatically makes iTerm2 match the system-wide light/dark mode.
+ home.file."/Library/Application Support/iTerm2/Scripts/AutoLaunch/auto_theme.py".text = builtins.readFile ./auto_theme.py;
+
+ programs.iterm2 = {
+ enable = true;
+ # config = {
+ # # Use the minimal tab style.
+ # # See: https://github.com/gnachman/iTerm2/blob/bd40fba0611fa94684dadf2478625f2a93eb6e47/sources/iTermPreferences.h#L29
+ # TabStyleWithAutomaticOption = 5;
+ # };
+
+ shellIntegration.enableZshIntegration = true;
+ };
+ };
+}
diff --git a/shared/home-manager/javascript/default.nix b/shared/home-manager/javascript/default.nix
new file mode 100644
index 0000000..2beaf12
--- /dev/null
+++ b/shared/home-manager/javascript/default.nix
@@ -0,0 +1,54 @@
+# This module configures development tools for JavaScript/TypeScript.
+{pkgs, ...}: {
+ home.packages = with pkgs; [
+ unstable.deno
+ unstable.nodejs_latest
+ ];
+
+ programs.neovim.extraLuaConfig = ''
+ require("lspconfig")["denols"].setup({
+ init_options = {
+ enable = true,
+ unstable = true,
+ lint = true,
+ nodeModulesDir = true,
+ },
+ cmd = { "${pkgs.unstable.deno}/bin/deno", "lsp" },
+ root_dir = function(startpath)
+ if util.find_package_json_ancestor(startpath) then
+ -- This is a Node project; let ts_ls handle this one.
+ -- This exactly mirrors how typescript-langauge-server yields to this server for Deno projects.
+ return nil
+ else
+ -- Otherwise, we try to find the root or
+ -- default to the current directory.
+ return util.root_pattern("deno.json", "deno.jsonc", ".git")(startpath)
+ or util.path.dirname(startpath)
+ end
+ end,
+ });
+
+ require("lspconfig")["ts_ls"].setup({
+ cmd = { "${pkgs.nodePackages_latest.typescript-language-server}/bin/typescript-language-server", "--stdio" },
+ root_dir = function(startpath)
+ local find_deno_root_dir = util.root_pattern("deno.json", "deno.jsonc")
+ if find_deno_root_dir(startpath) then
+ -- This is a Deno project; let deno-lsp handle this one.
+ -- This exactly mirrors how deno-lsp yields to this server for Node projects.
+ return nil
+ else
+ -- Otherwise fall back to the usual resolution method.
+ -- See: https://github.com/neovim/nvim-lspconfig/blob/056f569f71e4b726323b799b9cfacc53653bceb3/lua/lspconfig/server_configurations/ts_ls.lua#L15
+ return util.root_pattern("tsconfig.json", "jsconfig.json", "package.json", ".git")(startpath)
+ end
+ end,
+ -- We also have to disallow starting in without a root directory, as otherwise returning
+ -- nil from find_root will just cause the LSP to be spawned in single file mode instead of yielding to deno-lsp.
+ --
+ -- This has the side effect that Deno LSP will be preferred in a single file context which is what we want!
+ --
+ -- See: https://github.com/neovim/nvim-lspconfig/blob/056f569f71e4b726323b799b9cfacc53653bceb3/lua/lspconfig/manager.lua#L281-L286
+ single_file_support = false,
+ })
+ '';
+}
diff --git a/shared/home-manager/neovim/completion.nix b/shared/home-manager/neovim/completion.nix
new file mode 100644
index 0000000..3776674
--- /dev/null
+++ b/shared/home-manager/neovim/completion.nix
@@ -0,0 +1,47 @@
+# This module sets up auto completion for Neovim.
+{pkgs, ...}: {
+ programs.neovim.plugins = with pkgs.vimPlugins; [
+ # This is the actual completion engine.
+ {
+ plugin = nvim-cmp;
+ type = "lua";
+ config = ''
+ local cmp = require("cmp")
+
+ cmp.setup({
+ mapping = cmp.mapping.preset.insert({
+ ["<C-b>"] = cmp.mapping.scroll_docs(-4),
+ ["<C-f>"] = cmp.mapping.scroll_docs(4),
+ ["<C-j>"] = cmp.mapping.select_next_item(),
+ ["<C-k>"] = cmp.mapping.select_prev_item(),
+ ["<C-Space>"] = cmp.mapping.complete(),
+ ["<C-e>"] = cmp.mapping.abort(),
+ ["<Tab>"] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
+ }),
+ sources = cmp.config.sources({
+ { name = "nvim_lsp" },
+ { name = "calc" },
+ { name = "path" },
+ { name = "buffer" },
+ }),
+ -- disable completion in comments
+ enabled = function()
+ local context = require("cmp.config.context")
+ -- keep command mode completion enabled when cursor is in a comment
+ if vim.api.nvim_get_mode().mode == "c" then
+ return true
+ else
+ return not context.in_treesitter_capture("comment")
+ and not context.in_syntax_group("Comment")
+ end
+ end
+ })
+ '';
+ }
+ # The following are plugins for the... completion plugin.
+ cmp-nvim-lsp
+ cmp-calc
+ cmp-buffer
+ cmp-path
+ ];
+}
diff --git a/shared/home-manager/neovim/default.nix b/shared/home-manager/neovim/default.nix
new file mode 100644
index 0000000..63a7564
--- /dev/null
+++ b/shared/home-manager/neovim/default.nix
@@ -0,0 +1,28 @@
+# This file contains the HM configuration options for Neovim.
+{...}: {
+ imports = [
+ ./completion.nix
+ ./editing-plugins.nix
+ ./lsp.nix
+ ];
+
+ programs.neovim = {
+ enable = true;
+
+ # Import my existing config. I've been working on this for years and when
+ # my enthusiasm for Nix eventually dies off, I want to take it with me.
+ extraConfig = builtins.readFile ./init.vim;
+
+ # Typing `vi`, `vim`, or `vimdiff` will also run neovim.
+ viAlias = true;
+ vimAlias = true;
+ vimdiffAlias = true;
+ };
+
+ # Set Neovim as the default editor.
+ home.sessionVariables.EDITOR = "nvim";
+ home.sessionVariables.VISUAL = "nvim";
+
+ # Use neovim as man pager.
+ home.sessionVariables.MANPAGER = "nvim +Man!";
+}
diff --git a/shared/home-manager/neovim/editing-plugins.nix b/shared/home-manager/neovim/editing-plugins.nix
new file mode 100644
index 0000000..23c7d63
--- /dev/null
+++ b/shared/home-manager/neovim/editing-plugins.nix
@@ -0,0 +1,26 @@
+# This module sets up and configures various miscellaneous plugins.
+# TODO: I fear this file will become the utils.lua of my Neovim configuration. Remove it!
+{pkgs, ...}: {
+ programs.neovim.plugins = [
+ {
+ plugin = pkgs.vimPlugins.vim-localvimrc;
+ type = "viml";
+ config = ''
+ let g:localvimrc_persistent = 1
+ let g:localvimrc_name = [ "local.vim", "editors/local.vim" ]
+ '';
+ }
+ {
+ plugin = pkgs.vimPlugins.vim-sneak;
+ type = "viml";
+ config = ''
+ let g:sneak#s_next = 1
+ let g:sneak#use_ic_scs = 1
+ map f <Plug>Sneak_f
+ map F <Plug>Sneak_F
+ map t <Plug>Sneak_t
+ map T <Plug>Sneak_T
+ '';
+ }
+ ];
+}
diff --git a/shared/home-manager/neovim/init.vim b/shared/home-manager/neovim/init.vim
new file mode 100644
index 0000000..eeb6920
--- /dev/null
+++ b/shared/home-manager/neovim/init.vim
@@ -0,0 +1,274 @@
+" Settings
+"""""""""""""""""""""""""""
+
+" Leave boomer mode
+set nocompatible
+
+set history=1000
+
+" Backspace in insert mode
+set backspace=indent,eol,start
+
+" Hide buffer when abandoned (you can gd away, etc)
+set hid
+
+" Searching
+" NOTE: ignorecase and smartcase must be used together (see :h 'smartcase')
+set incsearch gdefault ignorecase smartcase nohlsearch
+
+" Only auto-continue comments when i_<cr> is pressed (not n_o)
+" Must be set after :filetype-plugin-on
+filetype plugin indent on
+au FileType * setlocal fo-=o fo+=r
+
+" Enable syntax highlighting
+syn on
+
+" Colorscheme
+" au VimEnter * ++nested colorscheme ansi_linus
+
+" Persistent undo
+set undofile
+
+" Give me some thinking time, jesus!
+set timeout timeoutlen=2000
+
+" Line numbers
+set number relativenumber
+
+" Improve macro performance
+set lazyredraw
+
+" Show matching brackets
+set showmatch
+set matchtime=2
+
+set listchars=tab:>-,eol:$,space:.,trail:@,nbsp:%
+
+" Enable mouse input for all modes but visual.
+"
+" I disable mouse in visual mode so I can select text in the terminal using
+" the mouse. This is useful when copying text from a remote instance of vim
+" SSH session where "* doesn't work.
+set mouse=nicr
+
+" sussy sus the sussy sus
+set nowrap
+
+" Mappings
+"""""""""""""""""""""""""""
+
+let g:mapleader = "\<space>"
+let g:maplocalleader = "\<space>"
+
+" Some keys are hard to press with the Danish layout. Luckily, we have some
+" spare keys! Note that ctrl and esc are swapped at the OS level.
+nnoremap æ $
+nnoremap Æ 0
+
+" Switching windows
+" TODO: make this work with iTerm2 panes
+" nnoremap <c-h> <c-w><c-h>
+" nnoremap <c-j> <c-w><c-j>
+" nnoremap <c-k> <c-w><c-k>
+" nnoremap <c-l> <c-w><c-l>
+" tnoremap <c-h> <c-\><c-n><c-w><c-h>
+" tnoremap <c-j> <c-\><c-n><c-w><c-j>
+" tnoremap <c-k> <c-\><c-n><c-w><c-k>
+" tnoremap <c-l> <c-\><c-n><c-w><c-l>
+
+" Resize windows
+nnoremap + <c-w>+
+nnoremap - <c-w>-
+
+" Switching tabs
+nnoremap <silent> <leader>tt :tabnext<CR>
+nnoremap <silent> <leader>tn :tabnew<CR>
+nnoremap <silent> <leader>to :tabonly<CR>
+nnoremap <silent> <leader>tc :tabclose<CR>
+nnoremap <silent> <leader>tm :tabmove
+" Just use gt and gT
+" nnoremap <silent> <leader>tl :tabn<CR>
+" nnoremap <silent> <leader>th :tabN<CR>
+nnoremap <silent> <leader>t<S-L> :tabl<CR>
+nnoremap <silent> <leader>t<S-H> :tabr<CR>
+
+" Fast macros (qq to record)
+nnoremap Q @q
+vnoremap Q :norm! @q<cr>
+
+" Make Y act like C and D
+nnoremap <s-y> y$
+vnoremap <s-y> $y
+
+" Indent using tab key
+nnoremap <Tab> >l
+nnoremap <S-Tab> <l
+vnoremap <Tab> >gv
+vnoremap <S-Tab> <gv
+
+noremap! <C-j> <down>
+noremap! <C-k> <up>
+noremap! <C-h> <left>
+noremap! <C-l> <right>
+
+" Toggle showing 'listchars'
+nnoremap <silent> <leader>l :set list!<cr>
+
+" Escape in terminal mode
+tnoremap <esc><esc> <c-\><c-n>
+
+" Seamlessly enter/leave terminal buffer.
+tnoremap <c-w> <c-\><c-n><c-w>
+au BufEnter term://* norm! i
+
+" Join to end of line below
+" This is already used by the window switching mappings
+nnoremap <c-j> ddpkJ
+
+" Move window to the left and switch to the eastern window.
+" I do this move pretty frequently.
+nnoremap <c-w><c-w> <c-w>L<c-w>h
+
+" If the fzf executable is available, assume that the fzf plugin is going to
+" be loaded. In that case we want an easy way to load a file.
+if executable("fzf")
+ nnoremap <leader><leader> <CMD>FZF<CR>
+else
+ nnoremap <leader><leader> <CMD>echo "FZF not found!"<CR>
+endif
+
+" Define go-to-definition help pages, otherwise see the mappings in the hook
+" for LSP configuration.
+autocmd Filetype help nnoremap <buffer> gd <C-]>
+
+" Commands
+"""""""""""""""""""""""""""
+
+" Create a temporary buffer
+" NOTE: relied on by other commands
+command Temp new | setlocal buftype=nofile bufhidden=wipe noswapfile nomodified nobuflisted
+command TempTab tabnew | setlocal buftype=nofile bufhidden=wipe noswapfile nomodified nobuflisted
+
+" Reverse lines
+command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohl
+
+" Redraw screen
+" CTRL-L mapping is used in other thing
+command Redraw norm!
+
+" Run buffer contents as vimscript
+command! -bar -range=% Run execute 'silent!' . <line1> . ',' . <line2> . 'y|@"'
+
+" Output the result of a command to the buf
+command! -nargs=+ -complete=command Output
+ \ redir => output |
+ \ silent execute <q-args> |
+ \ redir END |
+ \ tabnew |
+ \ setlocal buftype=nofile bufhidden=wipe noswapfile nobuflisted nomodified |
+ \ silent put=output |
+ \ if <q-args> =~ ':!' |
+ \ silent 1,2delete _ |
+ \ else |
+ \ silent 1,4delete _ |
+ \ endif
+
+" Copy buffer to system clipboard
+command! Copy silent w !pbcopy
+
+" Copy the location of the current file
+command! CopyDir !echo %:r | pbcopy
+
+" View in-memory changes before writing to disk
+command! DiffOnDisk
+ \ let orig_filetype=&ft |
+ \ vert new |
+ \ read ++edit # | 0d_ |
+ \ setlocal bt=nofile bh=wipe nobl noswf ro |
+ \ let &l:filetype = orig_filetype |
+ \ diffthis |
+ \ wincmd p |
+ \ diffthis
+
+command WrapItUp setlocal wrap
+ \| nnoremap <buffer> j gj
+ \| nnoremap <buffer> k gk
+ \| nnoremap <buffer> 0 g0
+ \| nnoremap <buffer> $ g$
+
+" Miscellaneous
+"""""""""""""""""""""""""""
+
+" Show the color column only if insert mode (and only if cc is set)
+augroup ShowCCInInsertMode
+ au!
+ au InsertEnter * if &tw != 0 | let &cc = &tw + 1 | endif
+ au InsertLeave * let &cc = 0
+augroup END
+
+" Auto-refresh vim config
+" au BufWritePost $XDG_CONFIG_HOME/*.{vim,lua} so %
+
+" Jump to last editing location when opening files
+au BufReadPost *
+ \ if line("'\"") > 0 && line("'\"") <= line("$") |
+ \ exe "normal! g'\"" |
+ \ endif
+
+augroup Sus
+ au!
+
+ " Add syntax groups if relevant. This conditional is compensating for
+ " the lack of negative matches in :au.
+ "
+ " See: https://vim.fandom.com/wiki/Highlight_unwanted_spaces
+ " See: https://stackoverflow.com/questions/6496778/vim-run-autocmd-on-all-filetypes-except
+ fun! s:AddSyntax()
+ if bufname() !~ 'term://\|man://'
+ " Any trailing whitespace at the end of lines.
+ syn match SusWhitespace /\s\+$/ containedin=ALL
+
+ " Any non-breaking spaces. These are generated by
+ " CMD+SPACE and deeply annoying.
+ syn match SusWhitespace /\%u00A0/ containedin=ALL
+
+ " Any characters beyond the maximum width of the text.
+ if &tw > 0
+ let reg = '\%' . (&tw + 1) . 'v.\+'
+ exe 'syn match SusWhitespace /'.reg.'/ containedin=ALL'
+ endif
+ endif
+ endfun
+
+ " Remove highligt group.
+ "
+ " Note that we have to do abit more work since the the syntax rules
+ " have changed under Vim's nose. Hopefully the perfomance
+ " characteristics don't come back to haunt us.
+ fun! s:RemoveSyntax()
+ syn clear SusWhitespace
+ syn sync fromstart
+ endfun
+
+ " Add a persistent highligt group, which matches are going to use.
+ au VimEnter,ColorScheme * hi SusWhitespace ctermbg=red guibg=red
+
+ " Create some persistent syntax highlighting groups.
+ au Syntax * call s:AddSyntax()
+
+ " When 'textwidth' changes, we may need to recalculate.
+ au OptionSet textwidth call s:RemoveSyntax()
+ \ | call s:AddSyntax()
+
+ " Temporarily remove the groups when in insert mode.
+ au InsertEnter * call s:RemoveSyntax()
+ au InsertLeave * call s:AddSyntax()
+augroup END
+
+" Allow for quick prototyping outside of NixOS/Home-Manager by loading some
+" extra configuration if relevant.
+let extra_vimrc = expand("~/extra-temporary.vimrc")
+if filereadable(extra_vimrc)
+ execute "source " . extra_vimrc
+endif
diff --git a/shared/home-manager/neovim/lsp.nix b/shared/home-manager/neovim/lsp.nix
new file mode 100644
index 0000000..bc10487
--- /dev/null
+++ b/shared/home-manager/neovim/lsp.nix
@@ -0,0 +1,59 @@
+# Installs and configures lspconfig. The actual LSPs are added in the per-language profiles.
+{pkgs, ...}: {
+ programs.neovim.plugins = [
+ {
+ plugin = pkgs.vimPlugins.nvim-lspconfig;
+ type = "lua";
+ config = ''
+ local lspconfig = require("lspconfig")
+ local util = require("lspconfig.util")
+
+ -- Mappings.
+ -- See `:help vim.diagnostic.*` for documentation on any of the below functions
+ local opts = { noremap=true, silent=true }
+ vim.keymap.set('n', '<leader>e', vim.diagnostic.open_float, opts)
+ vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts)
+ vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts)
+ vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, opts)
+
+ -- Use an on_attach function to only map the following keys
+ -- after the language server attaches to the current buffer
+ vim.api.nvim_create_autocmd("LspAttach", {
+ callback = function(args)
+ local bufnr = args.buf
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+
+ -- Enable completion triggered by <c-x><c-o>
+ if client.server_capabilities.completionProvider then
+ vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc"
+ end
+
+ -- XXX: What does this do?
+ if client.server_capabilities.definitionProvider then
+ vim.bo[bufnr].tagfunc = "v:lua.vim.lsp.tagfunc"
+ end
+
+ -- Mappings.
+ -- See `:help vim.lsp.*` for documentation on any of the below functions
+ local bufopts = { noremap=true, silent=true, buffer=bufnr }
+ vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts)
+ vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts)
+ vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts)
+ vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, bufopts)
+ vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, bufopts)
+ vim.keymap.set('n', '<leader>wa', vim.lsp.buf.add_workspace_folder, bufopts)
+ vim.keymap.set('n', '<leader>wr', vim.lsp.buf.remove_workspace_folder, bufopts)
+ vim.keymap.set('n', '<leader>wl', function()
+ print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
+ end, bufopts)
+ vim.keymap.set('n', '<leader>D', vim.lsp.buf.type_definition, bufopts)
+ vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, bufopts)
+ vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, bufopts)
+ vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts)
+ vim.keymap.set('n', '<leader>f', function() vim.lsp.buf.format { async = true } end, bufopts)
+ end,
+ })
+ '';
+ }
+ ];
+}
diff --git a/shared/home-manager/networking-utils/default.nix b/shared/home-manager/networking-utils/default.nix
new file mode 100644
index 0000000..70802a9
--- /dev/null
+++ b/shared/home-manager/networking-utils/default.nix
@@ -0,0 +1,10 @@
+# This module adds some networking utilities to my home managed environment.
+{pkgs, ...}: {
+ home.packages = with pkgs;
+ [
+ nmap
+ inetutils
+ socat
+ ]
+ ++ lib.optional (!pkgs.stdenv.isDarwin) netcat;
+}
diff --git a/shared/home-manager/nix/default.nix b/shared/home-manager/nix/default.nix
new file mode 100644
index 0000000..dcdff2a
--- /dev/null
+++ b/shared/home-manager/nix/default.nix
@@ -0,0 +1,14 @@
+# This module configures development tools for Nix.
+{pkgs, ...}: {
+ programs.neovim = {
+ plugins = with pkgs.vimPlugins; [
+ vim-nix
+ ];
+
+ extraLuaConfig = ''
+ require("lspconfig")["nixd"].setup({
+ cmd = { "${pkgs.nixd}/bin/nixd" },
+ })
+ '';
+ };
+}
diff --git a/shared/home-manager/noweb/default.nix b/shared/home-manager/noweb/default.nix
new file mode 100644
index 0000000..1506431
--- /dev/null
+++ b/shared/home-manager/noweb/default.nix
@@ -0,0 +1,16 @@
+{pkgs, ...}: {
+ home.packages = with pkgs; [
+ noweb
+ texliveFull
+ yalafi-shell
+ ];
+
+ programs.neovim.plugins = with pkgs; [
+ vim-noweb
+ ];
+
+ # Prepend nowebs STY files to the search path. I chose to do it globally,
+ # rather than using `makeWrapper` because I sometimes want to manually invoke
+ # `pdflatex` and the like on the output of `noweave`.
+ home.sessionVariables.TEXINPUTS = "${pkgs.noweb.tex}/tex/latex/noweb/:$TEXINPUTS";
+}
diff --git a/shared/home-manager/python/default.nix b/shared/home-manager/python/default.nix
new file mode 100644
index 0000000..380d352
--- /dev/null
+++ b/shared/home-manager/python/default.nix
@@ -0,0 +1,16 @@
+# This module configures development tools for Python.
+{pkgs, ...}: {
+ home.packages = with pkgs; [
+ (python311Full.withPackages (ps:
+ with ps; [
+ virtualenv
+ tkinter
+ ]))
+ ];
+
+ programs.neovim.extraLuaConfig = ''
+ require("lspconfig")["pyright"].setup({
+ cmd = { "${pkgs.pyright}/bin/pyright-langserver", "--stdio" },
+ })
+ '';
+}
diff --git a/shared/home-manager/qbittorrent/default.nix b/shared/home-manager/qbittorrent/default.nix
new file mode 100644
index 0000000..0b7e2b1
--- /dev/null
+++ b/shared/home-manager/qbittorrent/default.nix
@@ -0,0 +1,5 @@
+# Adds qbittorrent.
+# FIXME: Configuration is still stored mutably.
+{pkgs, ...}: {
+ home.packages = [pkgs.qbittorrent];
+}
diff --git a/shared/home-manager/rust/default.nix b/shared/home-manager/rust/default.nix
new file mode 100644
index 0000000..3ca301c
--- /dev/null
+++ b/shared/home-manager/rust/default.nix
@@ -0,0 +1,13 @@
+# This module configures development tools for Rust.
+{pkgs, ...}: {
+ home.packages = with pkgs; [
+ rustc
+ cargo
+ ];
+
+ programs.neovim.extraLuaConfig = ''
+ require("lspconfig")["rust_analyzer"].setup({
+ cmd = { "${pkgs.rust-analyzer}/bin/rust-analyzer" },
+ })
+ '';
+}
diff --git a/shared/home-manager/shell-utils/default.nix b/shared/home-manager/shell-utils/default.nix
new file mode 100644
index 0000000..8635ceb
--- /dev/null
+++ b/shared/home-manager/shell-utils/default.nix
@@ -0,0 +1,34 @@
+# This module adds some common shell utilities to my home managed environment.
+{pkgs, ...}: let
+ isLinux = pkgs.stdenv.isLinux;
+ isDarwin = pkgs.stdenv.isDarwin;
+in {
+ home.packages = with pkgs;
+ [
+ human-sleep
+ ripgrep
+ jc
+ jq
+ nowrap
+ echoargs
+ ]
+ ++ lib.optionals isLinux [
+ file # File is not included in NixOS, but *is* included in Darwin.
+ ]
+ ++ lib.optionals isDarwin [
+ pbv
+ trash
+ disable-sleep
+
+ # Unlike the `stat` command on Linux (from coreutils or whatever), OSX's
+ # `stat` does not automatically use the nicer format when stdout is a
+ # sterminal.
+ (pkgs.writeShellScriptBin "stat" ''
+ if [ -t 1 ]; then
+ /usr/bin/stat -x "$@"
+ else
+ /usr/bin/stat "$@"
+ fi
+ '')
+ ];
+}
diff --git a/shared/home-manager/svelte/default.nix b/shared/home-manager/svelte/default.nix
new file mode 100644
index 0000000..7b76041
--- /dev/null
+++ b/shared/home-manager/svelte/default.nix
@@ -0,0 +1,15 @@
+# This module configures development tools for Svelte.
+{pkgs, ...}: {
+ programs.neovim = {
+ plugins = with pkgs.vimPlugins; [
+ vim-svelte
+ ];
+
+ extraLuaConfig = ''
+ require("lspconfig")["svelte"].setup({
+ cmd = { "${pkgs.nodePackages_latest.svelte-language-server}/bin/svelteserver", "--stdio" },
+ root_dir = util.root_pattern("package.json", ".git", "deno.json", "deno.jsonc"),
+ })
+ '';
+ };
+}
diff --git a/shared/home-manager/zsh/default.nix b/shared/home-manager/zsh/default.nix
new file mode 100644
index 0000000..31796a9
--- /dev/null
+++ b/shared/home-manager/zsh/default.nix
@@ -0,0 +1,31 @@
+{config, ...}: {
+ imports = [
+ ./plugins.nix
+ ./editing.nix
+ ];
+
+ programs.zsh = {
+ enable = true;
+
+ # Feeble attempt at cleaning up home directory.
+ # TODO: dotDir = (pathRelativeTo config.xdg.configHome config.home) + "/zsh";
+ dotDir = ".config/zsh";
+ history.path = config.xdg.cacheHome + "/zsh/history";
+
+ initExtra = ''
+ set -o PROMPTSUBST
+ if [ -v NVIM -o -v VIM ]; then
+ # smol prompt
+ PROMPT='%# '
+ else
+ # loong looooong prooooompt – Nagāi Sakeru Gumi
+ PROMPT='%B%(2L.LVL%L .)%b%F{red}%(?..E%? )%f%F{93}%n%f@%F{35}%m%f%# '
+ fi
+ RPROMPT='%F{green}%$((COLUMNS/4))<...<%~%<<%f'
+
+ mkcd () {
+ mkdir "$1" && cd "$1"
+ }
+ '';
+ };
+}
diff --git a/shared/home-manager/zsh/editing.nix b/shared/home-manager/zsh/editing.nix
new file mode 100644
index 0000000..241ef3c
--- /dev/null
+++ b/shared/home-manager/zsh/editing.nix
@@ -0,0 +1,43 @@
+# This module contains all ZSH configuration related to the editing experience (e.g. setting VI mode).
+{
+ pkgs,
+ lib,
+ ...
+}: let
+ inherit (lib.strings) concatStringsSep;
+ inherit (lib.attrsets) catAttrs;
+
+ plugins = [
+ {
+ name = "zsh-vi-mode-cursor";
+ src = pkgs.fetchFromGitHub {
+ owner = "Buckmeister";
+ repo = "zsh-vi-mode-cursor";
+ rev = "fa7cc0973ee71636e906e25e782d0aea19545d60";
+ hash = "sha256-j73M4bvAoHWt5Wwg47hM0p5Or74x/3btTOPnI22SqG8=";
+ };
+ }
+ ];
+in {
+ programs.zsh = {
+ # VIM! VIM! VIM!
+ defaultKeymap = "viins";
+
+ plugins = map (p: removeAttrs p ["config"]) plugins;
+
+ initExtra = ''
+ # Set up external editing by pressing '!' in normal mode.
+ autoload -z edit-command-line
+ zle -N edit-command-line
+ bindkey -M vicmd '!' edit-command-line
+
+ # Plugins config.
+ ${concatStringsSep "\n" (catAttrs "config" plugins)}
+ '';
+ };
+
+ programs.fzf = {
+ enable = true;
+ enableZshIntegration = true;
+ };
+}
diff --git a/shared/home-manager/zsh/plugins.nix b/shared/home-manager/zsh/plugins.nix
new file mode 100644
index 0000000..6dbc151
--- /dev/null
+++ b/shared/home-manager/zsh/plugins.nix
@@ -0,0 +1,47 @@
+# This module manages behavioral plugins – plugins that alter how ZSH acts (e.g. autovenv, direnv).
+{
+ pkgs,
+ lib,
+ config,
+ ...
+}: let
+ inherit (lib.strings) concatStringsSep;
+ inherit (lib.attrsets) catAttrs;
+
+ plugins = [
+ {
+ name = "autovenv";
+ src = pkgs.fetchFromGitHub {
+ owner = "linnnus";
+ repo = "autovenv";
+ rev = "d9f0cd7";
+ hash = "sha256-GfJIybMYxE97xLSkrOSGsn+AREmnCyqe9n2aZwjw4w4=";
+ };
+ }
+ {
+ name = "zsh-vi-mode-cursor";
+ src = pkgs.fetchFromGitHub {
+ owner = "Buckmeister";
+ repo = "zsh-vi-mode-cursor";
+ rev = "fa7cc0973ee71636e906e25e782d0aea19545d60";
+ hash = "sha256-j73M4bvAoHWt5Wwg47hM0p5Or74x/3btTOPnI22SqG8=";
+ };
+ }
+ {
+ name = "zsh-nix-shell";
+ file = "nix-shell.plugin.zsh";
+ src = pkgs.fetchFromGitHub {
+ owner = "chisui";
+ repo = "zsh-nix-shell";
+ rev = "v0.7.0";
+ sha256 = "149zh2rm59blr2q458a5irkfh82y3dwdich60s9670kl3cl5h2m1";
+ };
+ }
+ ];
+in {
+ programs.zsh = {
+ plugins = map (p: removeAttrs p ["config"]) plugins;
+
+ initExtra = concatStringsSep "\n" (catAttrs "config" plugins);
+ };
+}
diff --git a/shared/nixos/cloudflare-proxy/default.nix b/shared/nixos/cloudflare-proxy/default.nix
new file mode 100644
index 0000000..45ccaa6
--- /dev/null
+++ b/shared/nixos/cloudflare-proxy/default.nix
@@ -0,0 +1,88 @@
+# This module adds some extra configuration useful when running behid a Cloudflare Proxy.
+# Mainly, it blocks all incomming conncections on relevant ports that aren't
+# coming from an official CloudFlare domain.
+{
+ config,
+ lib,
+ pkgs,
+ metadata,
+ ...
+}: let
+ # TODO: What happens when these get out of date??? Huh??? You little pissbaby
+ fileToList = x: lib.strings.splitString "\n" (builtins.readFile x);
+ cfipv4 = fileToList (pkgs.fetchurl {
+ url = "https://www.cloudflare.com/ips-v4";
+ hash = "sha256-8Cxtg7wBqwroV3Fg4DbXAMdFU1m84FTfiE5dfZ5Onns=";
+ });
+ cfipv6 = fileToList (pkgs.fetchurl {
+ url = "https://www.cloudflare.com/ips-v6";
+ hash = "sha256-np054+g7rQDE3sr9U8Y/piAp89ldto3pN9K+KCNMoKk=";
+ });
+
+ IPv4Whitelist = [metadata.hosts.muhammed.ipAddress];
+ IPv6Whitelist = [];
+in {
+ config = {
+ # Teach NGINX how to extract the proxied IP from proxied requests.
+ #
+ # See: https://nixos.wiki/wiki/Nginx#Using_realIP_when_behind_CloudFlare_or_other_CDN
+ services.nginx.commonHttpConfig = let
+ realIpsFromList = lib.strings.concatMapStringsSep "\n" (x: "set_real_ip_from ${x};");
+ in ''
+ ${realIpsFromList cfipv4}
+ ${realIpsFromList cfipv6}
+ real_ip_header CF-Connecting-IP;
+ '';
+
+ # Block non-Cloudflare IP addresses.
+ networking.firewall = let
+ chain = "cloudflare-whitelist";
+ in {
+ extraCommands = let
+ allow-interface = lib.strings.concatMapStringsSep "\n" (i: ''ip46tables --append ${chain} --in-interface ${i} --jump RETURN'');
+ allow-ip = cmd: lib.strings.concatMapStringsSep "\n" (r: ''${cmd} --append ${chain} --source ${r} --jump RETURN'');
+ in ''
+ # Flush the old firewall rules. This behavior mirrors the default firewall service.
+ # See: https://github.com/NixOS/nixpkgs/blob/ac911bf685eecc17c2df5b21bdf32678b9f88c92/nixos/modules/services/networking/firewall-iptables.nix#L59-L66
+ ip46tables --delete INPUT --protocol tcp --destination-port 80 --syn --jump ${chain} 2>/dev/null || true
+ ip46tables --delete INPUT --protocol tcp --destination-port 443 --syn --jump ${chain} 2>/dev/null || true
+ ip46tables --flush ${chain} || true
+ ip46tables --delete-chain ${chain} || true
+
+ # Create a chain that only allows whitelisted IPs through.
+ ip46tables --new-chain ${chain}
+
+ # Allow trusted interfaces through.
+ ${allow-interface config.networking.firewall.trustedInterfaces}
+
+ # Allow local whitelisted IPs through
+ ${allow-ip "iptables" IPv4Whitelist}
+ ${allow-ip "ip6tables" IPv6Whitelist}
+
+ # Allow Cloudflare's IP ranges through.
+ ${allow-ip "iptables" cfipv4}
+ ${allow-ip "ip6tables" cfipv6}
+
+ # Everything else is dropped.
+ #
+ # TODO: I would like to use `nixos-fw-log-refuse` here, but I keep
+ # running into weird issues when reloading the firewall.
+ # Something about the table not being deleted properly.
+ ip46tables --append ${chain} --jump DROP
+
+ # Inject our chain as the first check in INPUT (before nixos-fw).
+ # We want to capture any new incomming TCP connections.
+ ip46tables --insert INPUT 1 --protocol tcp --destination-port 80 --syn --jump ${chain}
+ ip46tables --insert INPUT 1 --protocol tcp --destination-port 443 --syn --jump ${chain}
+ '';
+ extraStopCommands = ''
+ # Clean up added rulesets (${chain}). This mirrors the behavior of the
+ # default firewall at the time of writing.
+ #
+ # See: https://github.com/NixOS/nixpkgs/blob/ac911bf685eecc17c2df5b21bdf32678b9f88c92/nixos/modules/services/networking/firewall-iptables.nix#L218-L219
+ ip46tables --delete INPUT --protocol tcp --destination-port 80 --syn --jump ${chain} 2>/dev/null || true
+ ip46tables --delete INPUT --protocol tcp --destination-port 443 --syn --jump ${chain} 2>/dev/null || true
+ '';
+ };
+ };
+}
diff --git a/shared/nixos/common-hm-settings/default.nix b/shared/nixos/common-hm-settings/default.nix
new file mode 100644
index 0000000..9262f51
--- /dev/null
+++ b/shared/nixos/common-hm-settings/default.nix
@@ -0,0 +1,27 @@
+# This module sets common settings related to home-manager (HM). All hosts that
+# I directly interact with should include this module.
+#
+# NOTE: Even though this lives under `shared/nixos` the configuration in here
+# should also be compatible with nix-darwin!!
+{
+ flakeInputs,
+ flakeOutputs,
+ metadata,
+ ...
+}: {
+ # FIXME: Ideally this module would import flakeInputs.home-manager but that causes an infinite recursion for some reason.
+
+ # Use the flake input pkgs so Home Manager configuration can share overlays
+ # etc. with the rest of the configuration.
+ home-manager.useGlobalPkgs = true;
+
+ # Pass special arguments from flake.nix further down the chain. I really hate
+ # this split module system.
+ home-manager.extraSpecialArgs = {inherit flakeInputs flakeOutputs metadata;};
+
+ # All interactive systems (i.e. the ones that would use HM) have a 'linus' user.
+ home-manager.users.linus = {
+ imports = builtins.attrValues flakeOutputs.homeModules;
+ xdg.enable = true;
+ };
+}
diff --git a/shared/nixos/common-nix-settings/default.nix b/shared/nixos/common-nix-settings/default.nix
new file mode 100644
index 0000000..b5c0a02
--- /dev/null
+++ b/shared/nixos/common-nix-settings/default.nix
@@ -0,0 +1,60 @@
+# This module sets common settings related to Nix such as enabling flakes and
+# using overlays everywhere..
+#
+# NOTE: Even though this lives under `shared/nixos` the configuration in here
+# should also be compatible with nix-darwin!!
+{
+ pkgs,
+ lib,
+ config,
+ flakeInputs,
+ flakeOutputs,
+ ...
+}:
+lib.mkMerge [
+ {
+ # Enable de facto stable features.
+ nix.settings.experimental-features = ["nix-command" "flakes"];
+
+ nixpkgs.overlays = [
+ # Use local overlays.
+ flakeOutputs.overlays.additions
+ flakeOutputs.overlays.modifications
+
+ # Add unstable nixpkgs.
+ (final: prev: {unstable = flakeInputs.nixpkgs-unstable.legacyPackages.${pkgs.system};})
+ ];
+
+ # I'm not *that* vegan.
+ nixpkgs.config.allowUnfree = true;
+
+ # This will add each flake input as a registry
+ # To make nix3 commands consistent with your flake
+ nix.registry = lib.mapAttrs (_: value: {flake = value;}) flakeInputs;
+
+ nix.nixPath =
+ [
+ # Use overlays from this repo for building system configuration as well as system-wide.
+ # See: https://nixos.wiki/wiki/Overlays#Using_nixpkgs.overlays_from_configuration.nix_as_.3Cnixpkgs-overlays.3E_in_your_NIX_PATH
+ "nixpkgs-overlays=${flakeInputs.self}/overlays/compat.nix"
+
+ # This will additionally add out inputs to the system's legacy channels
+ # Making legacy nix commands consistent as well, awesome!
+ ]
+ ++ lib.mapAttrsToList (key: value: "${key}=${value.to.path}") config.nix.registry;
+
+ # Add shell-utilities which are only relevant if Nix is enabled.
+ environment.systemPackages = with pkgs; [
+ # For running programs easily.
+ nix-index # Also includes nix-locate
+ flakeInputs.comma.packages.${system}.default
+
+ # For editing secrets.
+ flakeInputs.agenix.packages.${system}.default
+ ];
+ }
+ (lib.mkIf pkgs.stdenv.isLinux {
+ # There is not nix-darwin equivalent to this NixOS option.
+ nix.enable = true;
+ })
+]
diff --git a/shared/nixos/common-shell-settings/default.nix b/shared/nixos/common-shell-settings/default.nix
new file mode 100644
index 0000000..ec71861
--- /dev/null
+++ b/shared/nixos/common-shell-settings/default.nix
@@ -0,0 +1,44 @@
+# This module sets options to ensure a consistent Baseline Shell Experince™
+# across the entire fleet. This includes e.g. common utilities and aliases.
+#
+# NOTE: Even though this lives under `shared/nixos` the configuration in here
+# should also be compatible with nix-darwin!!
+{pkgs, ...}: {
+ # Set ZSH as the shell.
+ # https://nixos.wiki/wiki/Command_Shell#Changing_default_shelltrue
+ programs.zsh.enable = true;
+ environment.shells = [pkgs.zsh];
+
+ # Very basic system administration tools.
+ environment.systemPackages = with pkgs; [
+ curl
+ jq
+ moreutils
+ neovim
+ tree
+ ];
+
+ # Aliases that are burned into my muscle memory.
+ environment.shellAliases = {
+ "mv" = "mv -i";
+ "rm" = "rm -i";
+ "cp" = "cp -i";
+ "ls" = "ls -F -G -A --color=auto";
+ "grep" = "grep --color=auto";
+ "file" = "file --no-dereference";
+ "tree" = "tree --dirsfirst --gitignore";
+
+ # See: https://github.com/NixOS/nix/issues/5858
+ "nix" = "nix --print-build-logs";
+
+ ".." = "cd ../";
+ "..." = "cd ../../";
+ "...." = "cd ../../../";
+ "....." = "cd ../../../../";
+ "......" = "cd ../../../../../";
+ "......." = "cd ../../../../../../";
+ "........" = "cd ../../../../../../../";
+ "........." = "cd ../../../../../../../../";
+ ".........." = "cd ../../../../../../../../../";
+ };
+}