Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .config/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake ../#nix
16 changes: 16 additions & 0 deletions .config/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
*
!language-nix
!.envrc
!.gitignore
!commitlintConfig.nix
!configVscode.nix
!importFromLanguageFolder.nix
!configZed.nix
!devShell.nix
!sanitizeProjectName.nix
!stubProject.nix
!CONTRIBUTE.md
!installGitHooks.nix
!lintCommit.nix
!recurse.nix
!getSemverTag.nix
37 changes: 37 additions & 0 deletions .config/CONTRIBUTE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
The .config folder contains all of the code needed to support projects of various languages

In this monorepo, we assume that each project is written in ONE language.

To add support for projects in a new language, create a `language-*/` folder containing:

```
language-go/
|
|-- .envrc # direnv integration: use flake ../../#go
|
|-- .gitignore # exclude everything except .nix files
|
|-- devShell.nix # project-lint, project-build, project-test commands
|
|-- configVscode.nix # LSP, formatter, extension settings for VSCode
|
|-- configZed.nix # LSP, formatter, extension settings for Zed
|
|-- stubProject.nix # script to scaffold new projects
|
'-- templateProject/ # files copied by stubProject.nix
```

Each nix expression points editors to nix-installed dev tools rather than
system-installed ones, ensuring consistent tooling across machines.

**Reference Documentation:**

