diff --git a/Cargo.lock b/Cargo.lock index 130f687..6243123 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1166,9 +1166,9 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "cross-stream" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8138385fb398870cda06244639caa3bf928a1452b8ee5a37c46f3359df87f63" +checksum = "3e0208127642befc45f81b13d05dfc70fc675579330151416b6d0898a466c51d" dependencies = [ "base64 0.22.1", "bon", diff --git a/Cargo.toml b/Cargo.toml index e04d751..d9e04c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,7 +72,7 @@ pulldown-cmark = "0.12.2" notify = "8" [dependencies.cross-stream] -version = "0.13.3" +version = "0.13.4" optional = true [features] diff --git a/src/engine.rs b/src/engine.rs index 1b7098c..17ba865 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -387,6 +387,22 @@ impl Engine { Box::new(MjCompileCommand::with_store(store.clone())), ]) } + + /// Add http-nu's `.mj` (store-backed), `.md`, and highlight commands to this + /// engine, to use as an xs processor base via `Store::with_base_engine` so + /// actors, services, and actions can use them. See xs ADR 0007. + #[cfg(feature = "cross-stream")] + pub fn add_processor_commands(&mut self, store: &xs::store::Store) -> Result<(), Error> { + self.add_commands(vec![ + Box::new(MjCommand::with_store(store.clone())), + Box::new(MjCompileCommand::with_store(store.clone())), + Box::new(MjRenderCommand::new()), + Box::new(MdCommand::new()), + Box::new(HighlightCommand::new()), + Box::new(HighlightThemeCommand::new()), + Box::new(HighlightLangCommand::new()), + ]) + } } /// Creates an engine from a script by cloning a base engine and parsing the closure. diff --git a/src/store.rs b/src/store.rs index a131c6f..19e4e7e 100644 --- a/src/store.rs +++ b/src/store.rs @@ -37,6 +37,17 @@ impl Store { ) -> Result { let inner = xs::store::Store::new(path.clone())?; + // Hand the processors a base engine with http-nu's `.mj`, `.md`, and + // highlight commands so actors, services, and actions can use them, not + // just HTTP handlers. prepared_base clones this base per spawn. See xs + // ADR 0007. Set before any clone so all share it. + let inner = { + let mut base = crate::Engine::new().expect("Failed to build processor base engine"); + base.add_processor_commands(&inner) + .expect("Failed to register processor base commands"); + inner.with_base_engine(base.state) + }; + // API server let store_for_api = inner.clone(); tokio::spawn(async move { diff --git a/src/test_engine.rs b/src/test_engine.rs index 3ea714f..48f5270 100644 --- a/src/test_engine.rs +++ b/src/test_engine.rs @@ -8,6 +8,33 @@ fn eval_engine() -> Engine { engine } +#[cfg(feature = "cross-stream")] +#[test] +fn test_processor_base_command_surface() { + use nu_protocol::engine::StateWorkingSet; + + let tmp = tempfile::TempDir::new().unwrap(); + let store = xs::store::Store::new(tmp.path().to_path_buf()).unwrap(); + let mut engine = Engine::new().unwrap(); + engine.add_processor_commands(&store).unwrap(); + + // .mj and .md are present... + let ws = StateWorkingSet::new(&engine.state); + assert!( + ws.find_decl(b".mj").is_some(), + ".mj must be on the processor base" + ); + assert!( + ws.find_decl(b".md").is_some(), + ".md must be on the processor base" + ); + // ...and .static, an HTTP-handler command, is not. + assert!( + ws.find_decl(b".static").is_none(), + ".static must not be on the processor base" + ); +} + #[test] fn test_engine_eval() { let mut engine = Engine::new().unwrap();