Files
oh-my-pi/crates/pi-builtins
can1357 311c32eaf5 fix(natives): repaired win32 build and bazel feature drift
- Synced pi-builtins bazel crate_features with cargo's resolved default
  set: bazel features are literal, so the meta-features never expanded
  and the procs/rg cluster (nohup, pgrep, pidwait, pkill, proc-match,
  ps, rg, sleep, timeout, top) was silently compiled out, leaving the
  process builtins unregistered under bazel and failing pi-shell tests.
- Repaired windows compilation of pi-builtins: cfg-gated the
  uucore::mode import in mkdir, imported std::env in sort's non-unix
  locale probe, mapped ProcInfo::pid through a closure in kill, brought
  MetadataExt into scope in wc, and replaced stat's unstable
  windows_by_handle metadata with a stable GetFileInformationByHandle
  query (volume serial, link count, file index, no-dereference aware).
- Imported HashSet for pi-shell's windows-only PATH merge.
- Added a clippy-ported bazel config + CI bucket so pi-builtins keeps
  its manifest-declared clippy allows under the bazel aspect while rustc
  warnings stay denied, and zeroed the remaining windows-target rustc
  warnings (unused params/imports in find, mv, rm, proc_match, ps).
2026-08-09 03:17:34 +02:00
..
2026-08-08 10:19:25 +02:00

pi-builtins

Every builtin the embedded shell installs. Two layers:

  1. Shell builtins — cd, echo, test, printf, read, export, trap, wait, … A locally-patched fork of brush-builtins (MIT), tracking upstream except where noted in LICENSE.
  2. In-process command-line utilities — cat, grep/rg, sed, ls, find, sort, jq, fd, diff, xargs, ps, top, kill, the moreutils set, and ~50 more. One module per command, in src/<command>.rs.

The second layer exists so the shell never has to fork: a long-lived embedded shell resolves these names itself, on every platform, whether or not the host has the real binaries. They were previously ~50 separate vendored crates driven through a thread-local I/O shim; consolidating them here removed the shim.

The Host contract

src/host.rs is the whole story for a utility builtin. A utility is a clap argument model plus a synchronous body:

pub(crate) trait Utility: clap::Parser + Send + Sync + 'static {
    const NAME: &'static str;
    const USAGE_ERROR: u8 = 1;
    fn run(self, host: &mut Host) -> i32;
}

Host is the shell as the utility sees it, threaded explicitly rather than through process globals or thread locals: the command's own stdio (host.stdout, host.stderr, host.stdin), the shell's working directory (host.resolve(path) — mandatory for every path argument, since the host process's current directory is unrelated), the exported environment (host.var, host.env), cancellation (host.is_cancelled), a child-process launcher that inherits all of the above (host.child_env()), and the accumulated exit status (host.fail, host.exit_code).

host::util::<U, SE>() wraps a Utility into a registration that handles, once for all of them: process-substitution arguments (diff <(a) <(b)), --help/--version on stdout with status 0, usage errors on stderr, execution on a blocking thread, the shell's cancellation token, and panic containment.

Utilities that are genuinely async — sleep, timeout, ps, top, pgrep, kill, nohup — implement brush_core::builtins::Command directly instead.

Registration

Three entry points, so the embedding shell decides what to install:

Function Contents
default_builtins(set) The POSIX/bash builtins, per BuiltinSet.
utility_builtins() The coreutils-style commands, which shadow system binaries.
process_builtins() ps, top, pgrep, pkill, pidwait, sleep, timeout, nohup.

Every command is behind a cargo feature (builtin.<name>, util.<name>), so a single one can be built and tested in isolation:

$ cargo test -p pi-builtins --no-default-features --features base,util.sed

Licensing

MIT throughout, but the ported utilities carry upstream notices — uutils coreutils, uutils findutils, uutils sed, jaq, and rust-utf8. See LICENSE, which reproduces each in full and lists which commands it covers.