Skip to content

Commit 8354eaa

Browse files
committed
metadata being written successfully
1 parent 304bca6 commit 8354eaa

File tree

7 files changed

+209
-82
lines changed

7 files changed

+209
-82
lines changed

crates/quarto_markdown_pandoc/src/filters.rs

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
use crate::pandoc::MetaValue;
7+
use crate::pandoc::block::MetaBlock;
78
use crate::pandoc::inline::AsInline;
89
use crate::pandoc::meta::Meta;
910
use crate::pandoc::meta::parse_metadata_strings;
@@ -140,13 +141,21 @@ impl<'a> Filter<'a> {
140141
self
141142
}
142143

143-
// pub fn with_blocks<F>(mut self, f: F) -> Self
144-
// where
145-
// F: Fn(Blocks) -> FilterReturn<Blocks, Blocks> + 'static,
146-
// {
147-
// self.blocks = Some(Box::new(f));
148-
// self
149-
// }
144+
pub fn with_blocks<F>(mut self, f: F) -> Filter<'a>
145+
where
146+
F: FnMut(Blocks) -> FilterReturn<Blocks, Blocks> + 'a,
147+
{
148+
self.blocks = Some(Box::new(f));
149+
self
150+
}
151+
152+
pub fn with_meta<F>(mut self, f: F) -> Filter<'a>
153+
where
154+
F: FnMut(Meta) -> FilterReturn<Meta, Meta> + 'a,
155+
{
156+
self.meta = Some(Box::new(f));
157+
self
158+
}
150159
}
151160

152161
macro_rules! define_filter_with_methods {
@@ -657,6 +666,34 @@ pub fn topdown_traverse_block(block: Block, filter: &mut Filter) -> Blocks {
657666
Block::HorizontalRule(hr) => {
658667
handle_block_filter!(HorizontalRule, hr, horizontal_rule, filter)
659668
}
669+
// quarto extensions
670+
Block::BlockMetadata(meta) => {
671+
if let Some(f) = &mut filter.meta {
672+
return match f(meta.meta) {
673+
FilterReturn::Unchanged(m) => vec![Block::BlockMetadata(MetaBlock {
674+
meta: m,
675+
filename: meta.filename,
676+
range: meta.range,
677+
})],
678+
FilterReturn::FilterResult(new_meta, recurse) => {
679+
if !recurse {
680+
vec![Block::BlockMetadata(MetaBlock {
681+
meta: new_meta,
682+
filename: meta.filename,
683+
range: meta.range,
684+
})]
685+
} else {
686+
vec![Block::BlockMetadata(MetaBlock {
687+
meta: topdown_traverse_meta(new_meta, filter),
688+
filename: meta.filename,
689+
range: meta.range,
690+
})]
691+
}
692+
}
693+
};
694+
}
695+
vec![Block::BlockMetadata(meta)]
696+
}
660697
}
661698
}
662699

@@ -962,40 +999,8 @@ pub fn topdown_traverse_meta(meta: Meta, filter: &mut Filter) -> Meta {
962999
}
9631000

9641001
pub fn topdown_traverse(doc: pandoc::Pandoc, filter: &mut Filter) -> pandoc::Pandoc {
965-
let (real_blocks, meta_blocks): (Vec<Block>, Vec<Block>) = doc
966-
.blocks
967-
.into_iter()
968-
.partition(|b| !matches!(b, Block::RawBlock(rb) if rb.format == "quarto_minus_metadata"));
969-
970-
let mut meta = Meta::default();
971-
let mut meta_from_parses = Meta::default();
972-
meta_blocks.into_iter().for_each(|b| match b {
973-
Block::RawBlock(rb) if rb.format == "quarto_minus_metadata" => {
974-
let Some(result) = rawblock_to_meta(rb) else {
975-
return;
976-
};
977-
let meta_map = MetaValue::MetaMap(result);
978-
979-
match parse_metadata_strings(meta_map, &mut meta_from_parses) {
980-
MetaValue::MetaMap(m) => {
981-
for (k, v) in m {
982-
meta.insert(k, v);
983-
}
984-
}
985-
_ => panic!("Expected MetaMap from parse_metadata_strings"),
986-
}
987-
}
988-
_ => {}
989-
});
990-
for (k, v) in meta_from_parses {
991-
if !meta.contains_key(&k) {
992-
meta.insert(k, v);
993-
}
994-
}
995-
9961002
pandoc::Pandoc {
997-
meta: topdown_traverse_meta(meta, filter),
998-
blocks: topdown_traverse_blocks(real_blocks, filter),
999-
// TODO: handle meta
1003+
meta: topdown_traverse_meta(doc.meta, filter),
1004+
blocks: topdown_traverse_blocks(doc.blocks, filter),
10001005
}
10011006
}

