8
8
//! extern crate rustc_span;
9
9
//!
10
10
//! use rustc_span::edition::Edition;
11
- //! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes};
11
+ //! use rustdoc::html::markdown::{HeadingOffset, IdMap, Markdown, ErrorCodes};
12
12
//!
13
13
//! let s = "My *markdown* _text_";
14
14
//! let mut id_map = IdMap::new();
15
- //! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None);
15
+ //! let md = Markdown {
16
+ //! content: s,
17
+ //! links: &[],
18
+ //! ids: &mut id_map,
19
+ //! error_codes: ErrorCodes::Yes,
20
+ //! edition: Edition::Edition2015,
21
+ //! playground: &None,
22
+ //! heading_offset: HeadingOffset::H2,
23
+ //! };
16
24
//! let html = md.into_string();
17
25
//! // ... something using html
18
26
//! ```
@@ -47,6 +55,8 @@ use pulldown_cmark::{
47
55
#[ cfg( test) ]
48
56
mod tests;
49
57
58
+ const MAX_HEADER_LEVEL : u32 = 6 ;
59
+
50
60
/// Options for rendering Markdown in the main body of documentation.
51
61
pub ( crate ) fn main_body_opts ( ) -> Options {
52
62
Options :: ENABLE_TABLES
@@ -65,20 +75,33 @@ pub(crate) fn summary_opts() -> Options {
65
75
| Options :: ENABLE_SMART_PUNCTUATION
66
76
}
67
77
78
+ #[ derive( Debug , Clone , Copy ) ]
79
+ pub enum HeadingOffset {
80
+ H1 = 0 ,
81
+ H2 ,
82
+ H3 ,
83
+ H4 ,
84
+ H5 ,
85
+ H6 ,
86
+ }
87
+
68
88
/// When `to_string` is called, this struct will emit the HTML corresponding to
69
89
/// the rendered version of the contained markdown string.
70
- pub struct Markdown < ' a > (
71
- pub & ' a str ,
90
+ pub struct Markdown < ' a > {
91
+ pub content : & ' a str ,
72
92
/// A list of link replacements.
73
- pub & ' a [ RenderedLink ] ,
93
+ pub links : & ' a [ RenderedLink ] ,
74
94
/// The current list of used header IDs.
75
- pub & ' a mut IdMap ,
95
+ pub ids : & ' a mut IdMap ,
76
96
/// Whether to allow the use of explicit error codes in doctest lang strings.
77
- pub ErrorCodes ,
97
+ pub error_codes : ErrorCodes ,
78
98
/// Default edition to use when parsing doctests (to add a `fn main`).
79
- pub Edition ,
80
- pub & ' a Option < Playground > ,
81
- ) ;
99
+ pub edition : Edition ,
100
+ pub playground : & ' a Option < Playground > ,
101
+ /// Offset at which we render headings.
102
+ /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
103
+ pub heading_offset : HeadingOffset ,
104
+ }
82
105
/// A tuple struct like `Markdown` that renders the markdown with a table of contents.
83
106
crate struct MarkdownWithToc < ' a > (
84
107
crate & ' a str ,
@@ -489,11 +512,17 @@ struct HeadingLinks<'a, 'b, 'ids, I> {
489
512
toc : Option < & ' b mut TocBuilder > ,
490
513
buf : VecDeque < SpannedEvent < ' a > > ,
491
514
id_map : & ' ids mut IdMap ,
515
+ heading_offset : HeadingOffset ,
492
516
}
493
517
494
518
impl < ' a , ' b , ' ids , I > HeadingLinks < ' a , ' b , ' ids , I > {
495
- fn new ( iter : I , toc : Option < & ' b mut TocBuilder > , ids : & ' ids mut IdMap ) -> Self {
496
- HeadingLinks { inner : iter, toc, buf : VecDeque :: new ( ) , id_map : ids }
519
+ fn new (
520
+ iter : I ,
521
+ toc : Option < & ' b mut TocBuilder > ,
522
+ ids : & ' ids mut IdMap ,
523
+ heading_offset : HeadingOffset ,
524
+ ) -> Self {
525
+ HeadingLinks { inner : iter, toc, buf : VecDeque :: new ( ) , id_map : ids, heading_offset }
497
526
}
498
527
}
499
528
@@ -530,6 +559,7 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
530
559
self . buf . push_front ( ( Event :: Html ( format ! ( "{} " , sec) . into ( ) ) , 0 ..0 ) ) ;
531
560
}
532
561
562
+ let level = std:: cmp:: min ( level + ( self . heading_offset as u32 ) , MAX_HEADER_LEVEL ) ;
533
563
self . buf . push_back ( ( Event :: Html ( format ! ( "</a></h{}>" , level) . into ( ) ) , 0 ..0 ) ) ;
534
564
535
565
let start_tags = format ! (
@@ -1005,7 +1035,15 @@ impl LangString {
1005
1035
1006
1036
impl Markdown < ' _ > {
1007
1037
pub fn into_string ( self ) -> String {
1008
- let Markdown ( md, links, mut ids, codes, edition, playground) = self ;
1038
+ let Markdown {
1039
+ content : md,
1040
+ links,
1041
+ mut ids,
1042
+ error_codes : codes,
1043
+ edition,
1044
+ playground,
1045
+ heading_offset,
1046
+ } = self ;
1009
1047
1010
1048
// This is actually common enough to special-case
1011
1049
if md. is_empty ( ) {
@@ -1026,7 +1064,7 @@ impl Markdown<'_> {
1026
1064
1027
1065
let mut s = String :: with_capacity ( md. len ( ) * 3 / 2 ) ;
1028
1066
1029
- let p = HeadingLinks :: new ( p, None , & mut ids) ;
1067
+ let p = HeadingLinks :: new ( p, None , & mut ids, heading_offset ) ;
1030
1068
let p = Footnotes :: new ( p) ;
1031
1069
let p = LinkReplacer :: new ( p. map ( |( ev, _) | ev) , links) ;
1032
1070
let p = TableWrapper :: new ( p) ;
@@ -1048,7 +1086,7 @@ impl MarkdownWithToc<'_> {
1048
1086
let mut toc = TocBuilder :: new ( ) ;
1049
1087
1050
1088
{
1051
- let p = HeadingLinks :: new ( p, Some ( & mut toc) , & mut ids) ;
1089
+ let p = HeadingLinks :: new ( p, Some ( & mut toc) , & mut ids, HeadingOffset :: H1 ) ;
1052
1090
let p = Footnotes :: new ( p) ;
1053
1091
let p = TableWrapper :: new ( p. map ( |( ev, _) | ev) ) ;
1054
1092
let p = CodeBlocks :: new ( p, codes, edition, playground) ;
@@ -1077,7 +1115,7 @@ impl MarkdownHtml<'_> {
1077
1115
1078
1116
let mut s = String :: with_capacity ( md. len ( ) * 3 / 2 ) ;
1079
1117
1080
- let p = HeadingLinks :: new ( p, None , & mut ids) ;
1118
+ let p = HeadingLinks :: new ( p, None , & mut ids, HeadingOffset :: H1 ) ;
1081
1119
let p = Footnotes :: new ( p) ;
1082
1120
let p = TableWrapper :: new ( p. map ( |( ev, _) | ev) ) ;
1083
1121
let p = CodeBlocks :: new ( p, codes, edition, playground) ;
@@ -1295,7 +1333,7 @@ crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
1295
1333
// There's no need to thread an IdMap through to here because
1296
1334
// the IDs generated aren't going to be emitted anywhere.
1297
1335
let mut ids = IdMap :: new ( ) ;
1298
- let iter = Footnotes :: new ( HeadingLinks :: new ( p, None , & mut ids) ) ;
1336
+ let iter = Footnotes :: new ( HeadingLinks :: new ( p, None , & mut ids, HeadingOffset :: H1 ) ) ;
1299
1337
1300
1338
for ev in iter {
1301
1339
if let Event :: Start ( Tag :: Link ( kind, dest, _) ) = ev. 0 {
0 commit comments