@@ -132,6 +132,8 @@ pub struct SharedContext {
132132 /// This flag indicates whether listings of modules (in the side bar and documentation itself)
133133 /// should be ordered alphabetically or in order of appearance (in the source code).
134134 pub sort_modules_alphabetically : bool ,
135+ /// Additional themes to be added to the generated docs.
136+ pub themes : Vec < PathBuf > ,
135137}
136138
137139impl SharedContext {
@@ -219,6 +221,17 @@ impl Error {
219221 }
220222}
221223
224+ macro_rules! try_none {
225+ ( $e: expr, $file: expr) => ( {
226+ use std:: io;
227+ match $e {
228+ Some ( e) => e,
229+ None => return Err ( Error :: new( io:: Error :: new( io:: ErrorKind :: Other , "not found" ) ,
230+ $file) )
231+ }
232+ } )
233+ }
234+
222235macro_rules! try_err {
223236 ( $e: expr, $file: expr) => ( {
224237 match $e {
@@ -489,7 +502,8 @@ pub fn run(mut krate: clean::Crate,
489502 renderinfo : RenderInfo ,
490503 render_type : RenderType ,
491504 sort_modules_alphabetically : bool ,
492- deny_render_differences : bool ) -> Result < ( ) , Error > {
505+ deny_render_differences : bool ,
506+ themes : Vec < PathBuf > ) -> Result < ( ) , Error > {
493507 let src_root = match krate. src {
494508 FileName :: Real ( ref p) => match p. parent ( ) {
495509 Some ( p) => p. to_path_buf ( ) ,
@@ -513,6 +527,7 @@ pub fn run(mut krate: clean::Crate,
513527 markdown_warnings : RefCell :: new ( vec ! [ ] ) ,
514528 created_dirs : RefCell :: new ( FxHashSet ( ) ) ,
515529 sort_modules_alphabetically,
530+ themes,
516531 } ;
517532
518533 // If user passed in `--playground-url` arg, we fill in crate name here
@@ -859,12 +874,65 @@ fn write_shared(cx: &Context,
859874 // Add all the static files. These may already exist, but we just
860875 // overwrite them anyway to make sure that they're fresh and up-to-date.
861876
862- write ( cx. dst . join ( "main.js" ) ,
863- include_bytes ! ( "static/main.js" ) ) ?;
864877 write ( cx. dst . join ( "rustdoc.css" ) ,
865878 include_bytes ! ( "static/rustdoc.css" ) ) ?;
879+
880+ // To avoid "main.css" to be overwritten, we'll first run over the received themes and only
881+ // then we'll run over the "official" styles.
882+ let mut themes: HashSet < String > = HashSet :: new ( ) ;
883+
884+ for entry in & cx. shared . themes {
885+ let mut content = Vec :: with_capacity ( 100000 ) ;
886+
887+ let mut f = try_err ! ( File :: open( & entry) , & entry) ;
888+ try_err ! ( f. read_to_end( & mut content) , & entry) ;
889+ write ( cx. dst . join ( try_none ! ( entry. file_name( ) , & entry) ) , content. as_slice ( ) ) ?;
890+ themes. insert ( try_none ! ( try_none!( entry. file_stem( ) , & entry) . to_str( ) , & entry) . to_owned ( ) ) ;
891+ }
892+
893+ write ( cx. dst . join ( "brush.svg" ) ,
894+ include_bytes ! ( "static/brush.svg" ) ) ?;
866895 write ( cx. dst . join ( "main.css" ) ,
867- include_bytes ! ( "static/styles/main.css" ) ) ?;
896+ include_bytes ! ( "static/themes/main.css" ) ) ?;
897+ themes. insert ( "main" . to_owned ( ) ) ;
898+ write ( cx. dst . join ( "dark.css" ) ,
899+ include_bytes ! ( "static/themes/dark.css" ) ) ?;
900+ themes. insert ( "dark" . to_owned ( ) ) ;
901+
902+ let mut themes: Vec < & String > = themes. iter ( ) . collect ( ) ;
903+ themes. sort ( ) ;
904+ // To avoid theme switch latencies as much as possible, we put everything theme related
905+ // at the beginning of the html files into another js file.
906+ write ( cx. dst . join ( "theme.js" ) , format ! (
907+ r#"var themes = document.getElementById("theme-choices");
908+ var themePicker = document.getElementById("theme-picker");
909+ themePicker.onclick = function() {{
910+ if (themes.style.display === "block") {{
911+ themes.style.display = "none";
912+ themePicker.style.borderBottomRightRadius = "3px";
913+ themePicker.style.borderBottomLeftRadius = "3px";
914+ }} else {{
915+ themes.style.display = "block";
916+ themePicker.style.borderBottomRightRadius = "0";
917+ themePicker.style.borderBottomLeftRadius = "0";
918+ }}
919+ }};
920+ [{}].forEach(function(item) {{
921+ var div = document.createElement('div');
922+ div.innerHTML = item;
923+ div.onclick = function(el) {{
924+ switchTheme(currentTheme, mainTheme, item);
925+ }};
926+ themes.appendChild(div);
927+ }});
928+ "# , themes. iter( )
929+ . map( |s| format!( "\" {}\" " , s) )
930+ . collect:: <Vec <String >>( )
931+ . join( "," ) ) . as_bytes ( ) ) ?;
932+
933+ write ( cx. dst . join ( "main.js" ) , include_bytes ! ( "static/main.js" ) ) ?;
934+ write ( cx. dst . join ( "storage.js" ) , include_bytes ! ( "static/storage.js" ) ) ?;
935+
868936 if let Some ( ref css) = cx. shared . css_file_extension {
869937 let out = cx. dst . join ( "theme.css" ) ;
870938 try_err ! ( fs:: copy( css, out) , css) ;
@@ -1156,7 +1224,8 @@ impl<'a> SourceCollector<'a> {
11561224 } ;
11571225 layout:: render ( & mut w, & self . scx . layout ,
11581226 & page, & ( "" ) , & Source ( contents) ,
1159- self . scx . css_file_extension . is_some ( ) ) ?;
1227+ self . scx . css_file_extension . is_some ( ) ,
1228+ & self . scx . themes ) ?;
11601229 w. flush ( ) ?;
11611230 self . scx . local_sources . insert ( p. clone ( ) , href) ;
11621231 Ok ( ( ) )
@@ -1520,7 +1589,8 @@ impl Context {
15201589 layout:: render ( writer, & self . shared . layout , & page,
15211590 & Sidebar { cx : self , item : it } ,
15221591 & Item { cx : self , item : it } ,
1523- self . shared . css_file_extension . is_some ( ) ) ?;
1592+ self . shared . css_file_extension . is_some ( ) ,
1593+ & self . shared . themes ) ?;
15241594 } else {
15251595 let mut url = self . root_path ( ) ;
15261596 if let Some ( & ( ref names, ty) ) = cache ( ) . paths . get ( & it. def_id ) {
0 commit comments