@@ -132,6 +132,8 @@ pub struct SharedContext {
132
132
/// This flag indicates whether listings of modules (in the side bar and documentation itself)
133
133
/// should be ordered alphabetically or in order of appearance (in the source code).
134
134
pub sort_modules_alphabetically : bool ,
135
+ /// Additional themes to be added to the generated docs.
136
+ pub themes : Vec < PathBuf > ,
135
137
}
136
138
137
139
impl SharedContext {
@@ -219,6 +221,17 @@ impl Error {
219
221
}
220
222
}
221
223
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
+
222
235
macro_rules! try_err {
223
236
( $e: expr, $file: expr) => ( {
224
237
match $e {
@@ -489,7 +502,8 @@ pub fn run(mut krate: clean::Crate,
489
502
renderinfo : RenderInfo ,
490
503
render_type : RenderType ,
491
504
sort_modules_alphabetically : bool ,
492
- deny_render_differences : bool ) -> Result < ( ) , Error > {
505
+ deny_render_differences : bool ,
506
+ themes : Vec < PathBuf > ) -> Result < ( ) , Error > {
493
507
let src_root = match krate. src {
494
508
FileName :: Real ( ref p) => match p. parent ( ) {
495
509
Some ( p) => p. to_path_buf ( ) ,
@@ -513,6 +527,7 @@ pub fn run(mut krate: clean::Crate,
513
527
markdown_warnings : RefCell :: new ( vec ! [ ] ) ,
514
528
created_dirs : RefCell :: new ( FxHashSet ( ) ) ,
515
529
sort_modules_alphabetically,
530
+ themes,
516
531
} ;
517
532
518
533
// If user passed in `--playground-url` arg, we fill in crate name here
@@ -859,12 +874,65 @@ fn write_shared(cx: &Context,
859
874
// Add all the static files. These may already exist, but we just
860
875
// overwrite them anyway to make sure that they're fresh and up-to-date.
861
876
862
- write ( cx. dst . join ( "main.js" ) ,
863
- include_bytes ! ( "static/main.js" ) ) ?;
864
877
write ( cx. dst . join ( "rustdoc.css" ) ,
865
878
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" ) ) ?;
866
895
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
+
868
936
if let Some ( ref css) = cx. shared . css_file_extension {
869
937
let out = cx. dst . join ( "theme.css" ) ;
870
938
try_err ! ( fs:: copy( css, out) , css) ;
@@ -1156,7 +1224,8 @@ impl<'a> SourceCollector<'a> {
1156
1224
} ;
1157
1225
layout:: render ( & mut w, & self . scx . layout ,
1158
1226
& page, & ( "" ) , & Source ( contents) ,
1159
- self . scx . css_file_extension . is_some ( ) ) ?;
1227
+ self . scx . css_file_extension . is_some ( ) ,
1228
+ & self . scx . themes ) ?;
1160
1229
w. flush ( ) ?;
1161
1230
self . scx . local_sources . insert ( p. clone ( ) , href) ;
1162
1231
Ok ( ( ) )
@@ -1520,7 +1589,8 @@ impl Context {
1520
1589
layout:: render ( writer, & self . shared . layout , & page,
1521
1590
& Sidebar { cx : self , item : it } ,
1522
1591
& 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 ) ?;
1524
1594
} else {
1525
1595
let mut url = self . root_path ( ) ;
1526
1596
if let Some ( & ( ref names, ty) ) = cache ( ) . paths . get ( & it. def_id ) {
0 commit comments