@@ -39,8 +39,8 @@ pub type MarkdownEvents<'a> = Vec<Event<'a>>;
39
39
/// converted to regular markdown syntax.
40
40
///
41
41
/// Postprocessors are called in the order they've been added through [Exporter::add_postprocessor]
42
- /// just before notes are written out to their final destination.
43
- /// They may be used to achieve the following:
42
+ /// or [Exporter::add_postprocessor_impl] just before notes are written out to their final
43
+ /// destination. They may be used to achieve the following:
44
44
///
45
45
/// 1. Modify a note's [Context], for example to change the destination filename or update its [Frontmatter] (see [Context::frontmatter]).
46
46
/// 2. Change a note's contents by altering [MarkdownEvents].
@@ -54,7 +54,7 @@ pub type MarkdownEvents<'a> = Vec<Event<'a>>;
54
54
///
55
55
/// In some cases it may be desirable to change the contents of these embedded notes *before* they
56
56
/// are inserted into the final document. This is possible through the use of
57
- /// [Exporter::add_embed_postprocessor].
57
+ /// [Exporter::add_embed_postprocessor] or [Exporter::add_embed_postprocessor_impl] .
58
58
/// These "embed postprocessors" run much the same way as regular postprocessors, but they're run on
59
59
/// the note that is about to be embedded in another note. In addition:
60
60
///
@@ -137,6 +137,22 @@ pub type Postprocessor<'f> =
137
137
dyn Fn ( & mut Context , & mut MarkdownEvents ) -> PostprocessorResult + Send + Sync + ' f ;
138
138
type Result < T , E = ExportError > = std:: result:: Result < T , E > ;
139
139
140
+ /// Postprocess is a trait form of the [Postprocessor] callback that can be passed to
141
+ /// [Exporter::add_postprocessor_impl].
142
+ pub trait Postprocess : Send + Sync {
143
+ fn postprocess ( & self , ctx : & mut Context , events : & mut MarkdownEvents ) -> PostprocessorResult ;
144
+ }
145
+
146
+ /// EmbedPostprocess is a trait form of the [Postprocessor] callback that can be
147
+ /// passed to [Exporter::add_embed_postprocessor_impl].
148
+ pub trait EmbedPostprocess : Send + Sync {
149
+ fn embed_postprocess (
150
+ & self ,
151
+ ctx : & mut Context ,
152
+ events : & mut MarkdownEvents ,
153
+ ) -> PostprocessorResult ;
154
+ }
155
+
140
156
const PERCENTENCODE_CHARS : & AsciiSet = & CONTROLS . add ( b' ' ) . add ( b'(' ) . add ( b')' ) . add ( b'%' ) . add ( b'?' ) ;
141
157
const NOTE_RECURSION_LIMIT : usize = 10 ;
142
158
@@ -216,6 +232,23 @@ pub enum PostprocessorResult {
216
232
StopAndSkipNote ,
217
233
}
218
234
235
+ #[ derive( Clone ) ]
236
+ enum PostprocessorRef < ' p > {
237
+ Function ( & ' p Postprocessor < ' p > ) ,
238
+ Trait ( & ' p dyn Postprocess ) ,
239
+ EmbedTrait ( & ' p dyn EmbedPostprocess ) ,
240
+ }
241
+
242
+ impl < ' p > PostprocessorRef < ' p > {
243
+ fn call ( & ' p self , ctx : & mut Context , events : & mut MarkdownEvents ) -> PostprocessorResult {
244
+ match self {
245
+ PostprocessorRef :: Function ( f) => f ( ctx, events) ,
246
+ PostprocessorRef :: Trait ( t) => t. postprocess ( ctx, events) ,
247
+ PostprocessorRef :: EmbedTrait ( t) => t. embed_postprocess ( ctx, events) ,
248
+ }
249
+ }
250
+ }
251
+
219
252
#[ derive( Clone ) ]
220
253
/// Exporter provides the main interface to this library.
221
254
///
@@ -231,8 +264,8 @@ pub struct Exporter<'a> {
231
264
vault_contents : Option < Vec < PathBuf > > ,
232
265
walk_options : WalkOptions < ' a > ,
233
266
process_embeds_recursively : bool ,
234
- postprocessors : Vec < & ' a Postprocessor < ' a > > ,
235
- embed_postprocessors : Vec < & ' a Postprocessor < ' a > > ,
267
+ postprocessors : Vec < PostprocessorRef < ' a > > ,
268
+ embed_postprocessors : Vec < PostprocessorRef < ' a > > ,
236
269
}
237
270
238
271
impl < ' a > fmt:: Debug for Exporter < ' a > {
@@ -315,13 +348,33 @@ impl<'a> Exporter<'a> {
315
348
316
349
/// Append a function to the chain of [postprocessors][Postprocessor] to run on exported Obsidian Markdown notes.
317
350
pub fn add_postprocessor ( & mut self , processor : & ' a Postprocessor ) -> & mut Exporter < ' a > {
318
- self . postprocessors . push ( processor) ;
351
+ self . postprocessors
352
+ . push ( PostprocessorRef :: Function ( processor) ) ;
353
+ self
354
+ }
355
+
356
+ /// Append a trait implementation of [Postprocess] to the chain of [postprocessors] to run on
357
+ /// Obsidian Markdown notes.
358
+ pub fn add_postprocessor_impl ( & mut self , processor : & ' a dyn Postprocess ) -> & mut Exporter < ' a > {
359
+ self . postprocessors . push ( PostprocessorRef :: Trait ( processor) ) ;
319
360
self
320
361
}
321
362
322
363
/// Append a function to the chain of [postprocessors][Postprocessor] for embeds.
323
364
pub fn add_embed_postprocessor ( & mut self , processor : & ' a Postprocessor ) -> & mut Exporter < ' a > {
324
- self . embed_postprocessors . push ( processor) ;
365
+ self . embed_postprocessors
366
+ . push ( PostprocessorRef :: Function ( processor) ) ;
367
+ self
368
+ }
369
+
370
+ /// Append a trait implementation of [EmbedPostprocess] to the chain of [postprocessors] for
371
+ /// embeds.
372
+ pub fn add_embed_postprocessor_impl (
373
+ & mut self ,
374
+ processor : & ' a dyn EmbedPostprocess ,
375
+ ) -> & mut Exporter < ' a > {
376
+ self . embed_postprocessors
377
+ . push ( PostprocessorRef :: EmbedTrait ( processor) ) ;
325
378
self
326
379
}
327
380
@@ -400,8 +453,8 @@ impl<'a> Exporter<'a> {
400
453
401
454
let ( frontmatter, mut markdown_events) = self . parse_obsidian_note ( src, & context) ?;
402
455
context. frontmatter = frontmatter;
403
- for func in & self . postprocessors {
404
- match func ( & mut context, & mut markdown_events) {
456
+ for processor in & self . postprocessors {
457
+ match processor . call ( & mut context, & mut markdown_events) {
405
458
PostprocessorResult :: StopHere => break ,
406
459
PostprocessorResult :: StopAndSkipNote => return Ok ( ( ) ) ,
407
460
PostprocessorResult :: Continue => ( ) ,
@@ -603,10 +656,10 @@ impl<'a> Exporter<'a> {
603
656
if let Some ( section) = note_ref. section {
604
657
events = reduce_to_section ( events, section) ;
605
658
}
606
- for func in & self . embed_postprocessors {
659
+ for processor in & self . embed_postprocessors {
607
660
// Postprocessors running on embeds shouldn't be able to change frontmatter (or
608
661
// any other metadata), so we give them a clone of the context.
609
- match func ( & mut child_context, & mut events) {
662
+ match processor . call ( & mut child_context, & mut events) {
610
663
PostprocessorResult :: StopHere => break ,
611
664
PostprocessorResult :: StopAndSkipNote => {
612
665
events = vec ! [ ] ;
0 commit comments