From 2730368baef6b201fffa6ae6ea14a4a16b21c9a0 Mon Sep 17 00:00:00 2001 From: Andy Gayton Date: Sat, 20 Jun 2026 13:28:52 +0000 Subject: [PATCH 1/3] feat: give processor engines http-nu's commands via a store base engine --- Cargo.lock | 5 ++--- Cargo.toml | 5 ++++- src/engine.rs | 16 ++++++++++++++++ src/store.rs | 11 +++++++++++ src/test_engine.rs | 27 +++++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 130f687d..371335f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1166,9 +1166,8 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "cross-stream" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8138385fb398870cda06244639caa3bf928a1452b8ee5a37c46f3359df87f63" +version = "0.13.4-dev" +source = "git+https://github.com/cablehead/xs?branch=feat%2Fengine-base#5bc1bcd0d1d0bcc1cc46233246afa80b8ea2cd12" dependencies = [ "base64 0.22.1", "bon", diff --git a/Cargo.toml b/Cargo.toml index e04d7517..756bcc34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,8 +71,11 @@ syntect-assets = "0.23.6" pulldown-cmark = "0.12.2" notify = "8" +# TEMPORARY: track the xs feat/engine-base branch for `Store::with_base_engine` +# (xs PR #144). Return to a published version once that lands and is released. [dependencies.cross-stream] -version = "0.13.3" +git = "https://github.com/cablehead/xs" +branch = "feat/engine-base" optional = true [features] diff --git a/src/engine.rs b/src/engine.rs index 1b7098c6..17ba8652 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 a131c6f5..19e4e7e2 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 3ea714ff..3bb2ad57 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(); + + // The context-free commands a processor needs 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 request-scoped commands are not. + assert!( + ws.find_decl(b".static").is_none(), + ".static is request-scoped and must not be on the processor base" + ); +} + #[test] fn test_engine_eval() { let mut engine = Engine::new().unwrap(); From 0ac2d7862db599ea5b2e4fe8b7ea1b5e13657e59 Mon Sep 17 00:00:00 2001 From: Andy Gayton Date: Sat, 20 Jun 2026 13:28:52 +0000 Subject: [PATCH 2/3] test: processor base carries .mj/.md but not request-scoped commands --- src/test_engine.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test_engine.rs b/src/test_engine.rs index 3bb2ad57..48f52700 100644 --- a/src/test_engine.rs +++ b/src/test_engine.rs @@ -18,7 +18,7 @@ fn test_processor_base_command_surface() { let mut engine = Engine::new().unwrap(); engine.add_processor_commands(&store).unwrap(); - // The context-free commands a processor needs are present... + // .mj and .md are present... let ws = StateWorkingSet::new(&engine.state); assert!( ws.find_decl(b".mj").is_some(), @@ -28,10 +28,10 @@ fn test_processor_base_command_surface() { ws.find_decl(b".md").is_some(), ".md must be on the processor base" ); - // ...and request-scoped commands are not. + // ...and .static, an HTTP-handler command, is not. assert!( ws.find_decl(b".static").is_none(), - ".static is request-scoped and must not be on the processor base" + ".static must not be on the processor base" ); } From b42e64ee809e8e0d1f6108bae5d0a9f619873d72 Mon Sep 17 00:00:00 2001 From: Andy Gayton Date: Thu, 6 Aug 2026 03:18:35 +0000 Subject: [PATCH 3/3] build: repoint cross-stream to published 0.13.4 --- Cargo.lock | 5 +++-- Cargo.toml | 5 +---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 371335f5..6243123a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1166,8 +1166,9 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "cross-stream" -version = "0.13.4-dev" -source = "git+https://github.com/cablehead/xs?branch=feat%2Fengine-base#5bc1bcd0d1d0bcc1cc46233246afa80b8ea2cd12" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0208127642befc45f81b13d05dfc70fc675579330151416b6d0898a466c51d" dependencies = [ "base64 0.22.1", "bon", diff --git a/Cargo.toml b/Cargo.toml index 756bcc34..d9e04c60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,11 +71,8 @@ syntect-assets = "0.23.6" pulldown-cmark = "0.12.2" notify = "8" -# TEMPORARY: track the xs feat/engine-base branch for `Store::with_base_engine` -# (xs PR #144). Return to a published version once that lands and is released. [dependencies.cross-stream] -git = "https://github.com/cablehead/xs" -branch = "feat/engine-base" +version = "0.13.4" optional = true [features]