Skip to content

Commit f50a7c2

Browse files
authored
Import captures body (#778)
1 parent f1dd715 commit f50a7c2

File tree

11 files changed

+69
-9
lines changed

11 files changed

+69
-9
lines changed

.vscode/settings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"rust-analyzer.cargo.allFeatures": true,
3-
"rust-analyzer.checkOnSave.command": "clippy",
43
"python.formatting.provider": "black",
5-
"python.REPL.enableREPLSmartSend": false
4+
"python.REPL.enableREPLSmartSend": false,
5+
"rust-analyzer.check.command": "clippy"
66
}

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ All notable changes to MiniJinja are documented here.
66

77
- Fix incorrect permissions when `--output` is used in the CLI. #772
88
- Added `mj_err_get_debug_info` to the C-ABI. #775
9+
- Modules now capture their output like they do in Jinja2. This
10+
means that if you do `{% import 'template.j2' as x %}` and you
11+
then render `{{ x }}` the output of `template.j2` is rendered as
12+
if it was included. #778
913

1014
## 2.9.0
1115

minijinja-cli/examples/include.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
Text from an included template
1+
Text from an included template
2+
{% set x = 42 %}

minijinja/src/compiler/codegen.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,14 +325,14 @@ impl<'source> CodeGenerator<'source> {
325325
}
326326
#[cfg(feature = "multi_template")]
327327
ast::Stmt::Import(import) => {
328-
self.add(Instruction::BeginCapture(CaptureMode::Discard));
328+
self.add(Instruction::BeginCapture(CaptureMode::Capture));
329329
self.add(Instruction::PushWith);
330330
self.compile_expr(&import.expr);
331331
self.add_with_span(Instruction::Include(false), import.span());
332+
self.add(Instruction::EndCapture);
332333
self.add(Instruction::ExportLocals);
333334
self.add(Instruction::PopFrame);
334335
self.compile_assignment(&import.name);
335-
self.add(Instruction::EndCapture);
336336
}
337337
#[cfg(feature = "multi_template")]
338338
ast::Stmt::FromImport(from_import) => {

minijinja/src/vm/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ mod fuel;
3131
mod loop_object;
3232
#[cfg(feature = "macros")]
3333
mod macro_object;
34+
#[cfg(feature = "multi_template")]
35+
mod module_object;
3436
mod state;
3537

3638
// the cost of a single include against the stack limit.
@@ -664,12 +666,15 @@ impl<'env> Vm<'env> {
664666
}
665667
#[cfg(feature = "multi_template")]
666668
Instruction::ExportLocals => {
669+
let captured = stack.pop();
667670
let locals = state.ctx.current_locals_mut();
668-
let mut module = value_map_with_capacity(locals.len());
671+
let mut values = value_map_with_capacity(locals.len());
669672
for (key, value) in locals.iter() {
670-
module.insert(Value::from(*key), value.clone());
673+
values.insert(Value::from(*key), value.clone());
671674
}
672-
stack.push(Value::from_object(module));
675+
stack.push(Value::from_object(crate::vm::module_object::Module::new(
676+
values, captured,
677+
)));
673678
}
674679
#[cfg(feature = "multi_template")]
675680
Instruction::CallBlock(name) => {

minijinja/src/vm/module_object.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std::fmt;
2+
use std::sync::Arc;
3+
4+
use crate::value::{Enumerator, Object, Value, ValueMap};
5+
6+
/// Holds the locals of a module.
7+
#[derive(Debug, Default)]
8+
pub(crate) struct Module {
9+
values: ValueMap,
10+
captured: Value,
11+
}
12+
13+
impl Module {
14+
pub fn new(values: ValueMap, captured: Value) -> Self {
15+
Self { values, captured }
16+
}
17+
}
18+
19+
impl Object for Module {
20+
fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
21+
self.values.get(key).cloned()
22+
}
23+
24+
fn enumerate(self: &Arc<Self>) -> Enumerator {
25+
let keys = self.values.keys().cloned();
26+
Enumerator::Values(keys.collect())
27+
}
28+
29+
fn render(self: &Arc<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30+
write!(f, "{}", self.captured)
31+
}
32+
}

minijinja/tests/inputs/import_all.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
}
3+
---
4+
{% set x = 23 %}
5+
{% import 'import-mixed.txt' as module %}
6+
{{ module|tojson }}
7+
|||{{ module }}|||
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{"c": "The C Variable"}
22
---
33
{% import "include_with_var_and_macro.txt" as helpers -%}
4-
{{ helpers }}
4+
{{ dict(helpers) }}
55
missing: {{ helpers.missing }}
66
title: {{ helpers.title }}
77
helper: {{ helpers.helper("a", "b") }}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This is the body {{ x }}
2+
{%- set output = 42 %}

minijinja/tests/snapshots/[email protected]

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ State {
122122
"call_macro.txt",
123123
"debug.txt",
124124
"example_macro.txt",
125+
"import-mixed.txt",
125126
"include_with_var_and_macro.txt",
126127
"layout_with_var.txt",
127128
"self-extends.txt",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
source: minijinja/tests/test_templates.rs
3+
description: "{% set x = 23 %}\n{% import 'import-mixed.txt' as module %}\n{{ module|tojson }}\n|||{{ module }}|||"
4+
info: {}
5+
input_file: minijinja/tests/inputs/import_all.txt
6+
---
7+
{"output":42}
8+
|||This is the body 23|||

0 commit comments

Comments
 (0)