@@ -11,6 +11,8 @@ pub(crate) struct HomeManagerOption {
1111 pub ( crate ) name : String ,
1212 pub ( crate ) description : String ,
1313 pub ( crate ) type_info : String ,
14+ pub ( crate ) default_value : String ,
15+ pub ( crate ) declared_by : String ,
1416}
1517
1618fn decode_html_entities ( input : & str ) -> String {
@@ -111,25 +113,130 @@ fn extract_description(dd_block: &str) -> String {
111113}
112114
113115fn extract_type_info ( dd_block : & str ) -> String {
116+ extract_section_value (
117+ dd_block,
118+ "Type:" ,
119+ & [
120+ "Default:" ,
121+ "Example:" ,
122+ "Declared by:" ,
123+ "Defined by:" ,
124+ "Related packages:" ,
125+ "Related options:" ,
126+ ] ,
127+ )
128+ }
129+
130+ fn extract_default_value ( dd_block : & str ) -> String {
131+ extract_section_value (
132+ dd_block,
133+ "Default:" ,
134+ & [
135+ "Example:" ,
136+ "Declared by:" ,
137+ "Defined by:" ,
138+ "Related packages:" ,
139+ "Related options:" ,
140+ "Type:" ,
141+ ] ,
142+ )
143+ }
144+
145+ fn extract_declared_by ( dd_block : & str ) -> String {
146+ let Some ( section) = extract_section_html (
147+ dd_block,
148+ "Declared by:" ,
149+ & [
150+ "Defined by:" ,
151+ "Related packages:" ,
152+ "Related options:" ,
153+ "Example:" ,
154+ "Default:" ,
155+ "Type:" ,
156+ ] ,
157+ ) else {
158+ return String :: new ( ) ;
159+ } ;
160+
161+ let links = extract_links ( section) ;
162+ if links. is_empty ( ) {
163+ String :: new ( )
164+ } else {
165+ links. join ( ", " )
166+ }
167+ }
168+
169+ fn extract_links ( section : & str ) -> Vec < String > {
170+ let mut links = Vec :: new ( ) ;
171+ let mut seen = HashSet :: new ( ) ;
172+ let mut cursor = 0 ;
173+
174+ while let Some ( href_rel) = section[ cursor..] . find ( "href=" ) {
175+ let href_start = cursor + href_rel + "href=" . len ( ) ;
176+ let bytes = section. as_bytes ( ) ;
177+ if href_start >= bytes. len ( ) {
178+ break ;
179+ }
180+
181+ let quote = bytes[ href_start] ;
182+ if quote != b'"' && quote != b'\'' {
183+ cursor = href_start + 1 ;
184+ continue ;
185+ }
186+
187+ let mut end = href_start + 1 ;
188+ while end < bytes. len ( ) && bytes[ end] != quote {
189+ end += 1 ;
190+ }
191+ if end >= bytes. len ( ) {
192+ break ;
193+ }
194+
195+ let url = & section[ href_start + 1 ..end] ;
196+ let decoded = decode_html_entities ( url) ;
197+ if !decoded. is_empty ( ) && seen. insert ( decoded. clone ( ) ) {
198+ links. push ( decoded) ;
199+ }
200+
201+ cursor = end + 1 ;
202+ }
203+
204+ links
205+ }
206+
207+ fn extract_section_html < ' a > (
208+ input : & ' a str ,
209+ label : & str ,
210+ stop_markers : & [ & str ] ,
211+ ) -> Option < & ' a str > {
212+ let label_idx = input. find ( label) ?;
213+ let rest = & input[ label_idx + label. len ( ) ..] ;
214+ let mut end = rest. len ( ) ;
215+
216+ for marker in stop_markers {
217+ if let Some ( idx) = rest. find ( marker) {
218+ if idx < end {
219+ end = idx;
220+ }
221+ }
222+ }
223+
224+ Some ( & rest[ ..end] )
225+ }
226+
227+ fn extract_section_value ( dd_block : & str , label : & str , stop_markers : & [ & str ] ) -> String {
114228 let text = clean_html_text ( dd_block) ;
115- let Some ( type_idx ) = text. find ( "Type:" ) else {
229+ let Some ( section_idx ) = text. find ( label ) else {
116230 return String :: new ( ) ;
117231 } ;
118232
119- let rest = text[ type_idx + "Type:" . len ( ) ..] . trim_start ( ) ;
233+ let rest = text[ section_idx + label . len ( ) ..] . trim_start ( ) ;
120234 if rest. is_empty ( ) {
121235 return String :: new ( ) ;
122236 }
123237
124238 let mut end = rest. len ( ) ;
125- for marker in [
126- "Default:" ,
127- "Example:" ,
128- "Declared by:" ,
129- "Defined by:" ,
130- "Related packages:" ,
131- "Related options:" ,
132- ] {
239+ for marker in stop_markers {
133240 if let Some ( idx) = rest. find ( marker) {
134241 if idx < end {
135242 end = idx;
@@ -183,11 +290,15 @@ fn parse_home_manager_options(
183290
184291 let mut description = String :: new ( ) ;
185292 let mut type_info = String :: new ( ) ;
293+ let mut default_value = String :: new ( ) ;
294+ let mut declared_by = String :: new ( ) ;
186295 let mut next_cursor = cursor;
187296
188297 if let Some ( ( dd_block, dd_next_cursor) ) = extract_dd_block ( html, cursor) {
189298 description = extract_description ( dd_block) ;
190299 type_info = extract_type_info ( dd_block) ;
300+ default_value = extract_default_value ( dd_block) ;
301+ declared_by = extract_declared_by ( dd_block) ;
191302 next_cursor = dd_next_cursor;
192303 }
193304
@@ -201,6 +312,8 @@ fn parse_home_manager_options(
201312 name,
202313 description,
203314 type_info : type_info. trim ( ) . to_string ( ) ,
315+ default_value : default_value. trim ( ) . to_string ( ) ,
316+ declared_by : declared_by. trim ( ) . to_string ( ) ,
204317 } ) ;
205318
206319 cursor = next_cursor;
0 commit comments