shcl 2.0.0

SHCL - Simple Hierarchical Config Language. Reference parser, accessor, writer, and CLI.
Documentation

shcl

Simple Hierarchical Config Language. Forgiving to write, predictable to read.

Values are stored as plain text and coerced only when your code asks for a type, so a config file can never silently decide that NO means false. A bad line is skipped or repaired with a diagnostic instead of taking down the whole file.

This crate is the reference implementation. Independent Go, Python, and C bindings are held byte-for-byte against it by a shared conformance corpus.

Install

cargo add shcl

Zero dependencies. The crate also includes the CLI:

cargo install shcl

Use

use shcl::{Document, FileStatus};

// Reads and parses in one call, and never fails: the document is usable
// either way, and the status separates missing from unreadable from
// parsed-with-errors.
let (mut doc, file_status) = Document::load_file("server.shcl");
if file_status == FileStatus::NotFound {
	eprintln!("no config yet - using defaults");
}

// One call, a typed value, a visible fallback at the call site.
let limit = doc.get_int("site[example.com].max-upload-mb").unwrap_or(10);

// Or ask why a read failed: Good, Empty, NotFound, BadType, Multiple.
let r = doc.read_int("site[example.com].max-upload-mb");
if !r.ok() {
	eprintln!("{:?} (raw text was {:?})", r.status, r.raw);
}

// Wildcards read across instances, with a status per slot.
let roots = doc.read_string_array("site[*].root");

// Writes through a temp file and a rename, so an interrupted save cannot
// truncate the config - and refuses if the load dropped a line this write
// would delete (save_file_lossy is the override).
// Setters are #[must_use]: a path that cannot be written writes nothing at
// all, and write_reason names which of the five reasons it hit.
let path = "site[example.com].max-upload-mb";
if !doc.set_int(path, limit * 2) {
	eprintln!("not written: {:?}", doc.write_reason(path));
}
doc.save_file("server.shcl").unwrap();

Document::parse never fails, and neither does load_file. When you want a hard error instead, use Document::parse_with(&text, Strictness::Strict).

Also here: merge for layered config (defaults, site, user), validate against a schema that is itself a SHCL file, a full writer, and a canonical formatter that preserves comments.

Compatibility

Bindings are versioned in lockstep, so 2.x is the same behavior in every language. shcl = "2" picks up minor and patch releases on its own and never crosses a major version.

Docs

Language spec, formal grammar, and the other bindings: https://github.com/jim-collier/shcl

License

MIT. SHCL™ is a trademark of Jim Collier - see the trademark policy.