Skip to content
Merged
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
106 changes: 104 additions & 2 deletions dev-shell/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ let
../ekaos/modules/languages/crystal.nix
../ekaos/modules/languages/cue.nix
../ekaos/modules/languages/deno.nix
../ekaos/modules/languages/dotnet.nix
../ekaos/modules/languages/elixir.nix
../ekaos/modules/languages/erlang.nix
../ekaos/modules/languages/fortran.nix
Expand All @@ -29,27 +30,34 @@ let
../ekaos/modules/languages/guile.nix
../ekaos/modules/languages/hare.nix
../ekaos/modules/languages/haskell.nix
../ekaos/modules/languages/idris.nix
../ekaos/modules/languages/java.nix
../ekaos/modules/languages/javascript.nix
../ekaos/modules/languages/jsonnet.nix
../ekaos/modules/languages/julia.nix
../ekaos/modules/languages/kotlin.nix
../ekaos/modules/languages/lean.nix
../ekaos/modules/languages/lobster.nix
../ekaos/modules/languages/lua.nix
../ekaos/modules/languages/nim.nix
../ekaos/modules/languages/nix.nix
../ekaos/modules/languages/nodejs.nix
../ekaos/modules/languages/ocaml.nix
../ekaos/modules/languages/odin.nix
../ekaos/modules/languages/opentofu.nix
../ekaos/modules/languages/perl.nix
../ekaos/modules/languages/php.nix
../ekaos/modules/languages/pkl.nix
../ekaos/modules/languages/purescript.nix
../ekaos/modules/languages/python.nix
../ekaos/modules/languages/r-lang.nix
../ekaos/modules/languages/racket.nix
../ekaos/modules/languages/raku.nix
../ekaos/modules/languages/ruby.nix
../ekaos/modules/languages/rust.nix
../ekaos/modules/languages/scala.nix
../ekaos/modules/languages/shell.nix
../ekaos/modules/languages/sml.nix
../ekaos/modules/languages/solidity.nix
../ekaos/modules/languages/tcl.nix
../ekaos/modules/languages/terraform.nix
Expand All @@ -58,6 +66,7 @@ let
../ekaos/modules/languages/typescript.nix
../ekaos/modules/languages/unison.nix
../ekaos/modules/languages/vala.nix
../ekaos/modules/languages/vlang.nix
../ekaos/modules/languages/zig.nix
];

Expand Down Expand Up @@ -94,6 +103,17 @@ let
};
};

# Devshell feature modules (dotenv, scripts, etc.)
devshellModuleFiles = [
./modules/dotenv.nix
./modules/enterShell.nix
./modules/env.nix
./modules/files.nix
./modules/packages.nix
./modules/scripts.nix
./modules/treefmt.nix
];

# Simple mkShell implementation (Phase 1 - basic version)
mkShell =
attrs:
Expand Down Expand Up @@ -165,13 +185,14 @@ in
inherit (processCompose) tui logDir dataDir;
};

# Evaluate language modules (check = false ignores service options)
# Evaluate language + devshell feature modules (check = false ignores service options)
languagesEval = lib.evalModules {
modules = [
{ _module.check = false; }
languageStubModule
]
++ languageModuleFiles
++ devshellModuleFiles
++ modules;
specialArgs = {
inherit lib pkgs;
Expand All @@ -182,6 +203,75 @@ in
langPackages = languagesEval.config.environment.packages;
langVariables = languagesEval.config.environment.variables;

# Extract devshell feature config
dotenvCfg = languagesEval.config.dotenv or { enable = false; };
scriptsCfg = languagesEval.config.scripts or { };
treefmtCfg = languagesEval.config.treefmt or { enable = false; };
enterShellCode = languagesEval.config.enterShell or "";
envVars = languagesEval.config.env or { };
modulePackages = languagesEval.config.packages or [ ];
filesCfg = languagesEval.config.files or { };

# Build script wrappers from scripts config
scriptPackages = lib.mapAttrsToList (name: body: pkgs.writeShellScriptBin name body) scriptsCfg;

# Extra packages from devshell features
featurePackages = lib.optional (treefmtCfg.enable or false) pkgs.treefmt;

# Dotenv loading shell code
dotenvShellHook =
let
files =
if builtins.isList (dotenvCfg.filename or ".env") then
dotenvCfg.filename
else
[ (dotenvCfg.filename or ".env") ];
loadFile = f: ''
if [ -f "${f}" ]; then
set -a
. "${f}"
set +a
fi
'';
in
lib.optionalString (dotenvCfg.enable or false) (lib.concatMapStringsSep "\n" loadFile files);

# User-defined env vars
envExports = lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: value: "export ${name}=${lib.escapeShellArg value}") envVars
);

