Skip to content

Commit 406f976

Browse files
committed
yaml metadata writing in qmd
1 parent b6f0c47 commit 406f976

File tree

9 files changed

+137
-5
lines changed

9 files changed

+137
-5
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/quarto-markdown-pandoc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ glob = "0.3"
2323
paste = "1.0.15"
2424
once_cell = "1.21.3"
2525
yaml-rust2 = "0.10.3"
26+
hashlink = "0.10.0"
2627
error-message-macros = { path = "./error-message-macros" }
2728
ariadne = "0.4"
2829

crates/quarto-markdown-pandoc/src/writers/qmd.rs

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
use crate::pandoc::attr::is_empty_attr;
77
use crate::pandoc::block::MetaBlock;
88
use crate::pandoc::list::ListNumberDelim;
9+
use crate::pandoc::meta::MetaValue;
910
use crate::pandoc::table::{Alignment, Cell, Table};
1011
use crate::pandoc::{
1112
Block, BlockQuote, BulletList, CodeBlock, DefinitionList, Figure, Header, HorizontalRule,
1213
LineBlock, Meta, OrderedList, Pandoc, Paragraph, Plain, RawBlock, Str,
1314
};
1415
use crate::utils::string_write_adapter::StringWriteAdapter;
16+
use hashlink::LinkedHashMap;
1517
use std::io::{self, Write};
18+
use yaml_rust2::{Yaml, YamlEmitter};
1619

1720
struct BlockQuoteContext<'a, W: Write + ?Sized> {
1821
inner: &'a mut W,
@@ -158,14 +161,92 @@ impl<'a, W: Write + ?Sized> Write for OrderedListContext<'a, W> {
158161
}
159162
}
160163

161-
fn write_meta<T: std::io::Write + ?Sized>(meta: &Meta, _buf: &mut T) -> std::io::Result<bool> {
164+
/// Convert a MetaValue to a yaml_rust2::Yaml value
165+
/// MetaInlines and MetaBlocks are rendered using the qmd writer
166+
fn meta_value_to_yaml(value: &MetaValue) -> std::io::Result<Yaml> {
167+
match value {
168+
MetaValue::MetaString(s) => Ok(Yaml::String(s.clone())),
169+
MetaValue::MetaBool(b) => Ok(Yaml::Boolean(*b)),
170+
MetaValue::MetaInlines(inlines) => {
171+
// Render inlines using the qmd writer
172+
let mut buffer = String::new();
173+
let mut adapter = StringWriteAdapter::new(&mut buffer);
174+
for inline in inlines {
175+
write_inline(inline, &mut adapter)?;
176+
}
177+
Ok(Yaml::String(buffer))
178+
}
179+
MetaValue::MetaBlocks(blocks) => {
180+
// Render blocks using the qmd writer
181+
let mut buffer = String::new();
182+
let mut adapter = StringWriteAdapter::new(&mut buffer);
183+
for (i, block) in blocks.iter().enumerate() {
184+
if i > 0 {
185+
writeln!(&mut adapter)?;
186+
}
187+
write_block(block, &mut adapter)?;
188+
}
189+
// Trim trailing newline to avoid extra spacing in YAML
190+
let trimmed = buffer.trim_end();
191+
Ok(Yaml::String(trimmed.to_string()))
192+
}
193+
MetaValue::MetaList(list) => {
194+
let mut yaml_list = Vec::new();
195+
for item in list {
196+
yaml_list.push(meta_value_to_yaml(item)?);
197+
}
198+
Ok(Yaml::Array(yaml_list))
199+
}
200+
MetaValue::MetaMap(map) => {
201+
// Sort keys to ensure deterministic output
202+
let mut sorted_keys: Vec<_> = map.keys().collect();
203+
sorted_keys.sort();
204+
205+
let mut yaml_map = LinkedHashMap::new();
206+
for key in sorted_keys {
207+
let val = &map[key];
208+
yaml_map.insert(Yaml::String(key.clone()), meta_value_to_yaml(val)?);
209+
}
210+
Ok(Yaml::Hash(yaml_map))
211+
}
212+
}
213+
}
214+
215+
fn write_meta<T: std::io::Write + ?Sized>(meta: &Meta, buf: &mut T) -> std::io::Result<bool> {
162216
if meta.is_empty() {
163217
Ok(false)
164218
} else {
165-
panic!("Metadata writing is not yet implemented");
166-
// eventually we'll return true here so
167-
// that the caller knows to add a newline after the metadata block
168-
// Ok(true)
219+
// Convert Meta to YAML
220+
// Sort keys to ensure deterministic output
221+
let mut sorted_keys: Vec<_> = meta.keys().collect();
222+
sorted_keys.sort();
223+
224+
let mut yaml_map = LinkedHashMap::new();
225+
for key in sorted_keys {
226+
let value = &meta[key];
227+
yaml_map.insert(Yaml::String(key.clone()), meta_value_to_yaml(value)?);
228+
}
229+
let yaml = Yaml::Hash(yaml_map);
230+
231+
// Emit YAML to string
232+
let mut yaml_str = String::new();
233+
let mut emitter = YamlEmitter::new(&mut yaml_str);
234+
emitter
235+
.dump(&yaml)
236+
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
237+
238+
// The YamlEmitter adds "---\n" at the start and includes the content
239+
// We need to add the closing "---\n"
240+
// First, ensure yaml_str ends with a newline
241+
if !yaml_str.ends_with('\n') {
242+
yaml_str.push('\n');
243+
}
244+
245+
// Write the YAML metadata block
246+
write!(buf, "{}", yaml_str)?;
247+
writeln!(buf, "---")?;
248+
249+
Ok(true)
169250
}
170251
}
171252

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
draft: true
3+
published: false
4+
---
5+
6+
# Test Document
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
title: A **bold** title with *emphasis*
3+
subtitle: Testing inline elements
4+
---
5+
6+
# Test Document
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
tags:
3+
- tag1
4+
- tag2
5+
- tag3
6+
---
7+
8+
# Test Document
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
title: Test Document
3+
draft: true
4+
tags:
5+
- science
6+
- research
7+
settings:
8+
toc: true
9+
number-sections: false
10+
---
11+
12+
# Introduction
13+
14+
This is a test document.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
author:
3+
name: John Doe
4+
affiliation: Example University
5+
---
6+
7+
# Test Document
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: Simple Title
3+
author: John Doe
4+
---
5+
6+
# Test Document
7+
8+
This is a test.

0 commit comments

Comments
 (0)