Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions claude-notes/plans/2026-10-27-lua-api-q1-parity-gh-939-942.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,6 @@ branch off one integration branch (`feature/lua-api-q1-parity`).
- **The rest of `PANDOC_STATE`** (`resource_path`, `verbosity`, `log`,
`trace`, `user_data_dir`, `request_headers`, `source_url`). The minimal
two-field version is in #940; the rest has no q2 equivalent to report.
- **`EnvShortcodeHandler` on the environment snapshot** instead of its
own lookup-time merge (one consistent environment for shortcodes and
filters alike).
- **Exposing the full version string** (nightlies lose
`-nightly.YYYYMMDD` in the numeric Version). Q1 does not expose it
either.
Expand Down Expand Up @@ -399,6 +396,16 @@ branch off one integration branch (`feature/lua-api-q1-parity`).
Flag for a Windows run in the PR.
- Five quarto-core unit tests fail under plain `cargo test` but pass under
nextest (process isolation); unrelated to this change.
- **Follow-up, bd-irkfpip1 (stacked PR):** `EnvShortcodeHandler` reads
the same snapshot. `ShortcodeResolveTransform::with_lua_support` and
the two pipeline builders take an `Option<Arc<EnvSnapshot>>` in place
of the `project_env` + `quarto_profile` pair (47 call sites, all with
the same trailing `Default::default(), None` shape, rewritten by
script); the transform hands the snapshot to both the `env` handler
and the Lua engine's `HostContext`, which made the `RenderContext.
env_snapshot` bridge from the first PR unnecessary, so it was removed.
Without a snapshot (custom pipelines, unit tests) the handler reads the
real process environment, as before.

## Risks

Expand Down
42 changes: 4 additions & 38 deletions crates/quarto-core/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2266,8 +2266,7 @@ pub fn build_transform_pipeline(
target_format: String,
pipeline_profile: crate::format::PipelineProfile,
variables: Option<quarto_pandoc_types::ConfigValue>,
project_env: hashlink::LinkedHashMap<String, String>,
quarto_profile: Option<String>,
env_snapshot: Option<std::sync::Arc<crate::project::environment::EnvSnapshot>>,
) -> TransformPipeline {
let mut pipeline: TransformPipeline = TransformPipeline::new();

Expand Down Expand Up @@ -2326,8 +2325,7 @@ pub fn build_transform_pipeline(
runtime.clone(),
lua_format,
variables,
project_env,
quarto_profile,
env_snapshot,
)));
// Heading ids follow the *final* text: shortcode expansion just above
// and lmd cells (`lmd-execute`, before the transforms) both rewrite
Expand Down Expand Up @@ -3213,8 +3211,7 @@ pub fn build_q2_preview_transform_pipeline(
target_format: String,
pipeline_profile: crate::format::PipelineProfile,
variables: Option<quarto_pandoc_types::ConfigValue>,
project_env: hashlink::LinkedHashMap<String, String>,
quarto_profile: Option<String>,
env_snapshot: Option<std::sync::Arc<crate::project::environment::EnvSnapshot>>,
) -> TransformPipeline {
let mut pipeline = build_transform_pipeline(
shortcode_paths,
Expand All @@ -3223,8 +3220,7 @@ pub fn build_q2_preview_transform_pipeline(
target_format,
pipeline_profile,
variables,
project_env,
quarto_profile,
env_snapshot,
);
pipeline.retain_excluding(Q2_PREVIEW_TRANSFORM_EXCLUDED);
pipeline
Expand Down Expand Up @@ -4472,7 +4468,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let html_names: Vec<&str> = html.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -5194,7 +5189,6 @@ mod tests {
"q2-preview".to_string(),
crate::format::PipelineProfile::HtmlPreview,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand All @@ -5220,7 +5214,6 @@ mod tests {
"q2-preview".to_string(),
crate::format::PipelineProfile::HtmlPreview,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -5275,7 +5268,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -5333,7 +5325,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let found = pipeline
Expand Down Expand Up @@ -5366,7 +5357,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -5408,7 +5398,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -5485,7 +5474,6 @@ mod tests {
format.to_string(),
crate::format::PipelineProfile::from_format(format),
None,
Default::default(),
None,
);
let steps: Vec<(&str, TransformPhase)> =
Expand Down Expand Up @@ -5567,7 +5555,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);

Expand Down Expand Up @@ -5599,7 +5586,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let expected: Vec<&str> = pipeline
Expand Down Expand Up @@ -5632,7 +5618,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let expected: Vec<&str> = pipeline
Expand Down Expand Up @@ -5677,7 +5662,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let project = make_test_project();
Expand Down Expand Up @@ -5846,7 +5830,6 @@ mod tests {
"typst".to_string(),
crate::format::PipelineProfile::from_format("typst"),
None,
Default::default(),
None,
);
let expected: Vec<&str> = pipeline
Expand Down Expand Up @@ -6355,7 +6338,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6394,7 +6376,6 @@ mod tests {
"q2-preview".to_string(),
crate::format::PipelineProfile::HtmlPreview,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6422,7 +6403,6 @@ mod tests {
format.to_string(),
crate::format::PipelineProfile::from_format(format),
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6460,7 +6440,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let html_names: Vec<&str> = html_pipeline.iter().map(|t| t.name()).collect();
Expand All @@ -6480,7 +6459,6 @@ mod tests {
"docx".to_string(),
crate::format::PipelineProfile::Pandoc("docx".to_string()),
None,
Default::default(),
None,
);
let docx_names: Vec<&str> = docx_pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6513,7 +6491,6 @@ mod tests {
"docx".to_string(),
crate::format::PipelineProfile::Pandoc("docx".to_string()),
None,
Default::default(),
None,
);
let docx_names: Vec<&str> = docx_pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6545,7 +6522,6 @@ mod tests {
format.to_string(),
crate::format::PipelineProfile::from_format(format),
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand All @@ -6570,7 +6546,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6667,7 +6642,6 @@ mod tests {
"revealjs".to_string(),
crate::format::PipelineProfile::RevealjsRender,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6777,7 +6751,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let html_names: Vec<&str> = html.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6816,7 +6789,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let nav_names: Vec<&str> = html
Expand Down Expand Up @@ -6858,7 +6830,6 @@ mod tests {
"docx".to_string(),
crate::format::PipelineProfile::Pandoc("docx".to_string()),
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6925,7 +6896,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -6988,7 +6958,6 @@ mod tests {
"docx".to_string(),
crate::format::PipelineProfile::Pandoc("docx".to_string()),
None,
Default::default(),
None,
);

Expand Down Expand Up @@ -7035,7 +7004,6 @@ mod tests {
"q2-preview".to_string(),
crate::format::PipelineProfile::HtmlPreview,
None,
Default::default(),
None,
);
let names: Vec<&str> = pipeline.iter().map(|t| t.name()).collect();
Expand All @@ -7047,7 +7015,6 @@ mod tests {
"q2-preview".to_string(),
crate::format::PipelineProfile::HtmlPreview,
None,
Default::default(),
None,
);
let preview_names: Vec<&str> = preview_pipeline.iter().map(|t| t.name()).collect();
Expand Down Expand Up @@ -7523,7 +7490,6 @@ mod tests {
"html".to_string(),
crate::format::PipelineProfile::HtmlRender,
None,
Default::default(),
None,
);
let transform_names: Vec<&str> = html_transforms.iter().map(|t| t.name()).collect();
Expand Down
8 changes: 0 additions & 8 deletions crates/quarto-core/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,6 @@ pub struct RenderContext<'a> {
/// Bridged to/from `StageContext` by `AstTransformsStage`.
pub includes: PandocIncludes,

/// The environment Lua shortcode handlers see through `os.getenv`
/// (GH #939): [`crate::stage::StageContext::env_snapshot`], bridged
/// one-way by `AstTransformsStage`. `None` when a `RenderContext` is
/// built directly (unit tests, out-of-band drivers); the Lua `os`
/// table is then left as the stdlib / runtime provides it.
pub env_snapshot: Option<Arc<crate::project::environment::EnvSnapshot>>,

/// Diagnostics (warnings, errors, info) collected during transforms
pub diagnostics: Vec<DiagnosticMessage>,

Expand Down Expand Up @@ -613,7 +606,6 @@ impl<'a> RenderContext<'a> {
binaries,
options: RenderOptions::default(),
includes: PandocIncludes::default(),
env_snapshot: None,
diagnostics: Vec::new(),
ref_type_registry: None,
crossref_index: None,
Expand Down
13 changes: 2 additions & 11 deletions crates/quarto-core/src/stage/stages/ast_transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,7 @@ impl PipelineStage for AstTransformsStage {
ctx.format.target_format.clone(),
pipeline_profile,
ctx.variables.clone(),
ctx.project_env.clone(),
crate::project::project_profile::quarto_profile_env_value(
&ctx.project.config.active_config_profiles,
),
Some(ctx.env_snapshot.clone()),
)
}
_ => build_transform_pipeline(
Expand All @@ -194,10 +191,7 @@ impl PipelineStage for AstTransformsStage {
ctx.format.target_format.clone(),
pipeline_profile,
ctx.variables.clone(),
ctx.project_env.clone(),
crate::project::project_profile::quarto_profile_env_value(
&ctx.project.config.active_config_profiles,
),
Some(ctx.env_snapshot.clone()),
),
};
&jit_pipeline
Expand All @@ -222,9 +216,6 @@ impl PipelineStage for AstTransformsStage {
// Transfer mutable state to the RenderContext
render_ctx.artifacts = std::mem::take(&mut ctx.artifacts);
render_ctx.includes = std::mem::take(&mut ctx.includes);
// The environment Lua shortcodes read via os.getenv (GH #939);
// read-only, so the Arc is cloned rather than moved.
render_ctx.env_snapshot = Some(ctx.env_snapshot.clone());
render_ctx.ref_type_registry = ctx.ref_type_registry.take();
render_ctx.crossref_index = ctx.crossref_index.take();
render_ctx.observer = ctx.observer.clone();
Expand Down
Loading
Loading