From 1333a608b8ab3ca2a068524dc0b7c6e19836b209 Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Fri, 19 Jun 2026 15:12:05 -0500 Subject: [PATCH] feat: global no-color CLI support --- README.md | 19 ++- crates/cli/src/args.rs | 5 + crates/cli/src/commands.rs | 15 +- crates/cli/src/echo.rs | 39 ++++- crates/cli/src/lib.rs | 4 +- crates/cli/tests/build.rs | 91 ++++++++++++ crates/core/src/diagnostic.rs | 4 +- docs/internal/README.md | 7 +- .../specs/17_cli_and_build_outputs.md | 89 ----------- .../tasks/17_cli_and_build_outputs.md | 68 --------- docs/website/changelog.md | 22 ++- docs/website/guide/usage/cli.md | 138 ++++++++++++++++-- 12 files changed, 304 insertions(+), 197 deletions(-) delete mode 100644 docs/internal/specs/17_cli_and_build_outputs.md delete mode 100644 docs/internal/tasks/17_cli_and_build_outputs.md diff --git a/README.md b/README.md index 61ac5dc..f1530b0 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,8 @@ that each layer can be tested and explained. | Standard library | Selected modules and intrinsics | | Whole-project linked output | Supported subset | | Dependency source loading | Selected Hex and path packages | -| Browser, Node.js, and WASI ABIs | Incomplete | +| Browser, bundler, and Node.js | Supported adapter subset | +| WASI ABI | Incomplete | ### Working today @@ -50,12 +51,17 @@ that each layer can be tested and explained. - [x] Lower the supported subset to core IR - [x] Emit deterministic `.wasm` - [x] Render optional WAT -- [x] Run scalar and managed-value exports in Wasmtime tests +- [x] Run scalar and managed-value exports with Wasmtime - [x] Load `gleam.toml` and discover project modules - [x] Compile supported projects into linked Wasm output - [x] Load selected Hex and path dependency sources - [x] Lower supported externals to Wasm imports - [x] Validate target-aware host imports +- [x] Emit deterministic browser, bundler, and Node.js `.mjs` adapters +- [x] Emit optional AST, resolved, typed, IR, runtime, and ABI debug artifacts +- [x] Render source diagnostics with snippets, labels, notes, and stable + project ordering +- [x] Keep normal CLI output concise, with `--no-color` and `NO_COLOR` support ### Supported Gleam surface @@ -80,15 +86,18 @@ that each layer can be tested and explained. values - [x] Branches, comparisons, equality, pattern checks, and failure paths - [x] Selected runtime helpers and stdlib intrinsics +- [x] Checked runtime helper fragments before final module output ### Not yet implemented - [ ] Compile every valid Gleam project shape - [ ] Compile broad dependency source modules without subset limits -- [ ] Compile the full Gleam standard library from source -- [ ] Provide complete browser, bundler, and Node.js host ABIs +- [ ] Compile the full published `gleam_stdlib` package without registry shims +- [ ] Provide complete browser, bundler, and Node.js host APIs beyond the + current adapter subset - [ ] Provide complete WASI adapters -- [ ] Add garbage collection, reference counting, or heap growth checks +- [ ] Add garbage collection or reference counting for long-lived managed + values For more detail, see the case-study book in [docs/book](./docs/book/src/introduction.md) and the user/development docs in diff --git a/crates/cli/src/args.rs b/crates/cli/src/args.rs index dbcc25d..cd2082b 100644 --- a/crates/cli/src/args.rs +++ b/crates/cli/src/args.rs @@ -6,6 +6,11 @@ use compiler_core::target::CompileTarget; #[derive(Debug, Parser)] #[command(about = "Compile Gleam source to WebAssembly")] pub struct Args { + /// Disable ANSI colors in human-readable output. + /// + /// This is also enabled when the NO_COLOR environment variable is set. + #[arg(long, global = true)] + pub no_color: bool, #[command(subcommand)] pub command: Command, } diff --git a/crates/cli/src/commands.rs b/crates/cli/src/commands.rs index 622e9c1..24fde92 100644 --- a/crates/cli/src/commands.rs +++ b/crates/cli/src/commands.rs @@ -46,7 +46,7 @@ impl CompiledModule { } } -pub fn run(command: Command) -> ExitCode { +pub fn run(command: Command, no_color: bool) -> ExitCode { match command { Command::Build { project, output, out_dir, target, emit, wat, dump_dir, verbose, json } => { let mut builder = @@ -61,30 +61,31 @@ pub fn run(command: Command) -> ExitCode { Command::Run { input, function, args, target, verbose, json } => { Runner::new(&input, &function, &args, target, verbose, json).run() } - Command::Debug { view, input, tree_sitter, ast, spans, json, no_color } => run_debug( + Command::Debug { view, input, tree_sitter, ast, spans, json, no_color: debug_no_color } => run_debug( view, input.as_deref(), - DebugOptions::new(tree_sitter, ast, spans, json, no_color), + DebugOptions::new(tree_sitter, ast, spans, json, no_color || debug_no_color), + no_color, ), Command::List { project } => list(project.as_deref().unwrap_or_else(|| Path::new("."))), } } -fn run_debug(view: Option, input: Option<&Path>, opts: DebugOptions) -> ExitCode { +fn run_debug(view: Option, input: Option<&Path>, opts: DebugOptions, no_color: bool) -> ExitCode { match view { Some(DebugCommand::Ts(args)) => Debugger::new( &args.input, - DebugOptions::new(true, false, false, args.json, args.no_color), + DebugOptions::new(true, false, false, args.json, no_color || args.no_color), ) .run(), Some(DebugCommand::Spans(args)) => Debugger::new( &args.input, - DebugOptions::new(true, false, true, args.json, args.no_color), + DebugOptions::new(true, false, true, args.json, no_color || args.no_color), ) .run(), Some(DebugCommand::Ast(args)) => Debugger::new( &args.input, - DebugOptions::new(false, true, false, args.json, args.no_color), + DebugOptions::new(false, true, false, args.json, no_color || args.no_color), ) .run(), Some(DebugCommand::Json(args)) => Debugger::new( diff --git a/crates/cli/src/echo.rs b/crates/cli/src/echo.rs index 82748dd..a55e33f 100644 --- a/crates/cli/src/echo.rs +++ b/crates/cli/src/echo.rs @@ -1,11 +1,40 @@ +use std::sync::atomic::{AtomicBool, Ordering}; use std::{fmt::Display, process::ExitCode}; use compiler_core::diagnostic::{Diagnostic, Diagnostics}; use compiler_core::source::{SourceFile, Span}; use owo_colors::OwoColorize; +static COLOR_ENABLED: AtomicBool = AtomicBool::new(true); + +pub fn set_color_enabled(enabled: bool) { + COLOR_ENABLED.store(enabled, Ordering::Relaxed); +} + +fn color_enabled() -> bool { + COLOR_ENABLED.load(Ordering::Relaxed) +} + +fn styled_label(label: &str, style: LabelStyle) -> String { + if !color_enabled() { + return label.to_string(); + } + match style { + LabelStyle::Status => label.bright_magenta().bold().to_string(), + LabelStyle::Error => label.bright_red().bold().to_string(), + LabelStyle::Diagnostic => label.bright_yellow().bold().to_string(), + } +} + +#[derive(Clone, Copy)] +enum LabelStyle { + Status, + Error, + Diagnostic, +} + pub fn status(label: &str, message: impl AsRef) { - eprintln!("{} {}", label.bright_magenta().bold(), message.as_ref()); + eprintln!("{} {}", styled_label(label, LabelStyle::Status), message.as_ref()); } pub fn progress(message: impl AsRef) { @@ -13,7 +42,7 @@ pub fn progress(message: impl AsRef) { } pub fn error(message: impl AsRef) { - eprintln!("{} {}", "error".bright_red().bold(), message.as_ref()); + eprintln!("{} {}", styled_label("error", LabelStyle::Error), message.as_ref()); } pub fn fail(action: &str, subject: impl Display, cause: impl Display) -> ExitCode { @@ -36,7 +65,11 @@ pub fn fail_with_source_diagnostics( } pub fn diagnostic(message: impl AsRef) { - eprintln!("{} {}", "diagnostic".bright_yellow().bold(), message.as_ref()); + eprintln!( + "{} {}", + styled_label("diagnostic", LabelStyle::Diagnostic), + message.as_ref() + ); } pub fn diagnostics(diagnostics: &Diagnostics) { diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 52668df..744af81 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -6,5 +6,7 @@ use clap::Parser; pub fn run() -> std::process::ExitCode { let args = args::Args::parse(); - commands::run(args.command) + let no_color = args.no_color || std::env::var_os("NO_COLOR").is_some(); + echo::set_color_enabled(!no_color); + commands::run(args.command, no_color) } diff --git a/crates/cli/tests/build.rs b/crates/cli/tests/build.rs index 247e879..e51fdbc 100644 --- a/crates/cli/tests/build.rs +++ b/crates/cli/tests/build.rs @@ -46,6 +46,97 @@ fn builds_working_examples() { } } +#[test] +fn global_no_color_disables_status_ansi_output() { + let out_dir = unique_temp_dir("regulus_cli_no_color_build"); + fs::create_dir_all(&out_dir).expect("create output dir"); + + let output = Command::new(env!("CARGO_BIN_EXE_reggie")) + .current_dir(workspace_root()) + .arg("--no-color") + .arg("build") + .arg("examples/scalar_project") + .arg("--out-dir") + .arg(&out_dir) + .output() + .expect("run reggie build"); + + assert!( + output.status.success(), + "build failed\nstdout:\n{}\nstderr:\n{}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!(stderr.contains("wasm "), "missing status output:\n{stderr}"); + assert!( + !stderr.contains("\u{1b}["), + "--no-color should disable status ANSI codes: {stderr:?}" + ); + + let _ = fs::remove_dir_all(out_dir); +} + +#[test] +fn global_no_color_is_accepted_after_subcommand() { + let output = Command::new(env!("CARGO_BIN_EXE_reggie")) + .current_dir(workspace_root()) + .arg("list") + .arg("examples/multi_module_project") + .arg("--no-color") + .output() + .expect("run reggie list"); + + assert!( + output.status.success(), + "list failed\nstdout:\n{}\nstderr:\n{}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + stderr.contains("project multi_module_project"), + "missing project output:\n{stderr}" + ); + assert!( + !stderr.contains("\u{1b}["), + "--no-color should disable list ANSI codes: {stderr:?}" + ); +} + +#[test] +fn no_color_environment_disables_diagnostic_ansi_output() { + let out_dir = unique_temp_dir("regulus_cli_no_color_env"); + fs::create_dir_all(&out_dir).expect("create output dir"); + + let output = Command::new(env!("CARGO_BIN_EXE_reggie")) + .current_dir(workspace_root()) + .env("NO_COLOR", "1") + .arg("build") + .arg("examples/diagnostics/duplicate_modules") + .arg("--out-dir") + .arg(&out_dir) + .output() + .expect("run reggie build"); + + assert!(!output.status.success(), "diagnostic example should fail"); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + stderr.contains("error could not load project"), + "missing error output:\n{stderr}" + ); + assert!( + stderr.contains("diagnostic ProjectError"), + "missing diagnostic output:\n{stderr}" + ); + assert!( + !stderr.contains("\u{1b}["), + "NO_COLOR should disable diagnostic ANSI codes: {stderr:?}" + ); + + let _ = fs::remove_dir_all(out_dir); +} + #[test] fn snapshots_diagnostic_example() { let out_dir = unique_temp_dir("regulus_cli_example_diagnostic"); diff --git a/crates/core/src/diagnostic.rs b/crates/core/src/diagnostic.rs index 970f8f4..826518f 100644 --- a/crates/core/src/diagnostic.rs +++ b/crates/core/src/diagnostic.rs @@ -47,9 +47,9 @@ impl Diagnostic { } pub fn expected_found( - code: DiagnosticCode, got: impl Display, want: impl Display, span: Span, label: impl Into, + code: DiagnosticCode, expected: impl Display, actual: impl Display, span: Span, label: impl Into, ) -> Self { - Self::spanned(code, format!("expected `{got}` but found `{want}`"), span, label) + Self::spanned(code, format!("expected `{expected}` but found `{actual}`"), span, label) } pub fn duplicate( diff --git a/docs/internal/README.md b/docs/internal/README.md index 5d36cab..6376bdd 100644 --- a/docs/internal/README.md +++ b/docs/internal/README.md @@ -13,21 +13,18 @@ Wasm artifact. Current work is focused on making that Gleam-project-to-Wasm path more usable: -1. Improve CLI artifacts, diagnostics, and host metadata. -2. Fill stdlib and dependency gaps that block realistic projects. -3. Add larger examples as acceptance fixtures after the core gaps are planned. +1. Fill stdlib and dependency gaps that block realistic projects. +2. Add larger examples as acceptance fixtures after the core gaps are planned. ## Specs - [Stdlib and host interop](specs/16_stdlib_and_host_interop.md) -- [CLI and build outputs](specs/17_cli_and_build_outputs.md) - [Example projects](specs/18_example_projects.md) - [WASI host ABI](specs/20_wasi_host_abi.md) ## Task Trackers - [Stdlib and host interop](tasks/16_stdlib_and_host_interop.md) -- [CLI and build outputs](tasks/17_cli_and_build_outputs.md) - [WASI host ABI](tasks/21_wasi_host_abi.md) ### Examples diff --git a/docs/internal/specs/17_cli_and_build_outputs.md b/docs/internal/specs/17_cli_and_build_outputs.md deleted file mode 100644 index 02d2bf6..0000000 --- a/docs/internal/specs/17_cli_and_build_outputs.md +++ /dev/null @@ -1,89 +0,0 @@ -# CLI and build outputs - -Current single-file CLI behavior is documented in [CLI and build outputs][cli]. -This spec tracks the remaining user-facing command and artifact work that is not -specific to project linking. - -Project compilation itself is defined in the website development design record: -[Project compilation and dependencies][projects]. - -[cli]: ../../website/reference/cli-and-build-outputs.md -[projects]: ../../website/development/projects.md - -## Responsibilities - -The CLI should provide predictable commands and stable artifacts for both users -and compiler contributors. - -Remaining responsibilities: - -- keep normal output concise -- make debug output opt-in -- write deterministic artifacts -- avoid partial final artifacts after failed compilation -- expose enough metadata for host adapters and tests - -## Commands - -Single-file compilation remains useful for fixtures and small examples. Project -compilation reuses the same output, target, WAT, emit, dump, verbose, and JSON -reservation flags where possible. - -Current command surface: - -- `build [project]` compiles a Gleam project. -- `compile ` compiles one source file. -- `run ` compiles one source file and executes an export with Wasmtime. -- `exec` is an alias for `run`. -- `debug`/`dbg` inspect compiler-internal views. -- `list [project]` prints discovered project modules. - -`build` and `compile` both support output path selection, optional WAT output, -optional debug dump directories, target selection, and explicit artifact -selection. `run` and `exec` support Wasmtime execution for scalar arguments and -ABI-aware rendering of scalar and managed return values. - -Commands should continue to return clear exit codes for success, diagnostics, -and command misuse. - -## Artifacts - -Suggested outputs: - -- final `.wasm` -- optional `.wat` -- optional AST, resolved, typed, IR, and WAT dumps -- optional runtime layout and ABI metadata -- optional import/export metadata for host adapters -- deterministic JS host adapter files when requested - -Artifact paths should be stable enough for examples, snapshots, and host smoke -tests. - -## Diagnostics - -Diagnostics are rendered for humans by default and remain structured enough for -tests. - -The CLI should support: - -- file paths -- source snippets -- labels -- notes -- stable multi-module ordering -- stage-specific unsupported-feature messages -- clear messages for target and ABI mismatches - -## Backend output model - -The backend now builds a compiler-owned Wasm module and can emit bytes directly. -CLI output should treat WAT as a rendered debug artifact, not as the source of -truth for byte emission. - -Helper-backed modules should continue to assemble through checked helper -fragments before they are included in final output. - -## Active tasks - -See [CLI and build outputs tasks](../tasks/17_cli_and_build_outputs.md). diff --git a/docs/internal/tasks/17_cli_and_build_outputs.md b/docs/internal/tasks/17_cli_and_build_outputs.md deleted file mode 100644 index 856c1b8..0000000 --- a/docs/internal/tasks/17_cli_and_build_outputs.md +++ /dev/null @@ -1,68 +0,0 @@ -# CLI and build outputs tasks - -## Goal - -Make compiler commands predictable and generated artifacts useful. - -## Tasks - -### Commands - -- [x] Keep single-file compilation available for tests and examples. -- [x] Add output path configuration. -- [x] Add target selection for supported runtimes and host profiles: Wasmtime, - browser, bundler, Node.js, and WASI where implemented. -- [x] Return useful exit codes for success, diagnostics, and command misuse. -- [x] Keep project compilation flags consistent with single-file compilation. -- [x] Add CLI `run`/`exec` (aliases for one another) integration tests for Wasmtime execution. -- [x] Add ABI-aware rendering for managed `run` return values such as strings, - tuples, lists, records, `Result`, and `Option`. - -### Artifacts - -- [x] Write `.wasm` artifacts. -- [x] Add optional WAT output. -- [x] Add optional AST, resolved AST, typed output, and IR debug dumps. -- [x] Emit Wasm bytes from a structured module without going through WAT. -- [x] Add deterministic WAT snapshots generated from structured Wasm. -- [x] Emit deterministic `.mjs` adapter files when Wasm output is requested for - browser, bundler, and Node.js targets. -- [x] Expose JS host import and export metadata needed by checked host calls. -- [x] Add optional runtime layout and ABI debug output where helpful. -- [x] Include import and export metadata in explicit debug output where useful. -- [x] Emit or package deterministic browser and Node.js host adapter files when - requested. - -### Backend cleanup - -- [x] Disable silent fallback from structured codegen to the old WAT emitter. -- [x] Keep unsupported IR as source-spanned `WasmError` diagnostics. -- [x] Delete the old `Emitter` implementation and fallback-only tests. -- [x] Give helper-backed modules direct structured byte emission or checked - precompiled fragments. - -### Diagnostics and user output - -- [x] Render diagnostics with source snippets, labels, notes, and file paths. -- [x] Group diagnostics across project modules in a stable order. -- [x] Improve type-inference diagnostics for local generalization, ambiguous - types, recursive types, constructor fields, and branch mismatches. -- [x] Show unsupported-feature diagnostics from AST, resolver, type, lowering, - backend, stdlib, and ABI stages without losing source spans. -- [x] Keep normal compile output concise; make debug output opt-in. -- [x] Add human-readable messages for missing project files, duplicate modules, - unsupported exports, and backend target mismatches. - -### Integration tests - -- [x] Add CLI integration tests for project compilation commands. -- [x] Add CLI integration tests for diagnostics across multiple files. -- [x] Add tests for output path handling and optional WAT/debug artifacts. -- [x] Add tests for target selection and unsupported target combinations. -- [x] Add tests for browser and Node.js JS host profile output. -- [x] Add tests for bundler host adapter artifact paths. - -## Done when - -Users get concise command output, deterministic artifacts, and clear -source-rendered diagnostics for both single-file and project compilation. diff --git a/docs/website/changelog.md b/docs/website/changelog.md index 3148617..1c23b73 100644 --- a/docs/website/changelog.md +++ b/docs/website/changelog.md @@ -6,13 +6,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### 2026-06-19 -#### Changed +#### Added -- Promoted the JavaScript host ABI contract to the website development docs. +- CLI project and single-file compilation now share output path, target, WAT, + emit, dump, verbose, and JSON reservation flags. +- `run` and `exec` now compile one source file, execute a Wasmtime export, and + render scalar and supported managed return values. +- Build output now includes deterministic Wasm, optional WAT, AST, resolved, + typed, IR, runtime layout, ABI, and import/export metadata artifacts. +- Browser, bundler, and Node.js targets now emit deterministic `.mjs` host + adapter files when Wasm output is requested. +- CLI diagnostics now include stable multi-module ordering, source snippets, + labels, notes, clearer project errors, clearer target and ABI mismatch + messages, and improved type-inference context. -#### Removed +#### Changed -- Removed the completed internal JavaScript host ABI spec and task tracker. +- The CLI now supports a global `--no-color` flag and honors the + [`NO_COLOR`](https://no-color.org/) environment variable for plain + human-readable output. +- WAT is now treated as a rendered debug artifact; structured Wasm byte + emission is the source of truth for final `.wasm` output. ### 2026-06-05 diff --git a/docs/website/guide/usage/cli.md b/docs/website/guide/usage/cli.md index 938330b..94ca1ab 100644 --- a/docs/website/guide/usage/cli.md +++ b/docs/website/guide/usage/cli.md @@ -15,6 +15,19 @@ reggie build regulus build ``` +## Global options + +Pass `--no-color` before or after a subcommand to disable ANSI color in +human-readable output: + +```sh +reggie --no-color build examples/scalar_project +reggie build examples/scalar_project --no-color +``` + +Regulus also disables ANSI color when the `NO_COLOR` environment variable is +set[^no-color] + ## Build a project Use `build` for Gleam projects with a `gleam.toml` file. @@ -33,6 +46,17 @@ Project builds write `build/.wasm` by default. Use `--output` to choose an exact final path or `--out-dir` to write compiler-named artifacts into a directory. +Example: + +```sh +reggie --no-color build examples/scalar_project --out-dir build/docs +``` + +```text +Resolving dependencies +wasm build/docs/scalar_project.wasm (63 bytes) +``` + See [Project compilation and dependencies][project-compilation] for dependency loading, linked output, and current project limits. @@ -48,6 +72,10 @@ reggie compile path/to/module.gleam By default, single-file compilation writes a `.wasm` file next to the input. `--output` and `--out-dir` work the same way as project builds. +Single-file compilation exists for fixtures, small examples, and compiler +debugging. Project compilation should use `build` so module discovery, +dependencies, and linked output all follow the project model. + ## Run one file Use `run` to compile a single `.gleam` file and execute one exported function @@ -65,10 +93,20 @@ reggie run path/to/module.gleam --function add 1 2 reggie exec path/to/module.gleam ``` -Scalar arguments and return values use the low-level Wasm ABI. `Int` values are -passed as `i64`, `Float` values as `f64`, and `Bool` values as `i32`. Managed -values such as strings, lists, tuples, records, and custom types are pointers -into guest memory at the Wasm boundary. Programs can still print strings through +Example: + +```sh +reggie run examples/scalar_project/src/main.gleam --function add_one 41 +``` + +```text +42 +``` + +Scalar arguments use the low-level Wasm ABI. `Int` values are passed as `i64`, +`Float` values as `f64`, and `Bool` values as `i32`. Return values are rendered +for scalars and supported managed values such as strings, tuples, lists, +records, `Result`, and `Option`. Programs can also print strings through `gleam/io.print` and `gleam/io.println` when targeting Wasmtime. ## Targets @@ -85,11 +123,26 @@ Supported target values are `wasmtime`, `browser`, `bundler`, `nodejs`, and `wasi`. Project builds use the target from `gleam.toml` when `--target` is not provided. -`bundler` emits a deterministic `.mjs` adapter next to the `.wasm` artifact -when Wasm output is requested. That adapter loads the Wasm module, checks -imports, converts scalar and string calls, and reads supported structured -export results. `browser` and `nodejs` are accepted targets, but their complete -host glue and profile-specific APIs are still in progress. +`browser`, `bundler`, and `nodejs` emit deterministic `.mjs` adapters next to +the `.wasm` artifact when Wasm output is requested. The adapters load the Wasm +module, check imports, convert scalar and string calls, and read supported +structured export results. + +Example: + +```sh +reggie --no-color build examples/scalar_project --target nodejs --out-dir build/node +``` + +```text +Resolving dependencies +wasm build/node/scalar_project.wasm (2651 bytes) +js build/node/scalar_project.mjs +``` + +Target-specific externals are checked before Wasm assembly. If a source file +imports a browser or Node.js host module while compiling for Wasmtime, the CLI +reports the target mismatch with a source label and recovery note. ## Artifacts @@ -118,6 +171,18 @@ Supported emit values are: `--out-dir` when that option is used. Debug emit values write deterministic files beside the selected output path unless `--dump-dir` is set. +Example: + +```sh +reggie --no-color build examples/scalar_project --out-dir build/debug --emit wasm,wat +``` + +```text +Resolving dependencies +wasm build/debug/scalar_project.wasm (63 bytes) +wat build/debug/scalar_project.wat +``` + Use `--dump-dir` to write all compiler debug dumps into a separate directory: ```sh @@ -131,6 +196,45 @@ typed output, linked IR, WAT, runtime layout, and ABI output. If compilation fails, Regulus does not write the final Wasm artifact. Debug artifacts are only written when the requested compiler phase completes. +The backend emits final Wasm bytes from its structured module. WAT is rendered +from that module for debugging and snapshots; it is not the source of truth for +the final `.wasm` artifact. + +## Diagnostics and exit codes + +Successful commands exit with status code `0`. Compilation diagnostics and +project loading errors exit with a non-zero status code. Command misuse, such +as an unknown flag or invalid subcommand, is reported by the CLI argument +parser and also exits non-zero. + +Human diagnostics include file paths, source snippets when a span is available, +labels, and notes. Project diagnostics are grouped in a stable order across +modules. + +Missing project manifests are reported with the path Regulus tried to load: + +```sh +reggie --no-color build /tmp/not-a-regulus-project +``` + +```text +error could not load project /tmp/not-a-regulus-project +diagnostic ProjectError: project manifest not found at /tmp/not-a-regulus-project/gleam.toml + note: pass a project directory or a path to gleam.toml +``` + +Duplicate modules include both conflicting source paths: + +```sh +reggie --no-color build examples/diagnostics/duplicate_modules +``` + +```text +error could not load project examples/diagnostics/duplicate_modules +diagnostic ProjectError: duplicate module `app` in examples/diagnostics/duplicate_modules/src/app.gleam and examples/diagnostics/duplicate_modules/test/app.gleam + note: each module name must be unique across src and test +``` + ## Inspect one source file Use `debug` when changing parser or AST support for one `.gleam` file. The @@ -163,13 +267,21 @@ By default, debug/dbg require a source file and at least one view flag. Use `list` to inspect discovered modules without building artifacts. ```sh -reggie list examples/multi_module_project +reggie --no-color list examples/multi_module_project +``` + +```text +project multi_module_project 1.0.0 (2 modules) +module main -> examples/multi_module_project/src/main.gleam +module math -> examples/multi_module_project/src/math.gleam ``` ## Current limitations -Project compilation is still growing. Broad Hex dependency language coverage, -bodyless externals from dependency source, and richer host ABI adapters are -tracked in `docs/internal`. +Project compilation is still growing. Broad Hex dependency language coverage +and additional host APIs are documented in the development and reference docs +as they stabilize. [project-compilation]: ../../reference/compiling-projects.md + +[^no-color]: https://no-color.org/ -- 2.51.2