33 * Copyright (c) 2025 Posit, PBC
44 */
55
6+ use crate :: pandoc:: MetaValue ;
67use crate :: pandoc:: inline:: AsInline ;
78use crate :: pandoc:: meta:: Meta ;
9+ use crate :: pandoc:: meta:: parse_metadata_strings;
810use crate :: pandoc:: meta:: rawblock_to_meta;
911use crate :: pandoc:: { self , Block , Blocks , Inline , Inlines } ;
1012
@@ -17,8 +19,10 @@ pub enum FilterReturn<T, U> {
1719
1820type InlineFilterFn < ' a , T > = Box < dyn FnMut ( T ) -> FilterReturn < T , Inlines > + ' a > ;
1921type BlockFilterFn < ' a , T > = Box < dyn FnMut ( T ) -> FilterReturn < T , Blocks > + ' a > ;
22+ type MetaFilterFn < ' a > = Box < dyn FnMut ( Meta ) -> FilterReturn < Meta , Meta > + ' a > ;
2023type InlineFilterField < ' a , T > = Option < InlineFilterFn < ' a , T > > ;
2124type BlockFilterField < ' a , T > = Option < BlockFilterFn < ' a , T > > ;
25+ type MetaFilterField < ' a > = Option < MetaFilterFn < ' a > > ;
2226
2327pub struct Filter < ' a > {
2428 pub inlines : InlineFilterField < ' a , Inlines > ,
@@ -65,6 +69,8 @@ pub struct Filter<'a> {
6569 pub header : BlockFilterField < ' a , pandoc:: Header > ,
6670 pub table : BlockFilterField < ' a , pandoc:: Table > ,
6771 pub horizontal_rule : BlockFilterField < ' a , pandoc:: HorizontalRule > ,
72+
73+ pub meta : MetaFilterField < ' a > ,
6874}
6975
7076impl Default for Filter < ' static > {
@@ -113,6 +119,8 @@ impl Default for Filter<'static> {
113119 table : None ,
114120 horizontal_rule : None ,
115121 attr : None ,
122+
123+ meta : None ,
116124 }
117125 }
118126}
@@ -910,21 +918,83 @@ pub fn topdown_traverse_blocks(vec: Blocks, filter: &mut Filter) -> Blocks {
910918 }
911919}
912920
921+ pub fn topdown_traverse_meta_value ( value : MetaValue , filter : & mut Filter ) -> MetaValue {
922+ match value {
923+ MetaValue :: MetaMap ( m) => MetaValue :: MetaMap (
924+ m. into_iter ( )
925+ . map ( |( k, v) | ( k, topdown_traverse_meta_value ( v, filter) ) )
926+ . collect ( ) ,
927+ ) ,
928+ MetaValue :: MetaList ( l) => MetaValue :: MetaList (
929+ l. into_iter ( )
930+ . map ( |mv| topdown_traverse_meta_value ( mv, filter) )
931+ . collect ( ) ,
932+ ) ,
933+ MetaValue :: MetaBlocks ( b) => MetaValue :: MetaBlocks ( topdown_traverse_blocks ( b, filter) ) ,
934+ MetaValue :: MetaInlines ( i) => MetaValue :: MetaInlines ( topdown_traverse_inlines ( i, filter) ) ,
935+ value => value,
936+ }
937+ }
938+
939+ pub fn topdown_traverse_meta ( meta : Meta , filter : & mut Filter ) -> Meta {
940+ if let Some ( f) = & mut filter. meta {
941+ return match f ( meta) {
942+ FilterReturn :: FilterResult ( new_meta, recurse) => {
943+ if !recurse {
944+ return new_meta;
945+ }
946+ topdown_traverse_meta ( new_meta, filter)
947+ }
948+ FilterReturn :: Unchanged ( m) => {
949+ let meta_value = MetaValue :: MetaMap ( m) ;
950+ match topdown_traverse_meta_value ( meta_value, filter) {
951+ MetaValue :: MetaMap ( m) => m,
952+ _ => panic ! ( "Expected MetaMap after filtering meta" ) ,
953+ }
954+ }
955+ } ;
956+ } else {
957+ return meta
958+ . into_iter ( )
959+ . map ( |( k, v) | ( k, topdown_traverse_meta_value ( v, filter) ) )
960+ . collect ( ) ;
961+ }
962+ }
963+
913964pub fn topdown_traverse ( doc : pandoc:: Pandoc , filter : & mut Filter ) -> pandoc:: Pandoc {
914965 let ( real_blocks, meta_blocks) : ( Vec < Block > , Vec < Block > ) = doc
915966 . blocks
916967 . into_iter ( )
917968 . partition ( |b| !matches ! ( b, Block :: RawBlock ( rb) if rb. format == "quarto_minus_metadata" ) ) ;
918969
970+ let mut meta = Meta :: default ( ) ;
971+ let mut meta_from_parses = Meta :: default ( ) ;
919972 meta_blocks. into_iter ( ) . for_each ( |b| match b {
920973 Block :: RawBlock ( rb) if rb. format == "quarto_minus_metadata" => {
921- rawblock_to_meta ( rb) ;
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+ }
922987 }
923988 _ => { }
924989 } ) ;
990+ for ( k, v) in meta_from_parses {
991+ if !meta. contains_key ( & k) {
992+ meta. insert ( k, v) ;
993+ }
994+ }
925995
926996 pandoc:: Pandoc {
927- meta : Meta :: default ( ) ,
997+ meta : topdown_traverse_meta ( meta , filter ) ,
928998 blocks : topdown_traverse_blocks ( real_blocks, filter) ,
929999 // TODO: handle meta
9301000 }
0 commit comments