11//! Renders the grammar to markdown.
22
3- use super :: { Characters , Expression , ExpressionKind , Production } ;
3+ use super :: { Characters , Expression , ExpressionKind , Production , RenderCtx } ;
44use crate :: grammar:: Grammar ;
55use anyhow:: bail;
66use regex:: Regex ;
77use std:: borrow:: Cow ;
8- use std:: collections:: HashMap ;
98use std:: fmt:: Write ;
109use std:: sync:: LazyLock ;
1110
1211impl Grammar {
1312 pub fn render_markdown (
1413 & self ,
14+ cx : & RenderCtx ,
1515 names : & [ & str ] ,
16- link_map : & HashMap < String , String > ,
17- rr_link_map : & HashMap < String , String > ,
1816 output : & mut String ,
19- for_summary : bool ,
2017 ) -> anyhow:: Result < ( ) > {
2118 let mut iter = names. into_iter ( ) . peekable ( ) ;
2219 while let Some ( name) = iter. next ( ) {
2320 let Some ( prod) = self . productions . get ( * name) else {
2421 bail ! ( "could not find grammar production named `{name}`" ) ;
2522 } ;
26- prod. render_markdown ( link_map , rr_link_map , output, for_summary ) ;
23+ prod. render_markdown ( cx , output) ;
2724 if iter. peek ( ) . is_some ( ) {
2825 output. push_str ( "\n " ) ;
2926 }
@@ -42,14 +39,9 @@ pub fn markdown_id(name: &str, for_summary: bool) -> String {
4239}
4340
4441impl Production {
45- fn render_markdown (
46- & self ,
47- link_map : & HashMap < String , String > ,
48- rr_link_map : & HashMap < String , String > ,
49- output : & mut String ,
50- for_summary : bool ,
51- ) {
52- let dest = rr_link_map
42+ fn render_markdown ( & self , cx : & RenderCtx , output : & mut String ) {
43+ let dest = cx
44+ . rr_link_map
5345 . get ( & self . name )
5446 . map ( |path| path. to_string ( ) )
5547 . unwrap_or_else ( || format ! ( "missing" ) ) ;
@@ -60,12 +52,11 @@ impl Production {
6052 >\
6153 [{name}]({dest})\
6254 </span> → ",
63- id = markdown_id( & self . name, for_summary) ,
55+ id = markdown_id( & self . name, cx . for_summary) ,
6456 name = self . name,
6557 )
6658 . unwrap ( ) ;
67- self . expression
68- . render_markdown ( link_map, output, for_summary) ;
59+ self . expression . render_markdown ( cx, output) ;
6960 output. push ( '\n' ) ;
7061 }
7162}
@@ -92,16 +83,11 @@ impl Expression {
9283 }
9384 }
9485
95- fn render_markdown (
96- & self ,
97- link_map : & HashMap < String , String > ,
98- output : & mut String ,
99- for_summary : bool ,
100- ) {
86+ fn render_markdown ( & self , cx : & RenderCtx , output : & mut String ) {
10187 match & self . kind {
10288 ExpressionKind :: Grouped ( e) => {
10389 output. push_str ( "( " ) ;
104- e. render_markdown ( link_map , output, for_summary ) ;
90+ e. render_markdown ( cx , output) ;
10591 if !matches ! ( e. last( ) , ExpressionKind :: Break ( _) ) {
10692 output. push ( ' ' ) ;
10793 }
@@ -110,7 +96,7 @@ impl Expression {
11096 ExpressionKind :: Alt ( es) => {
11197 let mut iter = es. iter ( ) . peekable ( ) ;
11298 while let Some ( e) = iter. next ( ) {
113- e. render_markdown ( link_map , output, for_summary ) ;
99+ e. render_markdown ( cx , output) ;
114100 if iter. peek ( ) . is_some ( ) {
115101 if !matches ! ( e. last( ) , ExpressionKind :: Break ( _) ) {
116102 output. push ( ' ' ) ;
@@ -122,34 +108,34 @@ impl Expression {
122108 ExpressionKind :: Sequence ( es) => {
123109 let mut iter = es. iter ( ) . peekable ( ) ;
124110 while let Some ( e) = iter. next ( ) {
125- e. render_markdown ( link_map , output, for_summary ) ;
111+ e. render_markdown ( cx , output) ;
126112 if iter. peek ( ) . is_some ( ) && !matches ! ( e. last( ) , ExpressionKind :: Break ( _) ) {
127113 output. push ( ' ' ) ;
128114 }
129115 }
130116 }
131117 ExpressionKind :: Optional ( e) => {
132- e. render_markdown ( link_map , output, for_summary ) ;
118+ e. render_markdown ( cx , output) ;
133119 output. push_str ( "<sup>?</sup>" ) ;
134120 }
135121 ExpressionKind :: Repeat ( e) => {
136- e. render_markdown ( link_map , output, for_summary ) ;
122+ e. render_markdown ( cx , output) ;
137123 output. push_str ( "<sup>\\ *</sup>" ) ;
138124 }
139125 ExpressionKind :: RepeatNonGreedy ( e) => {
140- e. render_markdown ( link_map , output, for_summary ) ;
126+ e. render_markdown ( cx , output) ;
141127 output. push_str ( "<sup>\\ * (non-greedy)</sup>" ) ;
142128 }
143129 ExpressionKind :: RepeatPlus ( e) => {
144- e. render_markdown ( link_map , output, for_summary ) ;
130+ e. render_markdown ( cx , output) ;
145131 output. push_str ( "<sup>+</sup>" ) ;
146132 }
147133 ExpressionKind :: RepeatPlusNonGreedy ( e) => {
148- e. render_markdown ( link_map , output, for_summary ) ;
134+ e. render_markdown ( cx , output) ;
149135 output. push_str ( "<sup>+ (non-greedy)</sup>" ) ;
150136 }
151137 ExpressionKind :: RepeatRange ( e, a, b) => {
152- e. render_markdown ( link_map , output, for_summary ) ;
138+ e. render_markdown ( cx , output) ;
153139 write ! (
154140 output,
155141 "<sup>{}..{}</sup>" ,
@@ -159,7 +145,7 @@ impl Expression {
159145 . unwrap ( ) ;
160146 }
161147 ExpressionKind :: Nt ( nt) => {
162- let dest = link_map . get ( nt) . map_or ( "missing" , |d| d. as_str ( ) ) ;
148+ let dest = cx . md_link_map . get ( nt) . map_or ( "missing" , |d| d. as_str ( ) ) ;
163149 write ! ( output, "<span class=\" grammar-text\" >[{nt}]({dest})</span>" ) . unwrap ( ) ;
164150 }
165151 ExpressionKind :: Terminal ( t) => {
@@ -177,10 +163,10 @@ impl Expression {
177163 output. push_str ( "\\ \n " ) ;
178164 output. push_str ( & " " . repeat ( * indent) ) ;
179165 }
180- ExpressionKind :: Charset ( set) => charset_render_markdown ( set , link_map , output) ,
166+ ExpressionKind :: Charset ( set) => charset_render_markdown ( cx , set , output) ,
181167 ExpressionKind :: NegExpression ( e) => {
182168 output. push ( '~' ) ;
183- e. render_markdown ( link_map , output, for_summary ) ;
169+ e. render_markdown ( cx , output) ;
184170 }
185171 ExpressionKind :: Unicode ( s) => {
186172 output. push_str ( "U+" ) ;
@@ -190,7 +176,7 @@ impl Expression {
190176 if let Some ( suffix) = & self . suffix {
191177 write ! ( output, "<sub class=\" grammar-text\" >{suffix}</sub>" ) . unwrap ( ) ;
192178 }
193- if !for_summary {
179+ if !cx . for_summary {
194180 if let Some ( footnote) = & self . footnote {
195181 // The `ZeroWidthSpace` is to avoid conflicts with markdown link
196182 // references.
@@ -200,15 +186,11 @@ impl Expression {
200186 }
201187}
202188
203- fn charset_render_markdown (
204- set : & [ Characters ] ,
205- link_map : & HashMap < String , String > ,
206- output : & mut String ,
207- ) {
189+ fn charset_render_markdown ( cx : & RenderCtx , set : & [ Characters ] , output : & mut String ) {
208190 output. push_str ( "\\ [" ) ;
209191 let mut iter = set. iter ( ) . peekable ( ) ;
210192 while let Some ( chars) = iter. next ( ) {
211- chars. render_markdown ( link_map , output) ;
193+ chars. render_markdown ( cx , output) ;
212194 if iter. peek ( ) . is_some ( ) {
213195 output. push ( ' ' ) ;
214196 }
@@ -217,10 +199,10 @@ fn charset_render_markdown(
217199}
218200
219201impl Characters {
220- fn render_markdown ( & self , link_map : & HashMap < String , String > , output : & mut String ) {
202+ fn render_markdown ( & self , cx : & RenderCtx , output : & mut String ) {
221203 match self {
222204 Characters :: Named ( s) => {
223- let dest = link_map . get ( s) . map_or ( "missing" , |d| d. as_str ( ) ) ;
205+ let dest = cx . md_link_map . get ( s) . map_or ( "missing" , |d| d. as_str ( ) ) ;
224206 write ! ( output, "[{s}]({dest})" ) . unwrap ( ) ;
225207 }
226208 Characters :: Terminal ( s) => write ! (
0 commit comments