shrub_core/lib.rs
1//! The shell itself: the [`Shell`] type and everything that runs a script, for
2//! programs that embed shrub or build a front end on it.
3//!
4//! `shrub-core` sits between [`shrub_parser`], which turns text into a syntax
5//! tree, and the crates that add builtins or a line editor on top. It owns
6//! variables, expansion, redirection, jobs, traps, and programmable
7//! completion. It has no line editor or prompt drawing of its own.
8//!
9//! ## Quick start
10//!
11//! Build a [`Shell`] with [`Shell::builder`], then run text with
12//! [`Shell::run_string`]. The shell keeps its variables, functions, and working
13//! directory between calls.
14//!
15//! ```
16//! use shrub_core::{Error, Shell, SourceInfo};
17//!
18//! # #[tokio::main(flavor = "current_thread")]
19//! # async fn main() -> Result<(), Error> {
20//! let mut shell = Shell::builder().build().await?;
21//!
22//! let result = shell
23//! .run_string(
24//! "name=world; greet() { echo \"Hello, $1!\"; }; greet \"$name\"",
25//! &SourceInfo::default(),
26//! &shell.default_exec_params(),
27//! )
28//! .await?;
29//!
30//! assert!(result.is_success());
31//! assert_eq!(shell.env_str("name").as_deref(), Some("world"));
32//! # Ok::<(), Error>(())
33//! # }
34//! ```
35//!
36//! A failed parse or an error the shell cannot continue past comes back as
37//! [`Error`]. A command that exits non-zero is not an error: it is an
38//! [`ExecutionResult`] whose exit code you inspect.
39//!
40//! ## Builtins
41//!
42//! A new shell has no builtins registered. Add them while building, with
43//! [`ShellBuilder::builtin`], or later with [`Shell::register_builtin`]. Use
44//! [`builtins::builtin`] to register a type that implements
45//! [`builtins::Command`], or [`builtins::simple_builtin`] for a
46//! [`builtins::SimpleCommand`]. The `shrub-builtins` crate registers the
47//! standard set this way.
48//!
49//! ## Customizing a shell
50//!
51//! [`Shell`] is generic over [`ShellExtensions`], which swaps in parts of the
52//! shell's behavior at compile time; today that is how errors are formatted.
53//! Create such a shell with [`Shell::builder_with_extensions`].
54//!
55//! ## Parsing
56//!
57//! The syntax tree types are re-exported in [`parser`]. [`Shell::parse_string`]
58//! parses with the options the shell currently has set.
59//!
60//! ## Snapshots
61//!
62//! [`Shell::snapshot`] copies the state a command can change, between
63//! commands, into a [`snapshot::ShellSnapshot`], and
64//! [`Shell::restore_snapshot`] applies one to a fresh shell, so an embedder
65//! can carry a shell across a process restart.
66//!
67//! ## Cargo features
68//!
69//! | Feature | Effect |
70//! |---|---|
71//! | `serde` | Implements `Serialize` and `Deserialize` for the syntax tree and other data types, through the same feature of `shrub-parser`. |
72//! | `experimental-parser` | Makes the `winnow`-based parser available through [`parser::ParserImpl`], by enabling `shrub-parser`'s `winnow-parser` feature. |
73
74#![cfg_attr(docsrs, feature(doc_cfg))]
75
76pub mod arithmetic;
77mod braceexpansion;
78pub mod builtins;
79pub mod callstack;
80pub mod commands;
81pub mod completion;
82pub mod env;
83pub mod error;
84pub mod escape;
85pub mod expansion;
86mod extendedtests;
87pub mod extensions;
88pub mod functions;
89pub mod history;
90pub mod int_utils;
91pub mod interfaces;
92mod interp;
93mod ioutils;
94pub mod jobs;
95mod keywords;
96pub mod namedoptions;
97pub mod openfiles;
98pub mod options;
99pub mod pathcache;
100pub mod pathsearch;
101pub mod patterns;
102pub mod processes;
103mod prompt;
104mod regex;
105pub mod results;
106mod shell;
107pub mod snapshot;
108pub mod sourceinfo;
109pub mod sys;
110pub mod tasks;
111pub mod terminal;
112pub mod tests;
113pub mod timing;
114pub mod trace_categories;
115pub mod traps;
116pub mod variables;
117mod wellknownvars;
118
119/// Re-export parser types used in core definitions.
120pub mod parser {
121 pub use shrub_parser::{
122 BindingParseError, ParseError, ParserImpl, SourcePosition, SourcePositionOffset,
123 SourceSpan, TestCommandParseError, WordParseError, ast,
124 };
125}
126
127pub use commands::{CommandArg, ExecutionContext};
128pub use error::{BuiltinError, Error, ErrorKind};
129pub use extensions::ShellExtensions;
130pub use interp::{ExecutionParameters, ProcessGroupPolicy};
131pub use parser::{SourcePosition, SourcePositionOffset, SourceSpan};
132pub use results::{ExecutionControlFlow, ExecutionExitCode, ExecutionResult, ExecutionSpawnResult};
133pub use shell::{
134 CreateOptions, ProfileLoadBehavior, RcLoadBehavior, SavedCommandStatus, Shell, ShellBuilder,
135 ShellBuilderState, ShellFd, ShellState,
136};
137pub use sourceinfo::SourceInfo;
138pub use variables::{ShellValue, ShellVariable};