# File generation shell code
filesShellHook =
let
enabledFiles = lib.filterAttrs (
_: cfg: cfg.text != null || cfg.json != null || cfg.toml != null
) filesCfg;
generateFile =
name: cfg:
let
content =
if cfg.text != null then
cfg.text
else if cfg.json != null then
builtins.toJSON cfg.json
else if cfg.toml != null then
(lib.generators.toTOML { } cfg.toml)
else
"";
mode = if cfg.executable then "755" else "644";
escapedContent = lib.escapeShellArg content;
in
''
mkdir -p "$(dirname "${name}")"
printf '%s\n' ${escapedContent} > "${name}"
chmod ${mode} "${name}"
'';
in
lib.optionalString (enabledFiles != { }) (
"# Generated files\n" + lib.concatStringsSep "" (lib.mapAttrsToList generateFile enabledFiles)
);

# Generate export statements for language environment variables
langExports = lib.concatStringsSep "\n" (
lib.mapAttrsToList (
Expand Down Expand Up @@ -248,6 +338,11 @@ in
trap _pc_cleanup EXIT
''}

${lib.optionalString (envVars != { }) envExports}
${filesShellHook}
${dotenvShellHook}
${enterShellCode}

# User's custom shellHook
${shellHook}
'';
Expand All @@ -257,7 +352,14 @@ in
shellArgs
// {
buildInputs =
buildInputs ++ packages ++ langPackages ++ [ processComposePackage ] ++ (lib.attrValues utilities);
buildInputs
++ packages
++ modulePackages
++ langPackages
++ featurePackages
++ scriptPackages
++ [ processComposePackage ]
++ (lib.attrValues utilities);

shellHook = enhancedShellHook;

Expand Down
18 changes: 18 additions & 0 deletions dev-shell/modules/dotenv.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# dotenv — load .env files into the shell environment
#
# Usage:
# dotenv.enable = true;
# dotenv.filename = ".env"; # or a list: [ ".env" ".env.local" ]
{ lib, ... }:

{
options.dotenv = {
enable = lib.mkEnableOption "loading .env files into the shell environment";

filename = lib.mkOption {
type = lib.types.either lib.types.str (lib.types.listOf lib.types.str);
default = ".env";
description = "Path to .env file(s) to load, relative to the project root.";
};
};
}
16 changes: 16 additions & 0 deletions dev-shell/modules/enterShell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# enterShell — bash code to run when entering the dev shell
#
# Usage:
# enterShell = ''
# echo "Welcome to the project!"
# export MY_VAR=foo
# '';
{ lib, ... }:

{
options.enterShell = lib.mkOption {
type = lib.types.lines;
default = "";
description = "Bash code to execute when entering the dev shell.";
};
}
17 changes: 17 additions & 0 deletions dev-shell/modules/env.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# env — environment variables for the dev shell
#
# Usage:
# env.DATABASE_URL = "postgres://localhost/mydb";
# env.RUST_LOG = "debug";
{ lib, ... }:

{
options.env = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = { };
description = "Environment variables to set in the dev shell.";
example = {
DATABASE_URL = "postgres://localhost/mydb";
};
};
}
44 changes: 44 additions & 0 deletions dev-shell/modules/files.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# files — generate config files in the project directory
#
# Usage:
# files."config.json".json = { key = "value"; };
# files.".prettierrc".text = ''{ "semi": false }'';
# files."setup.cfg".ini = { metadata = { name = "myproject"; }; };
{ lib, ... }:

let
fileSubmodule = {
options = {
text = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Text content for the file.";
};

json = lib.mkOption {
type = lib.types.nullOr lib.types.anything;
default = null;
description = "JSON value to serialize into the file.";
};

toml = lib.mkOption {
type = lib.types.nullOr lib.types.anything;
default = null;
description = "TOML value to serialize into the file.";
};

executable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether the file should be executable.";
};
};
};
in
{
options.files = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule fileSubmodule);
default = { };
description = "Files to generate in the project directory when entering the dev shell.";
};
}
13 changes: 13 additions & 0 deletions dev-shell/modules/packages.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# packages — extra packages for the dev shell (module-level)
#
# Usage in a module:
# packages = [ pkgs.ripgrep pkgs.jq ];
{ lib, ... }:

{
options.packages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
description = "Extra packages to include in the dev shell.";
};
}
18 changes: 18 additions & 0 deletions dev-shell/modules/scripts.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# scripts — define named shell scripts available in the dev shell
#
# Usage:
# scripts.hello = "echo hello world";
# scripts.build = "cargo build --release";
{ lib, ... }:

{
options.scripts = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = { };
description = "Named shell scripts to make available in the dev shell.";
example = {
build = "cargo build --release";
test = "cargo test";
};
};
}
11 changes: 11 additions & 0 deletions dev-shell/modules/treefmt.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# treefmt — one CLI to format the whole tree
#
# Usage:
# treefmt.enable = true;
{ lib, ... }:

{
options.treefmt = {
enable = lib.mkEnableOption "treefmt, a unified code formatter";
};
}
1 change: 0 additions & 1 deletion ekaos/modules/languages/erlang.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ let
name = "erlang";
defaultPackage = pkgs: pkgs.erlang;
resolveVersion = langLib.mkMajorVersionResolver "erlang";
defaultLspPackage = pkgs: pkgs.erlang-language-platform;
};
in

Expand Down
1 change: 0 additions & 1 deletion ekaos/modules/languages/go.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ let
mod = langLib.mkLanguageModule {
name = "go";
defaultPackage = pkgs: pkgs.go;
defaultLspPackage = pkgs: pkgs.gopls;
environmentVariables = _: {
GOPATH = "$HOME/go";
};
Expand Down
4 changes: 4 additions & 0 deletions ekaos/modules/languages/java.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Java programming language module
#
# Usage:
# languages.java.enable = true;
# languages.java.version = "21"; # optional: select specific version
{
config,
lib,
Expand Down
4 changes: 3 additions & 1 deletion ekaos/modules/languages/javascript.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# JavaScript programming language module
#
# Usage:
# languages.javascript.enable = true;
{
config,
lib,
Expand All @@ -11,7 +14,6 @@ let
mod = langLib.mkLanguageModule {
name = "javascript";
defaultPackage = pkgs: pkgs.nodejs;
defaultLspPackage = pkgs: pkgs.typescript-language-server;
resolveVersion = langLib.mkMajorVersionResolver "nodejs";
environmentVariables = _: {
NODE_PATH = "$HOME/.node_modules";
Expand Down
1 change: 0 additions & 1 deletion ekaos/modules/languages/kotlin.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ let
mod = langLib.mkLanguageModule {
name = "kotlin";
defaultPackage = pkgs: pkgs.kotlin;

};
in

Expand Down
1 change: 0 additions & 1 deletion ekaos/modules/languages/lua.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ let
mod = langLib.mkLanguageModule {
name = "lua";
defaultPackage = pkgs: pkgs.lua;
defaultLspPackage = pkgs: pkgs.lua-language-server;
};
in

Expand Down
Loading
Loading