crates/quarto_markdown_pandoc/src/pandoc/block.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
use crate::impl_source_location;
7+
use crate::pandoc::Meta;
78
use crate::pandoc::attr::Attr;
89
use crate::pandoc::caption::Caption;
910
use crate::pandoc::inline::Inlines;
@@ -29,6 +30,8 @@ pub enum Block {
2930
Table(Table),
3031
Figure(Figure),
3132
Div(Div),
33+
// quarto extensions
34+
BlockMetadata(MetaBlock),
3235
}
3336

3437
pub type Blocks = Vec<Block>;
@@ -143,6 +146,14 @@ pub struct Div {
143146
pub range: Range,
144147
}
145148

149+
#[derive(Debug, Clone, PartialEq)]
150+
pub struct MetaBlock {
151+
pub meta: Meta,
152+
153+
pub filename: Option<String>,
154+
pub range: Range,
155+
}
156+
146157
impl_source_location!(
147158
// blocks
148159
Plain,
@@ -158,7 +169,9 @@ impl_source_location!(
158169
HorizontalRule,
159170
Table,
160171
Figure,
161-
Div
172+
Div,
173+
// quarto extensions
174+
MetaBlock
162175
);
163176

164177
fn make_block_leftover(node: &tree_sitter::Node, input_bytes: &[u8]) -> Block {

crates/quarto_markdown_pandoc/src/pandoc/meta.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,24 @@ impl MarkedEventReceiver for YamlEventHandler {
131131
}
132132
}
133133

134-
pub fn rawblock_to_meta(block: RawBlock) -> Option<Meta> {
134+
pub fn rawblock_to_meta(block: RawBlock) -> Meta {
135135
if block.format != "quarto_minus_metadata" {
136-
return None;
136+
panic!(
137+
"Expected RawBlock with format 'quarto_minus_metadata', got {}",
138+
block.format
139+
);
137140
}
138-
let content = extract_between_delimiters(&block.text)?;
141+
let content = extract_between_delimiters(&block.text).unwrap();
139142
let mut parser = Parser::new_from_str(content);
140143
let mut handler = YamlEventHandler::new();
141-
let _parse_result = parser.load(&mut handler, false);
142-
143-
handler.result
144+
let parse_result = parser.load(&mut handler, false);
145+
if parse_result.is_err() {
146+
panic!(
147+
"(unimplemented syntax error - this is a bug!) Failed to parse metadata block as YAML: {:?}",
148+
parse_result.err()
149+
);
150+
}
151+
handler.result.unwrap()
144152
}
145153

146154
pub fn parse_metadata_strings(meta: MetaValue, outer_metadata: &mut Meta) -> MetaValue {

crates/quarto_markdown_pandoc/src/readers/qmd.rs

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
use crate::errors;
22
use crate::errors::parse_is_good;
3-
use crate::pandoc;
3+
use crate::filters::FilterReturn::Unchanged;
4+
use crate::filters::topdown_traverse;
5+
use crate::filters::{Filter, FilterReturn};
6+
use crate::pandoc::block::MetaBlock;
7+
use crate::pandoc::meta::parse_metadata_strings;
8+
use crate::pandoc::{self, Block, Meta};
9+
use crate::pandoc::{MetaValue, rawblock_to_meta};
410
use crate::traversals;
511
use std::io::Write;
612
// use tree_sitter::LogType;
@@ -67,9 +73,64 @@ pub fn read<T: Write>(
6773
return Err(error_messages);
6874
}
6975

70-
// // repeat this 100 times to get profiling data
71-
// for _ in 0..100 {
72-
// let _ = pandoc::treesitter::treesitter_to_pandoc(&mut output_stream, &tree, &input_bytes);
73-
// }
74-
pandoc::treesitter_to_pandoc(&mut output_stream, &tree, &input_bytes)
76+
let mut result = pandoc::treesitter_to_pandoc(&mut output_stream, &tree, &input_bytes)?;
77+
let mut meta_from_parses = Meta::default();
78+
79+
eprintln!("Hello?");
80+
eprintln!("{:?}", result);
81+
82+
result = {
83+
let mut filter = Filter::new().with_raw_block(|rb| {
84+
eprintln!("raw block: {:?}", rb);
85+
if rb.format != "quarto_minus_metadata" {
86+
return Unchanged(rb);
87+
}
88+
let filename = rb.filename.clone();
89+
let range = rb.range.clone();
90+
let result = rawblock_to_meta(rb);
91+
let is_lexical = {
92+
let val = result.get("_scope");
93+
matches!(val, Some(MetaValue::MetaString(s)) if s == "lexical")
94+
};
95+
96+
if is_lexical {
97+
let mut inner_meta_from_parses = Meta::default();
98+
let mut meta_map = match parse_metadata_strings(
99+
MetaValue::MetaMap(result),
100+
&mut inner_meta_from_parses,
101+
) {
102+
MetaValue::MetaMap(m) => m,
103+
_ => panic!("Expected MetaMap from parse_metadata_strings"),
104+
};
105+
for (k, v) in inner_meta_from_parses {
106+
meta_map.insert(k, v);
107+
}
108+
return FilterReturn::FilterResult(
109+
vec![Block::BlockMetadata(MetaBlock {
110+
meta: meta_map,
111+
filename,
112+
range,
113+
})],
114+
false,
115+
);
116+
} else {
117+
let meta_map =
118+
match parse_metadata_strings(MetaValue::MetaMap(result), &mut meta_from_parses)
119+
{
120+
MetaValue::MetaMap(m) => m,
121+
_ => panic!("Expected MetaMap from parse_metadata_strings"),
122+
};
123+
for (k, v) in meta_map {
124+
meta_from_parses.insert(k, v);
125+
}
126+
return FilterReturn::FilterResult(vec![], false);
127+
}
128+
});
129+
topdown_traverse(result, &mut filter)
130+
};
131+
for (k, v) in meta_from_parses.into_iter() {
132+
result.meta.insert(k, v);
133+
}
134+
eprintln!("result\n{:?}", result);
135+
Ok(result)
75136
}

crates/quarto_markdown_pandoc/src/writers/json.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
use crate::pandoc::{Attr, Block, Caption, CitationMode, Inline, Inlines, ListAttributes, Pandoc};
77
use crate::utils::autoid;
8+
use crate::writers::json;
89
use serde_json::{Value, json};
910

1011
fn write_location<T: crate::pandoc::location::SourceLocation>(item: &T) -> Value {
@@ -278,17 +279,59 @@ fn write_block(block: &Block) -> Value {
278279
"c": bulletlist.content.iter().map(|blocks| blocks.iter().map(write_block).collect::<Vec<_>>()).collect::<Vec<_>>(),
279280
"l": write_location(bulletlist),
280281
}),
282+
Block::BlockMetadata(meta) => json!({
283+
"t": "BlockMetadata",
284+
"c": write_meta(&meta.meta),
285+
"l": write_location(meta),
286+
}),
287+
}
288+
}
289+
290+
fn write_meta_value(value: &crate::pandoc::MetaValue) -> Value {
291+
match value {
292+
crate::pandoc::MetaValue::MetaString(s) => json!({
293+
"t": "MetaString",
294+
"c": s
295+
}),
296+
crate::pandoc::MetaValue::MetaInlines(inlines) => json!({
297+
"t": "MetaInlines",
298+
"c": write_inlines(inlines)
299+
}),
300+
crate::pandoc::MetaValue::MetaBlocks(blocks) => json!({
301+
"t": "MetaBlocks",
302+
"c": write_blocks(blocks)
303+
}),
304+
crate::pandoc::MetaValue::MetaList(list) => json!({
305+
"t": "MetaList",
306+
"c": list.iter().map(write_meta_value).collect::<Vec<_>>()
307+
}),
308+
crate::pandoc::MetaValue::MetaMap(map) => json!({
309+
"t": "MetaMap",
310+
"c": map.iter().map(|(k, v)| json!([k, write_meta_value(v)])).collect::<Vec<_>>()
311+
}),
312+
crate::pandoc::MetaValue::MetaBool(b) => json!({
313+
"t": "MetaBool",
314+
"c": b
315+
}),
281316
}
282317
}
283318

