diff --git a/src/engine.rs b/src/engine.rs index 616dd1f..4161d3e 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()), + ]) + } } /// Runs `f`, which may evaluate Nushell, without stalling the tokio runtime. diff --git a/src/store.rs b/src/store.rs index 80cd315..9688d62 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 21fb60a..850fcbb 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();