| File | Documentation | Example |
| ------------------ | ------------------------------------------------------ | -------------------------------------------------------------- |
| `.envrc` | use `flake ../../#nix` | [language-nix/.envrc](language-nix/.envrc) |
| `.gitignore` | exclude all except `.nix` files | [language-nix/.gitignore](language-nix/.gitignore) |
| `devShell.nix` | see [devShell.nix](devShell.nix) lines 617-722 | [language-nix/devShell.nix](language-nix/devShell.nix) |
| `configVscode.nix` | see [configVscode.nix](configVscode.nix) lines 119-189 | [language-nix/configVscode.nix](language-nix/configVscode.nix) |
| `configZed.nix` | see [configZed.nix](configZed.nix) lines 146-213 | [language-nix/configZed.nix](language-nix/configZed.nix) |
| `stubProject.nix` | see [stubProject.nix](stubProject.nix) | [language-nix/stubProject.nix](language-nix/stubProject.nix) |
142 changes: 142 additions & 0 deletions .config/commitlintConfig.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# see: https://www.conventionalcommits.org/en/v1.0.0/#specification
# ___ ___ ________ ___ ___ ______________ _______
# \ \ \ \ / ___ '. \ \ __ | | |_____ ____/ ___ \
# \ \ \ \ \ \ \ \ \ \ | \ | | / / / / / /
# \ \___\ \ \ \ \ \ \ \ | \ | | / / / / / /
# \ ____ \ \ \ \ \ \ \' \' | / / / / / /
# \ \ \ \ \ \ \ \ \ | \ | / / / / / /
# \ \ \ \ \ '.___' \ \ | \ | / / / /___/ /
# \___\ \___\ '.________/ \___| \___| /___/ \________/
#
# _______ _______ ___ ___ ___ ___ ____________ _____________
# .' __ | .' ___ \ / | / | | \ | \ \____ ____\ ____ ____\
# / / '--' / / / / / | / | | \ | \ \ \ \ \
# / / / / / / / |/ /, | | \| \ \ \ \ \
# / / / / / / / /\ / | | | |\ /\ \ \ \ \ \
# / / __ / / / / / / \__/ | | | | \__/ \ \ \ \ \ \
# / '___/ / / '--' / / / | | | | \ \ .---' '---. \ \
# \_______.' \_______.' /___/ |___| |___| \___\ \___________\ \___\
#
#
# What are you going to be doing with your life in two years? Five years? A decade?
# You probably don't know for sure. Sit with that uncertainty for a second. That is
# exactly how the person maintaining your code in the future will feel when they have
# to fix a bug you introduced. They won't know why you wrote the code you did, unless
# you tell them. When they exclaim "Why would anyone ever write this? What on earth
# was this person thinking?!", your commit message should give them a compelling answer.
#
# We use a simplified version of conventional commit
#
# -,
# chore: inject global logger into main actor |- header
# --^-- --^--------------------------------- -'
# type header message
# -,
# * Mock the logger in tests |
# * Verify log calls |- body
# * Eliminate file I/O during test runs |
# -'
#
# Think of each commit as a step in a tutorial.
#
# When I review your PRs, I will step through each of your commits.
#
# Your commit message should read like an instruction, and it should describe what
# your code does. I should be able to follow your instruction, and write a different
# implementation of the same functionality
#
# When you submit a PR, Each commit must be independently buildable and testable.
#
{pkgs ? import <nixpkgs> {}}:
(pkgs.formats.yaml {}).generate "conf.yml" {
version = "v0.10.1";
formatter = "default";
rules = [
"header-min-length"
"header-max-length"
"body-max-line-length"
"footer-max-line-length"
"type-enum"
];
severity = {
default = "error";
};
settings = {
header-min-length = {
argument = 10;
};
header-max-length = {
argument = 50;
};
body-max-line-length = {
argument = 72;
};
footer-max-line-length = {
argument = 72;
};
type-enum = {
argument = [
# we only use 3 of the 11 available commit types. Why?
# Because code shouldn't be complicated. Asking a programmer
# to choose between 11 different commit types forces them to
# perform 50 subjective comparisons every. time. they. commit.
#
# Asking a programmer to choose between just 3 commit
# types makes them perform just 3 subjective comparisons
# for each commit. Here's when you should use each type
# of commit:
#
# your commit
# ,------------------|------------------,
# | | |
# feat fix chore
# -------^-------- -------^-------- -------^--------
# exports something fixes existing literally everything
# new. Adds to public API. else
# public API.
#
# Bumps major or Bumps patch
# minor version version number
# number

"feat" # New features that add functionality.

# "docs" # Documentation only changes.
# We do not use this, because you should update
# documentation in the same commit that you update
# code

"chore" # Regular maintenance tasks, no production code change.

# "style" # Changes that do not affect the meaning of the code
# (white-space, formatting, etc). We do not use this
# because you should NOT be changing the formatters.
#
# Doing so is a pet peeve of mine. Formatting changes
# shadow the git blame. They make it harder to understand
# who made a breaking change to the code, because a
# formatting change isn't a breaking change.

# "refactor" # Code changes that neither fix a bug nor add a feature.
# "perf" # Changes that improve performance.
# "test" # Adding missing tests or correcting existing tests.
# "build" # Changes that affect the build system or external dependencies.
# "ci" # Changes to CI configuration files and scripts.
#
# These are all just other names for chores

"fix" # Bug fixes and corrections. Try to avoid this.
# If you submit "fix" in a PR, I'm probably going to
# ask you to fixup your branch so that you don't need
# to commit the fix
#
# fix should only be used if we need to patch a production
# bug

#"revert" # Reverts a previous commit
# This is just another name for fix. Don't commit bugs in
# the first place and you'll have nothing to revert
];
};
};
}
161 changes: 161 additions & 0 deletions .config/configVscode.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
{
pkgs ? import <nixpkgs> {},
vscodeConfigs ? (import ./importFromLanguageFolder.nix {inherit pkgs;}).importConfigVscode,
}: let
validVscodeConfigs = builtins.map (vsc:
if
(builtins.isAttrs vsc)
&& (builtins.hasAttr "vscodeSettings" vsc)
&& (builtins.hasAttr "vscodeExtensions" vsc)
&& (builtins.hasAttr "vscodeLaunch" vsc)
&& (builtins.hasAttr "vscodeTasks" vsc)
then vsc
else builtins.throw "Invalid vscode configuration ${vsc}")
vscodeConfigs;
jsonFormatter = pkgs.formats.json {};
vscodeSettings = jsonFormatter.generate "settings.json" (
pkgs.lib.lists.fold (set: acc: pkgs.lib.attrsets.recursiveUpdate acc set) {} (builtins.map (vsc: vsc.vscodeSettings) validVscodeConfigs)
);
vscodeExtensions = jsonFormatter.generate "extensions.json" (
pkgs.lib.lists.fold (set: acc: pkgs.lib.attrsets.recursiveUpdate acc set) {} (builtins.map (vsc: vsc.vscodeExtensions) validVscodeConfigs)
);
vscodeLaunch = jsonFormatter.generate "launch.json" (
pkgs.lib.lists.fold (set: acc: pkgs.lib.attrsets.recursiveUpdate acc set) {} (builtins.map (vsc: vsc.vscodeLaunch) validVscodeConfigs)
);
vscodeTasks = jsonFormatter.generate "tasks.json" (
pkgs.lib.lists.fold (set: acc: pkgs.lib.attrsets.recursiveUpdate acc set) {} (builtins.map (vsc: vsc.vscodeTasks) validVscodeConfigs)
);
vscodeConfiguration = pkgs.stdenv.mkDerivation {
name = "vscodeConfiguration";
src = null;
phases = [
"buildPhase"
];
buildPhase = ''
mkdir -p $out
cd $out

ln -s ${vscodeSettings} settings.json
ln -s ${vscodeExtensions} extensions.json
ln -s ${vscodeLaunch} launch.json
ln -s ${vscodeTasks} tasks.json
'';
};
project-install-vscode-configuration = pkgs.writeShellApplication {
name = "project-install-vscode-configuration";
meta = {
description = "install .vscode/ configuration folder, if .vscode/ is not already present. Automatically run when this shell is opened.";
};
runtimeInputs = [pkgs.coreutils];
text = ''
if [ ! -d "./.git" ]; then
echo "please run this script from the root of the monorepo" >&2 && exit 1
fi

VSCODE_DIR=$(readlink -f "./.vscode")

if [ ! -e "./.vscode" ]; then
ln -s ${vscodeConfiguration} "./.vscode"
echo "✅ linked ${vscodeConfiguration} to ./.vscode" >&2
exit 0
fi

if [ "$VSCODE_DIR" = ${vscodeConfiguration} ]; then
echo "✅ vscode configuration already linked" >&2
exit 0
fi

if [ "$(dirname "$VSCODE_DIR")" = "$(dirname ${vscodeConfiguration})" ]; then
unlink "./.vscode"
ln -s ${vscodeConfiguration} "./.vscode"
echo "✅ vscode configuration updated" >&2
exit 0
fi

LINK_INSTEAD=$(basename ${vscodeConfiguration})

ln -s ${vscodeConfiguration} "./$LINK_INSTEAD"

echo "❌ cannot link vscode configuration because ./.vscode directory already exists." >&2
echo " Linking ${vscodeConfiguration} to ./$LINK_INSTEAD instead" >&2
echo " Please merge this configuration with your ./.vscode folder" >&2
'';
};
in
project-install-vscode-configuration
# HOW TO SET UP A LANGUAGE-SPECIFIC VSCODE CONFIGURATION
#
# Each language-specific folder contains a configVscode.nix. This
# nix file must contain the following nix expression:
#
# { pkgs ? import <nixpkgs> {} }: {
# vscodeSettings = {
# "some.setting" = true; # settings merged into settings.json
# "editor.formatOnSave" = true; # use exact VSCode setting keys
# "some.path" = "${pkgs.tool}/bin/t"; # nix store paths are supported
# };
# vscodeExtensions = {
# "recommendations" = [
# "publisher.extension-id" # extensions merged into extensions.json
# ];
# };
# vscodeLaunch = {
# "configurations" = [ # launch configs merged into launch.json
# {
# "type" = "node";
# "request" = "launch";
# "name" = "Debug Program";
# "program" = "\${workspaceFolder}/src/main.js";
# }
# ];
# };
# vscodeTasks = {
# "tasks" = [ # tasks merged into tasks.json
# {
# "label" = "build";
# "type" = "shell";
# "command" = "project-build";
# }
# ];
# };
# }
#
# this configVscode.nix merges the contents of all language-specific configVscode.nix:
#
# ________________________ ________________________
# / .vscode/ | / language-* |
# / settings.json | / configVscode.nix |
# | ----------------------- | | ----------------------- |
# | { | | vscodeSettings = { |
# | "nix.enable": true,<---- merged ------ "nix.enable" = true; |
# | "go.enable": true <---- from all ---- ... |
# | ... | langs | }; |
# | } | | |
# |_________________________| | vscodeExtensions = { |
# | "recommendations" = [ |
# ________________________ | "ext.id" |
# / .vscode/ | | ]; | |
# / extensions.json | | }; | |
# | ----------------------- | | | |
# | { | | vscodeLaunch = { ... }; |
# | "recommendations": [ | | | |
# | "ext.id" <--------- | -- merged -----------------' |
# | ] | | vscodeTasks = { ... }; |
# | } | |_________________________|
# |_________________________|
#
# The merge strategy uses Nix's // operator with recursiveUpdate,
# so later language configs can override earlier ones if keys conflict.
# Each attrset corresponds to a VSCode configuration file:
#
# vscodeSettings --> .vscode/settings.json
# vscodeExtensions --> .vscode/extensions.json
# vscodeLaunch --> .vscode/launch.json
# vscodeTasks --> .vscode/tasks.json
#
# See VSCode documentation:
# • settings.json: https://code.visualstudio.com/docs/getstarted/settings
# • extensions.json: https://code.visualstudio.com/docs/editor/extension-marketplace#_workspace-recommended-extensions
# • launch.json: https://code.visualstudio.com/docs/editor/debugging#_launch-configurations
# • tasks.json: https://code.visualstudio.com/docs/editor/tasks

Loading