diff options
| author | brustybee <bee@4d2.org> | 2026-03-19 23:43:21 +0530 |
|---|---|---|
| committer | brustybee <bee@4d2.org> | 2026-03-19 23:43:21 +0530 |
| commit | 9d2256adddbb830d33119a5e01e3fad6b4b0652b (patch) | |
| tree | 958e1de443a6d59a9b09716ba5815c52bfb7bfb3 /common/templates | |
| parent | f9142a5822a4f212a3031b932cbf51b2d50344a8 (diff) | |
add flake templates
Diffstat (limited to 'common/templates')
30 files changed, 961 insertions, 0 deletions
diff --git a/common/templates/clang/.envrc b/common/templates/clang/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/common/templates/clang/.envrc @@ -0,0 +1 @@ +use flake diff --git a/common/templates/clang/.gitignore b/common/templates/clang/.gitignore new file mode 100644 index 0000000..030089a --- /dev/null +++ b/common/templates/clang/.gitignore @@ -0,0 +1,58 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# debug information files +*.dwo + +.direnv +result diff --git a/common/templates/clang/build.zig b/common/templates/clang/build.zig new file mode 100644 index 0000000..2953ab7 --- /dev/null +++ b/common/templates/clang/build.zig @@ -0,0 +1,66 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "hello-c", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + }), + }); + + // 1. Link the C standard library + exe.linkLibC(); + + // 2. Add your C source files + exe.addCSourceFile(.{ + .file = b.path("src/main.c"), + .flags = &.{ "-Wall", "-Wextra", "-O2" }, + }); + + // 3. Declare intent for the executable to be installed + b.installArtifact(exe); + + // 4. Create the 'run' step + const run_step = b.step("run", "Run the app"); + const run_cmd = b.addRunArtifact(exe); + + run_step.dependOn(&run_cmd.step); + run_cmd.step.dependOn(b.getInstallStep()); + + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // --- 5. Support Testing --- + // This creates an executable that runs 'test' blocks in src/test.zig + const exe_unit_tests = b.addTest(.{ + .root_module = b.createModule(.{ + .root_source_file = b.path("src/test.zig"), + .target = target, + .optimize = optimize, + }), + }); + + // This exposes our Zig exported functions to the Linux + // dynamic symbol table so dlsym() can actually find them. + exe_unit_tests.rdynamic = true; + + exe_unit_tests.addCSourceFile(.{ + .file = b.path("src/main.c"), + .flags = &.{ "-Wall", "-Wextra", "-pedantic", "-Dmain=nomain" }, + }); + + // Allow tests to link against C and find your headers + exe_unit_tests.linkLibC(); + exe_unit_tests.addIncludePath(b.path("src")); + + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_exe_unit_tests.step); +} + diff --git a/common/templates/clang/flake.nix b/common/templates/clang/flake.nix new file mode 100644 index 0000000..a3dfd01 --- /dev/null +++ b/common/templates/clang/flake.nix @@ -0,0 +1,46 @@ +{ + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = + { self, nixpkgs, ... }: + let + inherit (nixpkgs) lib; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; + pname = "hello-c"; + in + { + packages = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.stdenv.mkDerivation { + inherit pname; + version = "0.1.0"; + src = self; + + # The zig hook handles the build AND the install automatically + nativeBuildInputs = [ pkgs.zig.hook ]; + doCheck = true; + }; + } + ); + + devShells = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.mkShellNoCC { + packages = [ + pkgs.zig + pkgs.zls + pkgs.clang-tools + ]; + }; + } + ); + }; +} diff --git a/common/templates/clang/src/main.c b/common/templates/clang/src/main.c new file mode 100644 index 0000000..5bda38b --- /dev/null +++ b/common/templates/clang/src/main.c @@ -0,0 +1,51 @@ +#define _GNU_SOURCE // Required to unlock RTLD_DEFAULT so we can search all loaded memory +#include <ctype.h> +#include <dlfcn.h> // Gives us dlsym() to look up memory addresses by string names +#include <stddef.h> + +void hello_world(const char* action) { + // __func__ is secretly injected by the compiler and holds the string "hello_world". + // We use raw pointers here (src and dst) instead of array indices because + // stepping the memory address forward directly (*dst++) generates faster machine code. + const char* src = __func__; + char result[64]; + char* dst = result; + int capitalize = 1; + + // We walk the 'src' pointer forward until we hit the null terminator. + // The (dst - result) < 60 check guarantees we never write past the end of + // our 64-byte array, preventing stack smashing if the function name is unusually long. + while (*src && (dst - result) < 60) { + if (*src == '_') { + *dst++ = ' '; + capitalize = 1; + } else { + *dst++ = capitalize ? toupper(*src) : *src; + capitalize = 0; + } + src++; + } + + // Cap off the string with a bang and the required null terminator + *dst++ = '!'; + *dst++ = '\n'; + *dst = '\0'; + + // Declare a function pointer that takes a format string and variadic arguments + int (*dynamic_eval)(const char*, ...); + + // This looks unhinged, but it is the official POSIX-compliant way to use dlsym. + // ISO C strictly forbids casting a raw data pointer (void*) directly to a + // function pointer. To bypass the compiler warning, we take the address of our + // function pointer, cast THAT to a void**, and dereference it to write the address. + *(void **)(&dynamic_eval) = dlsym(RTLD_DEFAULT, action); + + if (dynamic_eval) { + dynamic_eval("%s", result); + } +} + +int main(void) { + hello_world("printf"); + return 0; +} diff --git a/common/templates/clang/src/test.zig b/common/templates/clang/src/test.zig new file mode 100644 index 0000000..49ff4d0 --- /dev/null +++ b/common/templates/clang/src/test.zig @@ -0,0 +1,37 @@ +const std = @import("std"); + +extern fn hello_world(action: [*c]const u8) void; + +// We use global static memory for our trap. +// Because this test runs in a single thread and we know the string is tiny, +var captured_output: [64]u8 = undefined; +var captured_len: usize = 0; + +// Exported to the dynamic symbol table so dlsym() can find it. +// Signature must accept two pointers to perfectly map to the +// System V ABI hardware registers used by: dynamic_eval("%s", result); +// CPU registers (RDI and RSI) that the C code will use when calling this via variadic arguments. +export fn test_capture_sink(fmt: [*c]const u8, msg: [*c]const u8) void { + // We intentionally ignore the format string ("%s") sitting in the first register + _ = fmt; + + // std.mem.span walks the raw C pointer until it finds the \0 null terminator. + // It doesn't allocate memory; it just calculates the length so we have a safe Zig slice. + const slice = std.mem.span(msg); + + // Copy the raw bytes directly from the C memory space into our static Zig buffer. + @memcpy(captured_output[0..slice.len], slice); + captured_len = slice.len; +} + +test "catfish dlsym eval" { + // We hand our C code the name of our exported Zig function. + // The C code will parse its own __func__, ask the OS to find "test_capture_sink", + // and execute it, throwing the parsed string right back into our global variables. + hello_world("test_capture_sink"); + + // Reconstruct a strict Zig string from the exact number of bytes we captured + const result = captured_output[0..captured_len]; + + try std.testing.expectEqualStrings("Hello World!\n", result); +} diff --git a/common/templates/default.nix b/common/templates/default.nix new file mode 100644 index 0000000..ce06868 --- /dev/null +++ b/common/templates/default.nix @@ -0,0 +1,17 @@ +inputs: { + c = { + path = ./clang; + }; + rust = { + path = ./rust; + }; + zig = { + path = ./zig; + }; + go = { + path = ./go; + }; + python = { + path = ./python; + }; +} diff --git a/common/templates/go/.envrc b/common/templates/go/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/common/templates/go/.envrc @@ -0,0 +1 @@ +use flake diff --git a/common/templates/go/.gitignore b/common/templates/go/.gitignore new file mode 100644 index 0000000..9c1605b --- /dev/null +++ b/common/templates/go/.gitignore @@ -0,0 +1,36 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Code coverage profiles and other test artifacts +*.out +coverage.* +*.coverprofile +profile.cov + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env +.direnv + +#nix +result + +# Editor/IDE +# .idea/ +# .vscode/ diff --git a/common/templates/go/flake.nix b/common/templates/go/flake.nix new file mode 100644 index 0000000..3f8e7d5 --- /dev/null +++ b/common/templates/go/flake.nix @@ -0,0 +1,49 @@ +{ + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = + { + self, + nixpkgs, + ... + }: + let + inherit (nixpkgs) lib; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; + in + { + packages = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.buildGoModule { + pname = "hello_go"; + version = "0.0.1"; + src = self; + + # The "Trust but Verify" hash. + vendorHash = null; + }; + } + ); + + devShells = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.mkShellNoCC { + packages = with pkgs; [ + go + gopls + gotools + go-tools + ]; + }; + } + ); + }; +} diff --git a/common/templates/go/go.mod b/common/templates/go/go.mod new file mode 100644 index 0000000..24673a6 --- /dev/null +++ b/common/templates/go/go.mod @@ -0,0 +1,4 @@ +module hello_go + +go 1.25.5 + diff --git a/common/templates/go/main.go b/common/templates/go/main.go new file mode 100644 index 0000000..d895205 --- /dev/null +++ b/common/templates/go/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "runtime" + "strings" + "unicode" +) + +func hello_world(action string) { + // 1. Get the Program Counter (PC) of the current function + pc, _, _, _ := runtime.Caller(0) + + // 2. Get the full function name (e.g., "main.hello_world") + fullFuncName := runtime.FuncForPC(pc).Name() + + // 3. Strip the package path to get just "hello_world" + // Splits "main.hello_world" and takes the last part + parts := strings.Split(fullFuncName, ".") + funcName := parts[len(parts)-1] + + // 4. Split into words: "hello", "world" + words := strings.Split(funcName, "_") + + // 5. Capitalize each word: "Hello", "World" + for i, w := range words { + runes := []rune(w) + runes[0] = unicode.ToUpper(runes[0]) + words[i] = string(runes) + } + + // 6. Join with ", " and add "!" -> "Hello, World!" + finalString := strings.Join(words, ", ") + "!" + + // 7. Execute the action + if action == "print" { + fmt.Println(finalString) + } +} + +func main() { + hello_world("print") +} diff --git a/common/templates/python/.envrc b/common/templates/python/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/common/templates/python/.envrc @@ -0,0 +1 @@ +use flake diff --git a/common/templates/python/.gitignore b/common/templates/python/.gitignore new file mode 100644 index 0000000..f51634e --- /dev/null +++ b/common/templates/python/.gitignore @@ -0,0 +1,219 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +# Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +# poetry.lock +# poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +# pdm.lock +# pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +# pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# Redis +*.rdb +*.aof +*.pid + +# RabbitMQ +mnesia/ +rabbitmq/ +rabbitmq-data/ + +# ActiveMQ +activemq-data/ + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +# .idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# Streamlit +.streamlit/secrets.toml + +#nix +.direnv +result diff --git a/common/templates/python/flake.nix b/common/templates/python/flake.nix new file mode 100644 index 0000000..e773850 --- /dev/null +++ b/common/templates/python/flake.nix @@ -0,0 +1,98 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + pyproject-nix = { + url = "github:pyproject-nix/pyproject.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + uv2nix = { + url = "github:pyproject-nix/uv2nix"; + inputs.pyproject-nix.follows = "pyproject-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + pyproject-build-systems = { + url = "github:pyproject-nix/build-system-pkgs"; + inputs.pyproject-nix.follows = "pyproject-nix"; + inputs.uv2nix.follows = "uv2nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { + nixpkgs, + pyproject-nix, + uv2nix, + pyproject-build-systems, + ... + }: + let + inherit (nixpkgs) lib; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; + + workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; + + overlay = workspace.mkPyprojectOverlay { + sourcePreference = "wheel"; + }; + + editableOverlay = workspace.mkEditablePyprojectOverlay { + root = "$REPO_ROOT"; + }; + packageName = "hello_world"; + + pythonSets = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + python = pkgs.python3; + in + (pkgs.callPackage pyproject-nix.build.packages { + inherit python; + }).overrideScope + ( + lib.composeManyExtensions [ + pyproject-build-systems.overlays.wheel + overlay + ] + ) + ); + + in + { + devShells = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + pythonSet = pythonSets.${system}.overrideScope editableOverlay; + virtualenv = pythonSet.mkVirtualEnv "${packageName}-dev-env" workspace.deps.all; + in + { + default = pkgs.mkShellNoCC { + packages = [ + virtualenv + pkgs.uv + pkgs.pyrefly + pkgs.ruff + ]; + env = { + UV_NO_SYNC = "1"; + UV_PYTHON = pythonSet.python.interpreter; + UV_PYTHON_DOWNLOADS = "never"; + }; + shellHook = '' + unset PYTHONPATH + export REPO_ROOT=$(git rev-parse --show-toplevel) + ''; + }; + } + ); + + packages = forAllSystems (system: { + default = pythonSets.${system}.mkVirtualEnv packageName workspace.deps.default; + }); + }; +} diff --git a/common/templates/python/pyproject.toml b/common/templates/python/pyproject.toml new file mode 100644 index 0000000..5892765 --- /dev/null +++ b/common/templates/python/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "hello-world" +version = "0.1.0" +description = "Add your description here" +requires-python = ">=3.12" +dependencies = [] + +[project.scripts] +hello_world = "hello_world.main:main" + +[build-system] +requires = ["uv_build>=0.10.0,<0.11.0"] +build-backend = "uv_build" + +[tool.pyrefly] +project-includes = [ + "**/*.py*", + "**/*.ipynb", +] diff --git a/common/templates/python/src/hello_world/__init__.py b/common/templates/python/src/hello_world/__init__.py new file mode 100644 index 0000000..402c976 --- /dev/null +++ b/common/templates/python/src/hello_world/__init__.py @@ -0,0 +1,3 @@ +def hello_world(action: str): + result = [*hello_world.__name__.split("_")] + eval(action)(" ".join(result).title() + "!\n") diff --git a/common/templates/python/src/hello_world/main.py b/common/templates/python/src/hello_world/main.py new file mode 100644 index 0000000..71ad102 --- /dev/null +++ b/common/templates/python/src/hello_world/main.py @@ -0,0 +1,6 @@ +from hello_world import hello_world + + +def main(): + hello_world("print") + diff --git a/common/templates/python/uv.lock b/common/templates/python/uv.lock new file mode 100644 index 0000000..6fa00de --- /dev/null +++ b/common/templates/python/uv.lock @@ -0,0 +1,8 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "hello-world" +version = "0.1.0" +source = { editable = "." } diff --git a/common/templates/rust/.envrc b/common/templates/rust/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/common/templates/rust/.envrc @@ -0,0 +1 @@ +use flake diff --git a/common/templates/rust/.gitignore b/common/templates/rust/.gitignore new file mode 100644 index 0000000..e8cf9a0 --- /dev/null +++ b/common/templates/rust/.gitignore @@ -0,0 +1,29 @@ +# Generated by Cargo +# will have compiled files and executables +debug +target + +.direnv + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Generated by cargo mutants +# Contains mutation testing data +**/mutants.out*/ + +# RustRover +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + + +# Added by cargo + +/target + diff --git a/common/templates/rust/Cargo.lock b/common/templates/rust/Cargo.lock new file mode 100644 index 0000000..c87dd44 --- /dev/null +++ b/common/templates/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "rust-project" +version = "0.1.0" diff --git a/common/templates/rust/Cargo.toml b/common/templates/rust/Cargo.toml new file mode 100644 index 0000000..5ab6a6c --- /dev/null +++ b/common/templates/rust/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rust-project" +version = "0.1.0" +edition = "2024" +description = """ +my rust project +""" +repository = "" +license = "" + +[workspace] +members = [] + +[dependencies] diff --git a/common/templates/rust/flake.nix b/common/templates/rust/flake.nix new file mode 100644 index 0000000..afe2601 --- /dev/null +++ b/common/templates/rust/flake.nix @@ -0,0 +1,50 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + naersk.url = "github:nix-community/naersk"; + naersk.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = + { + self, + nixpkgs, + naersk, + ... + }: + let + inherit (nixpkgs) lib; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; + in + { + devShells = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + cargo + clippy + rustc + rustfmt + rust-analyzer + ]; + RUST_SRC_PATH = pkgs.rustPlatform.rustLibSrc; + }; + } + ); + + packages = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + naersk-lib = pkgs.callPackage naersk { }; + in + { + default = naersk-lib.buildPackage self; + } + ); + }; +} diff --git a/common/templates/rust/src/lib.rs b/common/templates/rust/src/lib.rs new file mode 100644 index 0000000..ee5d017 --- /dev/null +++ b/common/templates/rust/src/lib.rs @@ -0,0 +1,33 @@ +use std::any::type_name; + +pub fn hello_world(action: &str) { + // Every function in Rust has a unique, unnameable type. + // we define a tiny helper to extract that type's name. + fn get_type_name<T>(_: T) -> &'static str { + type_name::<T>() + } + + // This gives us "current_crate::hello_world" + let full_path = get_type_name(hello_world); + + // We transform the string entirely through a lazy iterator pipeline. + let formatted: String = full_path + .split("::") + .last() + .unwrap_or("") + .split('_') + .map(|word| { + // Capitalize the first letter and chain the rest + let mut chars = word.chars(); + chars + .next() + .map(|f| f.to_uppercase().collect::<String>() + chars.as_str()) + .unwrap_or_default() + }) + .collect::<Vec<_>>() + .join(", ") + + "!"; + + println!("{}", formatted) +} + diff --git a/common/templates/rust/src/main.rs b/common/templates/rust/src/main.rs new file mode 100644 index 0000000..629b4b1 --- /dev/null +++ b/common/templates/rust/src/main.rs @@ -0,0 +1,6 @@ +use rust_project::hello_world; + +fn main() { + hello_world("print"); +} + diff --git a/common/templates/zig/.envrc b/common/templates/zig/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/common/templates/zig/.envrc @@ -0,0 +1 @@ +use flake diff --git a/common/templates/zig/.gitignore b/common/templates/zig/.gitignore new file mode 100644 index 0000000..f55821a --- /dev/null +++ b/common/templates/zig/.gitignore @@ -0,0 +1,6 @@ +.direnv +.zig-cache/ +zig-out/ +result +*.o + diff --git a/common/templates/zig/flake.nix b/common/templates/zig/flake.nix new file mode 100644 index 0000000..26bb8f1 --- /dev/null +++ b/common/templates/zig/flake.nix @@ -0,0 +1,46 @@ +{ + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = + { + self, + nixpkgs, + ... + }: + let + inherit (nixpkgs) lib; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; + in + { + packages = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.stdenv.mkDerivation { + pname = "hello_zig"; + version = "0.1.0"; + src = self; + + nativeBuildInputs = [ pkgs.zig.hook ]; + }; + } + ); + + devShells = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.mkShellNoCC { + packages = [ + pkgs.zig + pkgs.zls + ]; + }; + } + ); + }; +} diff --git a/common/templates/zig/src/main.zig b/common/templates/zig/src/main.zig new file mode 100644 index 0000000..3b2b910 --- /dev/null +++ b/common/templates/zig/src/main.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub fn main() !void { + try std.fs.File.stdout().writeAll("Hello, World!\n"); +} |