319+
fn write_meta(meta: &crate::pandoc::Meta) -> Value {
320+
let map: serde_json::Map<String, Value> = meta
321+
.iter()
322+
.map(|(k, v)| (k.clone(), write_meta_value(v)))
323+
.collect();
324+
Value::Object(map)
325+
}
326+
284327
fn write_blocks(blocks: &[Block]) -> Value {
285328
json!(blocks.iter().map(write_block).collect::<Vec<_>>())
286329
}
287330

288331
fn write_pandoc(pandoc: &Pandoc) -> Value {
289332
json!({
290333
"pandoc-api-version": [1, 23, 1],
291-
"meta": {},
334+
"meta": write_meta(&pandoc.meta),
292335
"blocks": write_blocks(&pandoc.blocks),
293336
})
294337
}

crates/quarto_markdown_pandoc/src/writers/native.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ fn write_block<T: std::io::Write>(block: &Block, buf: &mut T) -> std::io::Result
563563
write!(buf, "] ")?;
564564
write_native_table_foot(foot, buf)?;
565565
}
566-
_ => panic!("Unsupported block type: {:?}", block),
566+
_ => panic!("Unsupported block type in native writer: {:?}", block),
567567
}
568568
Ok(())
569569
}

0 commit comments

Comments
 (0)