1
1
//! Renders the grammar to markdown.
2
2
3
- use super :: { Characters , Expression , ExpressionKind , Production } ;
3
+ use super :: { Characters , Expression , ExpressionKind , Production , RenderCtx } ;
4
4
use crate :: grammar:: Grammar ;
5
5
use anyhow:: bail;
6
6
use regex:: Regex ;
7
7
use std:: borrow:: Cow ;
8
- use std:: collections:: HashMap ;
9
8
use std:: fmt:: Write ;
10
9
use std:: sync:: LazyLock ;
11
10
12
11
impl Grammar {
13
12
pub fn render_markdown (
14
13
& self ,
14
+ cx : & RenderCtx ,
15
15
names : & [ & str ] ,
16
- link_map : & HashMap < String , String > ,
17
- rr_link_map : & HashMap < String , String > ,
18
16
output : & mut String ,
19
- for_summary : bool ,
20
17
) -> anyhow:: Result < ( ) > {
21
18
let mut iter = names. into_iter ( ) . peekable ( ) ;
22
19
while let Some ( name) = iter. next ( ) {
23
20
let Some ( prod) = self . productions . get ( * name) else {
24
21
bail ! ( "could not find grammar production named `{name}`" ) ;
25
22
} ;
26
- prod. render_markdown ( link_map , rr_link_map , output, for_summary ) ;
23
+ prod. render_markdown ( cx , output) ;
27
24
if iter. peek ( ) . is_some ( ) {
28
25
output. push_str ( "\n " ) ;
29
26
}
@@ -42,14 +39,9 @@ pub fn markdown_id(name: &str, for_summary: bool) -> String {
42
39
}
43
40
44
41
impl 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
53
45
. get ( & self . name )
54
46
. map ( |path| path. to_string ( ) )
55
47
. unwrap_or_else ( || format ! ( "missing" ) ) ;
@@ -60,12 +52,11 @@ impl Production {
60
52
>\
61
53
[{name}]({dest})\
62
54
</span> → ",
63
- id = markdown_id( & self . name, for_summary) ,
55
+ id = markdown_id( & self . name, cx . for_summary) ,
64
56
name = self . name,
65
57
)
66
58
. unwrap ( ) ;
67
- self . expression
68
- . render_markdown ( link_map, output, for_summary) ;
59
+ self . expression . render_markdown ( cx, output) ;
69
60
output. push ( '\n' ) ;
70
61
}
71
62
}
@@ -92,16 +83,11 @@ impl Expression {
92
83
}
93
84
}
94
85
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 ) {
101
87
match & self . kind {
102
88
ExpressionKind :: Grouped ( e) => {
103
89
output. push_str ( "( " ) ;
104
- e. render_markdown ( link_map , output, for_summary ) ;
90
+ e. render_markdown ( cx , output) ;
105
91
if !matches ! ( e. last( ) , ExpressionKind :: Break ( _) ) {
106
92
output. push ( ' ' ) ;
107
93
}
@@ -110,7 +96,7 @@ impl Expression {
110
96
ExpressionKind :: Alt ( es) => {
111
97
let mut iter = es. iter ( ) . peekable ( ) ;
112
98
while let Some ( e) = iter. next ( ) {
113
- e. render_markdown ( link_map , output, for_summary ) ;
99
+ e. render_markdown ( cx , output) ;
114
100
if iter. peek ( ) . is_some ( ) {
115
101
if !matches ! ( e. last( ) , ExpressionKind :: Break ( _) ) {
116
102
output. push ( ' ' ) ;
@@ -122,34 +108,34 @@ impl Expression {
122
108
ExpressionKind :: Sequence ( es) => {
123
109
let mut iter = es. iter ( ) . peekable ( ) ;
124
110
while let Some ( e) = iter. next ( ) {
125
- e. render_markdown ( link_map , output, for_summary ) ;
111
+ e. render_markdown ( cx , output) ;
126
112
if iter. peek ( ) . is_some ( ) && !matches ! ( e. last( ) , ExpressionKind :: Break ( _) ) {
127
113
output. push ( ' ' ) ;
128
114
}
129
115
}
130
116
}
131
117
ExpressionKind :: Optional ( e) => {
132
- e. render_markdown ( link_map , output, for_summary ) ;
118
+ e. render_markdown ( cx , output) ;
133
119
output. push_str ( "<sup>?</sup>" ) ;
134
120
}
135
121
ExpressionKind :: Repeat ( e) => {
136
- e. render_markdown ( link_map , output, for_summary ) ;
122
+ e. render_markdown ( cx , output) ;
137
123
output. push_str ( "<sup>\\ *</sup>" ) ;
138
124
}
139
125
ExpressionKind :: RepeatNonGreedy ( e) => {
140
- e. render_markdown ( link_map , output, for_summary ) ;
126
+ e. render_markdown ( cx , output) ;
141
127
output. push_str ( "<sup>\\ * (non-greedy)</sup>" ) ;
142
128
}
143
129
ExpressionKind :: RepeatPlus ( e) => {
144
- e. render_markdown ( link_map , output, for_summary ) ;
130
+ e. render_markdown ( cx , output) ;
145
131
output. push_str ( "<sup>+</sup>" ) ;
146
132
}
147
133
ExpressionKind :: RepeatPlusNonGreedy ( e) => {
148
- e. render_markdown ( link_map , output, for_summary ) ;
134
+ e. render_markdown ( cx , output) ;
149
135
output. push_str ( "<sup>+ (non-greedy)</sup>" ) ;
150
136
}
151
137
ExpressionKind :: RepeatRange ( e, a, b) => {
152
- e. render_markdown ( link_map , output, for_summary ) ;
138
+ e. render_markdown ( cx , output) ;
153
139
write ! (
154
140
output,
155
141
"<sup>{}..{}</sup>" ,
@@ -159,7 +145,7 @@ impl Expression {
159
145
. unwrap ( ) ;
160
146
}
161
147
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 ( ) ) ;
163
149
write ! ( output, "<span class=\" grammar-text\" >[{nt}]({dest})</span>" ) . unwrap ( ) ;
164
150
}
165
151
ExpressionKind :: Terminal ( t) => {
@@ -177,10 +163,10 @@ impl Expression {
177
163
output. push_str ( "\\ \n " ) ;
178
164
output. push_str ( & " " . repeat ( * indent) ) ;
179
165
}
180
- ExpressionKind :: Charset ( set) => charset_render_markdown ( set , link_map , output) ,
166
+ ExpressionKind :: Charset ( set) => charset_render_markdown ( cx , set , output) ,
181
167
ExpressionKind :: NegExpression ( e) => {
182
168
output. push ( '~' ) ;
183
- e. render_markdown ( link_map , output, for_summary ) ;
169
+ e. render_markdown ( cx , output) ;
184
170
}
185
171
ExpressionKind :: Unicode ( s) => {
186
172
output. push_str ( "U+" ) ;
@@ -190,7 +176,7 @@ impl Expression {
190
176
if let Some ( suffix) = & self . suffix {
191
177
write ! ( output, "<sub class=\" grammar-text\" >{suffix}</sub>" ) . unwrap ( ) ;
192
178
}
193
- if !for_summary {
179
+ if !cx . for_summary {
194
180
if let Some ( footnote) = & self . footnote {
195
181
// The `ZeroWidthSpace` is to avoid conflicts with markdown link
196
182
// references.
@@ -200,15 +186,11 @@ impl Expression {
200
186
}
201
187
}
202
188
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 ) {
208
190
output. push_str ( "\\ [" ) ;
209
191
let mut iter = set. iter ( ) . peekable ( ) ;
210
192
while let Some ( chars) = iter. next ( ) {
211
- chars. render_markdown ( link_map , output) ;
193
+ chars. render_markdown ( cx , output) ;
212
194
if iter. peek ( ) . is_some ( ) {
213
195
output. push ( ' ' ) ;
214
196
}
@@ -217,10 +199,10 @@ fn charset_render_markdown(
217
199
}
218
200
219
201
impl Characters {
220
- fn render_markdown ( & self , link_map : & HashMap < String , String > , output : & mut String ) {
202
+ fn render_markdown ( & self , cx : & RenderCtx , output : & mut String ) {
221
203
match self {
222
204
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 ( ) ) ;
224
206
write ! ( output, "[{s}]({dest})" ) . unwrap ( ) ;
225
207
}
226
208
Characters :: Terminal ( s) => write ! (
0 commit comments