Nix Chad

An opinionated macOS setup focused on software development.
Features
Firefox
discoverable key mappings
After pressing ? key a window enumerating all contextual key mappings
appears.
Neovim
programming/configuration languages support

| language | actions | completion | diagnostics | formatting | highlighting |
|---|---|---|---|---|---|
| bash | ☒ | ☑ | ☑ | ☑ | ☑ |
| dhall | ☒ | ☑ | ☑ | ☑ | ☑ |
| docker | ☒ | ☒ | ☑ | ☒ | ☑ |
| GitHub Actions workflow | ☑ | ☑ | ☑ | ☑ | ☑ |
| html | ☒ | ☑ | ☑ | ☑ | ☑ |
| java | ☒ | ☑ | ☑ | ☑ | ☑ |
| json | ☒ | ☑ | ☑ | ☑ | ☑ |
| javascript | ☑ | ☑ | ☑ | ☑ | ☑ |
| lua | ☑ | ☑ | ☑ | ☑ | ☑ |
| markdown | ☑ | ☑ | ☑ | ☑ | ☑ |
| nix | ☒ | ☑ | ☑ | ☑ | ☑ |
| purescript | ☑ | ☑ | ☑ | ☑ | ☑ |
| python | ☑ | ☑ | ☑ | ☑ | ☑ |
| typescript | ☑ | ☑ | ☑ | ☑ | ☑ |
| yaml | ☑ | ☒ | ☑ | ☑ | ☑ |
discoverable key mappings
After pressing \ key a window enumerating all key mappings appears.
The same window shows when user starts but does not finish a key
sequence which has some action assigned to it.
Prerequisites
Configuration
Initializing from a template
Run from a directory of your choice:
nix flake init --template github:mstream/nix-chad/main#default
Tweaking
Update any config entries to your liking, like in this example.
Applying
After any change to configuration, run from the directory where
flake.nix file resides:
nix run .#switch
Warning
While it is easy to roll back unwanted/broken configuration by either
reverting your configuration changes or using a different nix-chad
flake revision, there are some classes of misconfigurations that are
more difficult to undo.
One of them is one that results in an error during ZSH shell
initialization. If that results in, e.g. PATH environmental variable
not being properly set, you may lose easy access to your binaries.
In this situation, to recover back to working state, you may need to:
- switch to Bash using an absolute binary path
- use GUI tools (maybe enough to edit but not enough to rebuild Nix configuration)
- set
PATHenvironmental variable manually (requires knowledge about Nix) - install needed binaries without nix (an overkill just for recovery)
- using absolute
nix storepaths (very fiddly)
None of these options are convenient and most of them require relatively broad administrative knowledge. Thus, after every switch, it is highly recommended to:
- leave current shell session open
- create a new one,
- observe if initialization scripts do not produce any errors,
- and if so, use the previous session to fix the issues
Updating
To stay up-to-date witch changes to Nix Chad, run periodically:
nix flake update
chad.browser.bookmarks
Browser bookmarks.
Type: (list of ((bookmark submodule) or (directory submodule))) or (attribute set of ((bookmark submodule) or (directory submodule))) convertible to it
Default:
[ ]
Example:
[
{
bookmarks = [
{
keyword = "nixpkgs";
name = "NixOS Search - Packages";
tags = [
"nix"
];
url = "https://search.nixos.org/packages";
}
];
name = "Nix sites";
toolbar = true;
}
{
title = "Nix Chad";
url = "https://github.com/mstream/nix-chad";
}
]
Declared by:
chad.browser.extraExtensions
Additional Firefox extensions to be installed for the user.
Type: null or (function that evaluates to a(n) list of package)
Default:
null
Example:
exts: with exts; [ grammarly ];
Declared by:
chad.editor.documentWidth
Ideal maximum document’s width measured in number of characters.
Type: signed integer
Default:
72
Declared by:
chad.editor.keyMappings.categorized.close.suffixes.currentBuffer
close the current buffer
Type: string
Default:
"bc"
Declared by:
chad.editor.keyMappings.categorized.comment.suffixes.addEndOfLine
add at the end of line
Type: string
Default:
"lA"
Declared by:
chad.editor.keyMappings.categorized.comment.suffixes.addLineAbove
add line above
Type: string
Default:
"lO"
Declared by:
chad.editor.keyMappings.categorized.comment.suffixes.addLineBelow
add line below
Type: string
Default:
"lo"
Declared by:
chad.editor.keyMappings.categorized.comment.suffixes.block
block operator-pending
Type: string
Default:
"b"
Declared by:
chad.editor.keyMappings.categorized.comment.suffixes.line
line operator-pending
Type: string
Default:
"l"
Declared by:
chad.editor.keyMappings.categorized.comment.suffixes.toggleBlock
toggle block
Type: string
Default:
"tb"
Declared by:
chad.editor.keyMappings.categorized.comment.suffixes.toggleLine
toggle line
Type: string
Default:
"tl"
Declared by:
chad.editor.keyMappings.categorized.debug.suffixes.toggleDiagnosticsWindow
toggle diagnostics window
Type: string
Default:
"x"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.codeDefinitions
code definitions
Type: string
Default:
"cd"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.codeImplementations
code implementations
Type: string
Default:
"ci"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.codeReferences
code references
Type: string
Default:
"cr"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.codeTypeDefinitions
code type definitions
Type: string
Default:
"ct"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.files
files
Type: string
Default:
"f"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.gitBranches
Git branches
Type: string
Default:
"gb"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.gitCommits
Git commits
Type: string
Default:
"gc"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.gitLocalChanges
Git local changes
Type: string
Default:
"gl"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.gitStash
Git stashed changes
Type: string
Default:
"gs"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.implementations
implementations
Type: string
Default:
"i"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.vimBuffers
Vim buffers
Type: string
Default:
"vb"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.vimCommands
Vim commands
Type: string
Default:
"vc"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.vimHelp
Vim help topics
Type: string
Default:
"vh"
Declared by:
chad.editor.keyMappings.categorized.find.suffixes.words
words across files
Type: string
Default:
"w"
Declared by:
chad.editor.keyMappings.categorized.goTo.suffixes.declaration
declaration
Type: string
Default:
"D"
Declared by:
chad.editor.keyMappings.categorized.goTo.suffixes.definition
definition
Type: string
Default:
"d"
Declared by:
chad.editor.keyMappings.categorized.goTo.suffixes.implementation
implementation
Type: string
Default:
"i"
Declared by:
chad.editor.keyMappings.categorized.goTo.suffixes.nextProblem
next problem
Type: string
Default:
"]"
Declared by:
chad.editor.keyMappings.categorized.goTo.suffixes.previousProblem
previous problem
Type: string
Default:
"["
Declared by:
chad.editor.keyMappings.categorized.refactor.suffixes.action
action
Type: string
Default:
"a"
Declared by:
chad.editor.keyMappings.categorized.refactor.suffixes.format
format
Type: string
Default:
"f"
Declared by:
chad.editor.keyMappings.categorized.refactor.suffixes.name
name
Type: string
Default:
"n"
Declared by:
chad.editor.keyMappings.categorized.select.suffixes.decrement
decrement selection
Type: string
Default:
"d"
Declared by:
chad.editor.keyMappings.categorized.select.suffixes.increment
increment selection
Type: string
Default:
"i"
Declared by:
chad.editor.keyMappings.categorized.select.suffixes.initialize
initialize selection
Type: string
Default:
"s"
Declared by:
chad.editor.keyMappings.uncategorized.cancel
Cancel current selection or mode
Type: string
Default:
"<ESC>"
Declared by:
chad.editor.keyMappings.uncategorized.confirm
Confirm current selection
Type: string
Default:
"<CR>"
Declared by:
chad.editor.keyMappings.uncategorized.moveToBottomWindow
Move to window on the bottom
Type: string
Default:
"<C-j>"
Declared by:
chad.editor.keyMappings.uncategorized.moveToLeftWindow
Move to window on the left
Type: string
Default:
"<C-h>"
Declared by:
chad.editor.keyMappings.uncategorized.moveToRightWindow
Move to window on the right
Type: string
Default:
"<C-l>"
Declared by:
chad.editor.keyMappings.uncategorized.moveToTopWindow
Move to window on the top
Type: string
Default:
"<C-k>"
Declared by:
chad.editor.keyMappings.uncategorized.scrollDown
Scroll content down (half a page)
Type: string
Default:
"<C-d>"
Declared by:
chad.editor.keyMappings.uncategorized.scrollDownFullPage
Scroll content down (full page)
Type: string
Default:
"<C-f>"
Declared by:
chad.editor.keyMappings.uncategorized.scrollUp
Scroll content up (half a page)
Type: string
Default:
"<C-u>"
Declared by:
chad.editor.keyMappings.uncategorized.scrollUpFullPage
Scroll content up (full page)
Type: string
Default:
"<C-b>"
Declared by:
chad.editor.keyMappings.uncategorized.selectNext
Select next item on a list
Type: string
Default:
"<C-n>"
Declared by:
chad.editor.keyMappings.uncategorized.selectPrevious
Select previous item on a list
Type: string
Default:
"<C-p>"
Declared by:
chad.editor.keyMappings.uncategorized.showKeyMappings
Show key mappings
Type: string
Default:
"\\"
Declared by:
chad.editor.keyMappings.uncategorized.showSymbolInfo
Show information about the symbol under the cursor
Type: string
Default:
"K"
Declared by:
chad.editor.keyMappings.uncategorized.switchToNextTab
switch to next tab
Type: string
Default:
"<TAB>"
Declared by:
chad.editor.keyMappings.uncategorized.switchToPreviousTab
switch to previous tab
Type: string
Default:
"<S-TAB>"
Declared by:
chad.editor.lineNumbering
Absolute: line numbers counted from the beginning of the document Relative: line numbers counted from the current cursor position
Type: one of “absolute”, “relative”
Default:
"relative"
Declared by:
chad.editor.tabWidth
Tabulation width measured in number of characters.
Type: signed integer
Default:
2
Declared by:
chad.extraPackages
Additional nixpkgs packages to be accessible for the user.
Type: null or (function that evaluates to a(n) list of package)
Default:
null
Example:
pkgs: with pkgs; [ cowsay ];
Declared by:
chad.fontSize
A desired font size in tools that have means to set it fixed.
Type: signed integer
Default:
12
Example:
16
Declared by:
chad.git.alternativeGitIdentities
Alternative Git identities for selected repositories.
Type: list of (submodule)
Default:
[ ]
Example:
[
{
repositoryUrl = "git@github.com:somecompany/**";
sshKeyPath = "~/.ssh/work_id_rsa";
userEmail = "me@somecompany.com";
}
]
Declared by:
chad.git.alternativeGitIdentities.*.repositoryUrl
Git repository URL.
Type: string
Declared by:
chad.git.alternativeGitIdentities.*.sshKeyPath
Path to a SSH private key.
Type: string
Declared by:
chad.git.alternativeGitIdentities.*.userEmail
Key.
Type: string
Declared by:
chad.gpg.defaultKey
An ID of a key to be used for GPG signing by default. This is expected to be different for individuals. The key is not part of this repository and has to be provided manually.
Type: null or string
Default:
null
Example:
"BE318F09150F6CB0724FFEC0319EE1D7FC029354"
Declared by:
chad.initialSetup
Should be enabled when the switch is run for the first time
Type: boolean
Default:
false
Declared by:
chad.keyboard.disableKeyRepeat
Holding keys does not make characters being typed repeatedly.
Type: boolean
Default:
true
Declared by:
chad.keyboard.remapCapsLock
Treat Caps Lock key as Escape key.
Type: boolean
Default:
true
Declared by:
chad.keyboard.remapLeftArrow
Treat Left Arrow key as Right Control key.
Type: boolean
Default:
false
Declared by:
chad.keyboard.shortcuts
A set of macOS desktop-level shortcuts.
Type: attribute set of (submodule) (read only)
Default:
{
screenshot = {
modifierKeys = [
"command"
"shift"
];
otherKey = "S";
};
}
Declared by:
chad.keyboard.shortcuts.<name>.modifierKeys
A list of modifier keys.
Type: list of (one of “command”, “control”, “option”, “shift”) (read only)
Example:
[
"command"
"shift"
]
Declared by:
chad.keyboard.shortcuts.<name>.otherKey
A non-modifier key.
Type: one of “0”, “1”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9”, “A”, “B”, “C”, “D”, “E”, “F”, “G”, “H”, “I”, “J”, “K”, “L”, “M”, “N”, “O”, “P”, “Q”, “R”, “S”, “T”, “U”, “V”, “W”, “X”, “Y”, “Z” (read only)
Example:
"S"
Declared by:
chad.manageWindows.enable
Keep windows occupy maximum available share of space on desktop. Uses own emulation of multiple desktops/spaces.
Type: boolean
Default:
false
Declared by:
chad.manageWindows.exclusions
List of application names for which automatic window management should not be performed. It can be figured out using this command:
yabai -m query --windows
Type: list of (submodule)
Default:
[ ]
Example:
[
{
app = "^Discord$";
title = ".*Dialog$";
}
]
Declared by:
chad.manageWindows.exclusions.*.app
Regex for application name.
Type: string
Example:
"^Discord$"
Declared by:
chad.manageWindows.exclusions.*.title
Regex for window title.
Type: string
Default:
".*"
Example:
".*Dialog$"
Declared by:
chad.mouse.naturalScrollDirection
Should content scroll opposite to the swipe/roll direction.
Type: boolean
Default:
true
Declared by:
chad.software.openSourceOnly
Restricts software to Open Source only.
Type: boolean
Default:
true
Declared by:
chad.terminal.abbreviations.enable
Enables expandable command abbreviations.
Type: boolean
Default:
true
Declared by:
chad.terminal.abbreviations.extraAbbreviations
An attribute set that maps aliases (the top level attribute names in this option) to abbreviations. Abbreviations are expanded with the longer phrase after they are entered.
Type: attribute set of string
Default:
{ }
Example:
{
gco = "git checkout";
l = "less";
}
Declared by:
chad.terminal.keyBindings
Additional key bindings for terminal emulator.
Type: list of (submodule)
Default:
[ ]
Example:
[
{
chars = "\\u000c";
key = "K";
mods = "Control";
}
]
Declared by:
chad.terminal.keyBindings.*.chars
Substitution.
Type: string
Declared by:
chad.terminal.keyBindings.*.key
Key.
Type: string
Declared by:
chad.terminal.keyBindings.*.mods
Modifier key(s).
Type: string
Declared by:
chad.terminal.zshInitExtra
Additional initialization for ZSH sessions.
Type: strings concatenated with “\n”
Default:
""
Example:
''
export VAR1=val1
export VAR2=val2
''
Declared by:
chad.user.email
User’s e-mail address.
Type: string
Example:
"bob@example.com"
Declared by:
chad.user.homeDirectories
A list of desirect directories to be created in the home directory of the user. It is up to the user to provide the contents of these directories.
Type: list of string
Default:
[ ]
Example:
[
"Development/exercises"
"Development/presentations"
"Development/projects"
]
Declared by:
chad.user.name
User’s name.
Type: string
Example:
"bob"
Declared by:
Terminal Workspace (Zellij)
Enter Search
Switch to Scroll mode - Esc
Switch to Search mode - Enter
Normal
Switch to Pane mode - Ctrl a
Switch to Scroll mode - Ctrl s
Switch to Tab mode - Ctrl t
Pane
Close currently focused pane - x
Move focus to a pane to the left - j
Move focus to a pane to the left - h
Move focus to a pane to the right - l
Move focus to a pane to the left - k
Create a new pane - n
Toggle frames rendering for panes - z
Toggle fullscreen mode of the focused pane - f
Scroll
Scroll down by half a page - d
Scroll up by half a page - u
Scroll down by a single line - j
Scroll up by a single line - k
Switch to Enter Search mode - s
Search
Scroll down by half a page - d
Scroll up by half a page - u
Go to the next matched word - n
Go to the previous matched word - p
Toggle word match case sensitivity - c
Tab
Break the focused pane into a new tab - b
Close the current tab - x
Switch to tab under index of 1 - 1
Switch to tab under index of 2 - 2
Switch to tab under index of 3 - 3
Switch to tab under index of 4 - 4
Switch to tab under index of 5 - 5
Switch to tab under index of 6 - 6
Switch to tab under index of 7 - 7
Switch to tab under index of 8 - 8
Switch to tab under index of 9 - 9
Create a new tab - n
Switch between two most recently used tabs - Tab
Shared
Close currently focused pane - Alt x
Move focus to a pane to the left - Alt j
Move focus to a pane to the left - Alt h
Move focus to a pane to the right - Alt l
Move focus to a pane to the left - Alt k
Create a new pane - Alt n
Toggle frames rendering for panes - Alt z
Toggle fullscreen mode of the focused pane - Alt f
Editor (NeoVim)
Closing things
close the current buffer - <leader>xbc
Commenting things
add at the end of line - <leader>/lA
add line above - <leader>/lO
add line below - <leader>/lo
block operator-pending - <leader>/b
line operator-pending - <leader>/l
toggle block - <leader>/tb
toggle line - <leader>/tl
Debug code
toggle diagnostics window - <leader>dx
Finding things
code definitions - <leader>fcd
code implementations - <leader>fci
code references - <leader>fcr
code type definitions - <leader>fct
files - <leader>ff
Git branches - <leader>fgb
Git commits - <leader>fgc
Git local changes - <leader>fgl
Git stashed changes - <leader>fgs
implementations - <leader>fi
Vim buffers - <leader>fvb
Vim commands - <leader>fvc
Vim help topics - <leader>fvh
words across files - <leader>fw
Moving cursor to places
declaration - <leader>gD
definition - <leader>gd
implementation - <leader>gi
next problem - <leader>g]
previous problem - <leader>g[
Refactoring code
action - <leader>ra
format - <leader>rf
name - <leader>rn
Selecting text
decrement selection - <leader>sd
increment selection - <leader>si
initialize selection - <leader>ss
Miscellaneous
Cancel current selection or mode - <ESC>
Confirm current selection - <CR>
Move to window on the bottom - <C-j>
Move to window on the left - <C-h>
Move to window on the right - <C-l>
Move to window on the top - <C-k>
Scroll content down (half a page) - <C-d>
Scroll content down (full page) - <C-f>
Scroll content up (half a page) - <C-u>
Scroll content up (full page) - <C-b>
Select next item on a list - <C-n>
Select previous item on a list - <C-p>
Show key mappings - \
Show information about the symbol under the cursor - K
switch to next tab - <TAB>
switch to previous tab - <S-TAB>
For Developers
Flake inputs
Choosing version
Since this project uses flake-parts partitions module, flake inputs
are stored separately per each partition. This introduces possibility
of using different versions of inputs when evaluating different
flake output attributes. This is possible even when inputs share a
reference to the same branch. This is because commit revision is being
resolved and stored in the repo at the time of running nix flake lock
command, and this may happen at different times. In order to guarantee
that they share the same versions, use these rules:
- If the input repository uses tags - use them.
- If the input repository does not use tags - use commit hashes.
- For
nixpkgsuse commit hashes from the branch which is appropriate for this project, namelynixpkgs-{NIXOS_RELEASE_VERSION}-darwin. - For
home-manageruse commit hashes from the branch which corresponds to thenixpkgsversion, namelyrelease-${NIXOS_RELEASE_VERSION}. - For
nix-darwinuse commit hashes from the branch which corresponds to thenixpkgsversion, namelynix-darwin-${NIXOS_RELEASE_VERSION}. - For
nixvimuse commit hashes from the branch which corresponds to thenixpkgsversion, namelynixos-${NIXOS_RELEASE_VERSION}.
Control version of transitive dependencies
For each input of a flake type, identify its dependencies, define them
as this project's inputs and make them being used by the input with the
help of inputs.{NAME_OF_TRANSITIVE_INPUT}.follows property.
Chad Library
attribute sets
lib.attrsets.generate
Generate an attribute set from a list of values
Example
generate ["a" "b" "c"] (v: {"${v}1"=v;"${v}2"=v;})
=>
{a1="a";a2="a";b1="b";b2="b";c1="c";c2="c";}
Type
generate :: [Any] -> (Any -> AttrSet) -> AttrSet
Arguments
values : List of values
generator : A function transforming a single value into an attribute set
lib.attrsets.merge
Deep merge two attribute sets
Example
merge {a="a";c={c1="c1";}} {b="b";c={c2="c2";}}
=>
{a="a";b="b";c={c1="c1";c2="c2";}}
Type
merge :: AttrSet -> AttrSet -> AttrSet
Arguments
left : Left attribute set
right : Right attribute set
bash code generation helpers
lib.bash.catchErrorExec
Generate bash code which executes a sequence of commands and stores their standard output and return code in cmd_out and cmd_ret variables.
Example
catchErrorExec ["foo" "bar" "baz"]
=>
"set +e;cmd_out=$(foo bar baz 2>&1);cmd_ret=$?;set -e"
Type
catchErrorExec :: [String] -> String
Arguments
commands : List of commands to be executed
lib.bash.command
Generate bash code representing program invocation command
Example
command {flags=["foo"];parameters={bar="baz";};program="qux";}
=>
"qux --foo --bar baz"
Type
options :: AttrSet -> String
Arguments
config : Configuration including flags and parameters and program path
lib.bash.echoError
Generate bash code printing a message into standard error stream
Example
echoError "foo bar"
=>
"echo \"foo bar\" >&2"
Type
echoError :: String -> String
Arguments
message : Message to be printed
lib.bash.matchPattern
Generate bash code which matches a text against a pattern
Example
matchPattern {pattern="a([[:lower:]])c?";text="ab";}
=>
"[p \"ab\" =~ a([[:lower:]])c? ]]"
Type
echoError :: AttrSet -> String
Arguments
config : Configuration including pattern and text
lib.bash.options
Generate bash code representing command options
Example
options {flags=["foo"];parameters={bar="baz";};}
=>
"--foo --bar baz"
Type
options :: AttrSet -> String
Arguments
config : Configuration including flags and parameters
various constants
enumerations
functions
KDL file format utils
lib.kdl.key
Generate a key with given name and arguments
Example
key {name="foo";args=["bar" 123];}
=>
"foo \"bar\" 123"
Type
key :: AttrSet -> String
Arguments
config : Config containing name and arguments
lists manipulation
lua code generation helpers
markdown code generation helpers
nix CLI bash command generation helpers
macOS keyboard shortcuts configuration support
strings manipulation
lib.strings.camelToKebabCase
Convert camel-case string to kebab-case string
Example
camelToKebabCase "fooBar"
=>
"foo-bar"
Type
camelToKebabCase :: String -> String
Arguments
input : Input string
lib.strings.camelToSnakeCase
Convert camel-case string to snake-case string
Example
camelToSnakeCase "fooBar"
=>
"foo_bar"
Type
camelToSnakeCase :: String -> String
Arguments
input : Input string