@@ -5,6 +5,7 @@ use crate::builtin_renderers::{CmdRenderer, MarkdownRenderer};
55use crate :: init:: BookBuilder ;
66use crate :: load:: { load_book, load_book_from_disk} ;
77use anyhow:: { Context , Error , Result , bail} ;
8+ use indexmap:: IndexMap ;
89use log:: { debug, error, info, log_enabled, trace, warn} ;
910use mdbook_core:: book:: { Book , BookItem , BookItems } ;
1011use mdbook_core:: config:: { Config , RustEdition } ;
@@ -28,14 +29,18 @@ mod tests;
2829pub struct MDBook {
2930 /// The book's root directory.
3031 pub root : PathBuf ,
32+
3133 /// The configuration used to tweak now a book is built.
3234 pub config : Config ,
35+
3336 /// A representation of the book's contents in memory.
3437 pub book : Book ,
35- renderers : Vec < Box < dyn Renderer > > ,
3638
37- /// List of pre-processors to be run on the book.
38- preprocessors : Vec < Box < dyn Preprocessor > > ,
39+ /// Renderers to execute.
40+ renderers : IndexMap < String , Box < dyn Renderer > > ,
41+
42+ /// Pre-processors to be run on the book.
43+ preprocessors : IndexMap < String , Box < dyn Preprocessor > > ,
3944}
4045
4146impl MDBook {
@@ -156,7 +161,7 @@ impl MDBook {
156161 pub fn build ( & self ) -> Result < ( ) > {
157162 info ! ( "Book building has started" ) ;
158163
159- for renderer in & self . renderers {
164+ for renderer in self . renderers . values ( ) {
160165 self . execute_build_process ( & * * renderer) ?;
161166 }
162167
@@ -171,7 +176,7 @@ impl MDBook {
171176 renderer. name ( ) . to_string ( ) ,
172177 ) ;
173178 let mut preprocessed_book = self . book . clone ( ) ;
174- for preprocessor in & self . preprocessors {
179+ for preprocessor in self . preprocessors . values ( ) {
175180 if preprocessor_should_run ( & * * preprocessor, renderer, & self . config ) ? {
176181 debug ! ( "Running the {} preprocessor." , preprocessor. name( ) ) ;
177182 preprocessed_book = preprocessor. run ( & preprocess_ctx, preprocessed_book) ?;
@@ -207,13 +212,15 @@ impl MDBook {
207212 /// The only requirement is that your renderer implement the [`Renderer`]
208213 /// trait.
209214 pub fn with_renderer < R : Renderer + ' static > ( & mut self , renderer : R ) -> & mut Self {
210- self . renderers . push ( Box :: new ( renderer) ) ;
215+ self . renderers
216+ . insert ( renderer. name ( ) . to_string ( ) , Box :: new ( renderer) ) ;
211217 self
212218 }
213219
214220 /// Register a [`Preprocessor`] to be used when rendering the book.
215221 pub fn with_preprocessor < P : Preprocessor + ' static > ( & mut self , preprocessor : P ) -> & mut Self {
216- self . preprocessors . push ( Box :: new ( preprocessor) ) ;
222+ self . preprocessors
223+ . insert ( preprocessor. name ( ) . to_string ( ) , Box :: new ( preprocessor) ) ;
217224 self
218225 }
219226
@@ -258,10 +265,9 @@ impl MDBook {
258265
259266 // Index Preprocessor is disabled so that chapter paths
260267 // continue to point to the actual markdown files.
261- self . preprocessors = determine_preprocessors ( & self . config , & self . root ) ?
262- . into_iter ( )
263- . filter ( |pre| pre. name ( ) != IndexPreprocessor :: NAME )
264- . collect ( ) ;
268+ self . preprocessors = determine_preprocessors ( & self . config , & self . root ) ?;
269+ self . preprocessors
270+ . shift_remove_entry ( IndexPreprocessor :: NAME ) ;
265271 let ( book, _) = self . preprocess_book ( & TestRenderer ) ?;
266272
267273 let color_output = std:: io:: stderr ( ) . is_terminal ( ) ;
@@ -399,24 +405,25 @@ struct OutputConfig {
399405}
400406
401407/// Look at the `Config` and try to figure out what renderers to use.
402- fn determine_renderers ( config : & Config ) -> Result < Vec < Box < dyn Renderer > > > {
403- let mut renderers = Vec :: new ( ) ;
408+ fn determine_renderers ( config : & Config ) -> Result < IndexMap < String , Box < dyn Renderer > > > {
409+ let mut renderers = IndexMap :: new ( ) ;
404410
405411 let outputs = config. outputs :: < OutputConfig > ( ) ?;
406412 renderers. extend ( outputs. into_iter ( ) . map ( |( key, table) | {
407- if key == "html" {
413+ let renderer = if key == "html" {
408414 Box :: new ( HtmlHandlebars :: new ( ) ) as Box < dyn Renderer >
409415 } else if key == "markdown" {
410416 Box :: new ( MarkdownRenderer :: new ( ) ) as Box < dyn Renderer >
411417 } else {
412418 let command = table. command . unwrap_or_else ( || format ! ( "mdbook-{key}" ) ) ;
413- Box :: new ( CmdRenderer :: new ( key, command) )
414- }
419+ Box :: new ( CmdRenderer :: new ( key. clone ( ) , command) )
420+ } ;
421+ ( key, renderer)
415422 } ) ) ;
416423
417424 // if we couldn't find anything, add the HTML renderer as a default
418425 if renderers. is_empty ( ) {
419- renderers. push ( Box :: new ( HtmlHandlebars :: new ( ) ) ) ;
426+ renderers. insert ( "html" . to_string ( ) , Box :: new ( HtmlHandlebars :: new ( ) ) ) ;
420427 }
421428
422429 Ok ( renderers)
@@ -442,7 +449,10 @@ struct PreprocessorConfig {
442449}
443450
444451/// Look at the `MDBook` and try to figure out what preprocessors to run.
445- fn determine_preprocessors ( config : & Config , root : & Path ) -> Result < Vec < Box < dyn Preprocessor > > > {
452+ fn determine_preprocessors (
453+ config : & Config ,
454+ root : & Path ,
455+ ) -> Result < IndexMap < String , Box < dyn Preprocessor > > > {
446456 // Collect the names of all preprocessors intended to be run, and the order
447457 // in which they should be run.
448458 let mut preprocessor_names = TopologicalSort :: < String > :: new ( ) ;
@@ -490,7 +500,7 @@ fn determine_preprocessors(config: &Config, root: &Path) -> Result<Vec<Box<dyn P
490500 }
491501
492502 // Now that all links have been established, queue preprocessors in a suitable order
493- let mut preprocessors = Vec :: with_capacity ( preprocessor_names. len ( ) ) ;
503+ let mut preprocessors = IndexMap :: with_capacity ( preprocessor_names. len ( ) ) ;
494504 // `pop_all()` returns an empty vector when no more items are not being depended upon
495505 for mut names in std:: iter:: repeat_with ( || preprocessor_names. pop_all ( ) )
496506 . take_while ( |names| !names. is_empty ( ) )
@@ -516,14 +526,14 @@ fn determine_preprocessors(config: &Config, root: &Path) -> Result<Vec<Box<dyn P
516526 . to_owned ( )
517527 . unwrap_or_else ( || format ! ( "mdbook-{name}" ) ) ;
518528 Box :: new ( CmdPreprocessor :: new (
519- name,
529+ name. clone ( ) ,
520530 command,
521531 root. to_owned ( ) ,
522532 table. optional ,
523533 ) )
524534 }
525535 } ;
526- preprocessors. push ( preprocessor) ;
536+ preprocessors. insert ( name , preprocessor) ;
527537 }
528538 }
529539
0 commit comments