Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

Refactor docs to use ExDocs search_data model for global HexDocs indexing of Gleam packages

+104 -61
+78 -37
compiler-core/src/docs.rs
··· 94 94 95 95 let mut files = vec![]; 96 96 97 - let mut search_indexes = vec![]; 97 + let mut search_items = vec![]; 98 98 99 99 let modules_links: Vec<_> = modules 100 100 .clone() ··· 148 148 content: Content::Text(temp.render().expect("Page template rendering")), 149 149 }); 150 150 151 - search_indexes.push(SearchIndex { 152 - doc: config.name.to_string(), 151 + search_items.push(SearchItem { 152 + type_: SearchItemType::Page, 153 + parent_title: config.name.to_string(), 153 154 title: config.name.to_string(), 154 - content, 155 - url: page.path.to_string(), 155 + doc: content, 156 + ref_: page.path.to_string(), 156 157 }) 157 158 } 158 159 ··· 213 214 }) 214 215 .join("\n"); 215 216 216 - search_indexes.push(SearchIndex { 217 - doc: module.name.to_string(), 217 + search_items.push(SearchItem { 218 + type_: SearchItemType::Type, 219 + parent_title: module.name.to_string(), 218 220 title: type_.name.to_string(), 219 - content: format!( 221 + doc: format!( 220 222 "{}\n{}\n{}\n{}", 221 223 type_.definition, 222 224 type_.text_documentation, 223 225 constructors, 224 226 import_synonyms(&module.name, type_.name) 225 227 ), 226 - url: format!("{}.html#{}", module.name, type_.name), 228 + ref_: format!("{}.html#{}", module.name, type_.name), 227 229 }) 228 230 }); 229 231 constants.iter().for_each(|constant| { 230 - search_indexes.push(SearchIndex { 231 - doc: module.name.to_string(), 232 + search_items.push(SearchItem { 233 + type_: SearchItemType::Constant, 234 + parent_title: module.name.to_string(), 232 235 title: constant.name.to_string(), 233 - content: format!( 236 + doc: format!( 234 237 "{}\n{}\n{}", 235 238 constant.definition, 236 239 constant.text_documentation, 237 240 import_synonyms(&module.name, constant.name) 238 241 ), 239 - url: format!("{}.html#{}", module.name, constant.name), 242 + ref_: format!("{}.html#{}", module.name, constant.name), 240 243 }) 241 244 }); 242 245 functions.iter().for_each(|function| { 243 - search_indexes.push(SearchIndex { 244 - doc: module.name.to_string(), 246 + search_items.push(SearchItem { 247 + type_: SearchItemType::Function, 248 + parent_title: module.name.to_string(), 245 249 title: function.name.to_string(), 246 - content: format!( 250 + doc: format!( 247 251 "{}\n{}\n{}", 248 252 function.signature, 249 253 function.text_documentation, 250 254 import_synonyms(&module.name, function.name) 251 255 ), 252 - url: format!("{}.html#{}", module.name, function.name), 256 + ref_: format!("{}.html#{}", module.name, function.name), 253 257 }) 254 258 }); 255 - search_indexes.push(SearchIndex { 256 - doc: module.name.to_string(), 259 + search_items.push(SearchItem { 260 + type_: SearchItemType::Module, 261 + parent_title: module.name.to_string(), 257 262 title: module.name.to_string(), 258 - content: documentation_content, 259 - url: format!("{}.html", module.name), 263 + doc: documentation_content, 264 + ref_: format!("{}.html", module.name), 260 265 }); 261 266 262 267 let page_title = format!("{} · {} · v{}", name, config.name, config.version); ··· 358 363 ), 359 364 }); 360 365 361 - // lunr.min.js, search-data.js and index.js: 366 + // lunr.min.js, search-data.js, search-data.json and index.js 362 367 363 368 files.push(OutputFile { 364 369 path: Utf8PathBuf::from("js/lunr.min.js"), 365 370 content: Content::Text(std::include_str!("../templates/docs-js/lunr.min.js").to_string()), 366 371 }); 367 372 373 + let search_data_json = serde_to_string(&SearchData { 374 + items: escape_html_contents(search_items), 375 + proglang: SearchProgLang::Gleam, 376 + }) 377 + .expect("search index serialization"); 378 + 368 379 files.push(OutputFile { 369 380 path: Utf8PathBuf::from("search-data.js"), 370 - content: Content::Text(format!( 371 - "window.Gleam.initSearch({});", 372 - serde_to_string(&escape_html_contents(search_indexes)) 373 - .expect("search index serialization") 374 - )), 381 + content: Content::Text(format!("window.Gleam.initSearch({});", search_data_json)), 382 + }); 383 + 384 + files.push(OutputFile { 385 + path: Utf8PathBuf::from("search-data.json"), 386 + content: Content::Text(search_data_json.to_string()), 375 387 }); 376 388 377 389 files.push(OutputFile { ··· 505 517 .replace('\'', "&#39;") 506 518 } 507 519 508 - fn escape_html_contents(indexes: Vec<SearchIndex>) -> Vec<SearchIndex> { 520 + fn escape_html_contents(indexes: Vec<SearchItem>) -> Vec<SearchItem> { 509 521 indexes 510 522 .into_iter() 511 - .map(|idx| SearchIndex { 512 - doc: idx.doc, 523 + .map(|idx| SearchItem { 524 + type_: idx.type_, 525 + parent_title: idx.parent_title, 513 526 title: idx.title, 514 - content: escape_html_content(idx.content), 515 - url: idx.url, 527 + doc: escape_html_content(idx.doc), 528 + ref_: idx.ref_, 516 529 }) 517 - .collect::<Vec<SearchIndex>>() 530 + .collect::<Vec<SearchItem>>() 518 531 } 519 532 520 533 fn import_synonyms(parent: &str, child: &str) -> String { ··· 824 837 } 825 838 826 839 #[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)] 827 - struct SearchIndex { 828 - doc: String, 840 + struct SearchData { 841 + items: Vec<SearchItem>, 842 + proglang: SearchProgLang, 843 + } 844 + 845 + #[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)] 846 + struct SearchItem { 847 + #[serde(rename = "type")] 848 + type_: SearchItemType, 849 + #[serde(rename = "parentTitle")] 850 + parent_title: String, 829 851 title: String, 830 - content: String, 831 - url: String, 852 + doc: String, 853 + #[serde(rename = "ref")] 854 + ref_: String, 855 + } 856 + 857 + #[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)] 858 + #[serde(rename_all = "lowercase")] 859 + enum SearchItemType { 860 + Constant, 861 + Function, 862 + Module, 863 + Page, 864 + Type, 865 + } 866 + 867 + #[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)] 868 + #[serde(rename_all = "lowercase")] 869 + enum SearchProgLang { 870 + // Elixir, 871 + // Erlang, 872 + Gleam, 832 873 }
+26 -24
compiler-core/templates/docs-js/index.js
··· 171 171 else el.addEventListener(type, handler); 172 172 }; 173 173 174 - const searchLoaded = function (index, docs) { 174 + const searchLoaded = function (index, searchItems) { 175 175 const preview_words_after = 10; 176 176 const preview_words_before = 5; 177 177 const previews = 3; ··· 285 285 } 286 286 287 287 function addResult(resultsList, result) { 288 - const doc = docs[result.ref]; 288 + const searchItem = searchItems[result.ref]; 289 289 const resultsListItem = document.createElement("li"); 290 290 resultsListItem.classList.add("search-results-list-item"); 291 291 resultsList.appendChild(resultsListItem); 292 292 const resultLink = document.createElement("a"); 293 293 resultLink.classList.add("search-result"); 294 - resultLink.setAttribute("href", `${window.unnest}/${doc.url}`); 294 + resultLink.setAttribute("href", `${window.unnest}/${searchItem.ref}`); 295 295 resultsListItem.appendChild(resultLink); 296 296 const resultTitle = document.createElement("div"); 297 297 resultTitle.classList.add("search-result-title"); ··· 303 303 resultTitle.appendChild(resultDoc); 304 304 const resultDocTitle = document.createElement("div"); 305 305 resultDocTitle.classList.add("search-result-doc-title"); 306 - resultDocTitle.innerHTML = doc.doc; 306 + resultDocTitle.innerHTML = searchItem.parentTitle; 307 307 resultDoc.appendChild(resultDocTitle); 308 308 let resultDocOrSection = resultDocTitle; 309 - if (doc.doc != doc.title) { 309 + if (searchItem.parentTitle != searchItem.title) { 310 310 resultDoc.classList.add("search-result-doc-parent"); 311 311 const resultSection = document.createElement("div"); 312 312 resultSection.classList.add("search-result-section"); 313 - resultSection.innerHTML = doc.title; 313 + resultSection.innerHTML = searchItem.title; 314 314 resultTitle.appendChild(resultSection); 315 315 resultDocOrSection = resultSection; 316 316 } ··· 334 334 let ellipsesBefore = true; 335 335 let ellipsesAfter = true; 336 336 for (let k = 0; k < preview_words_before; k++) { 337 - const nextSpace = doc.content.lastIndexOf( 337 + const nextSpace = searchItem.doc.lastIndexOf( 338 338 " ", 339 339 previewStart - 2, 340 340 ); 341 - const nextDot = doc.content.lastIndexOf(". ", previewStart - 2); 341 + const nextDot = searchItem.doc.lastIndexOf(". ", previewStart - 2); 342 342 if (nextDot >= 0 && nextDot > nextSpace) { 343 343 previewStart = nextDot + 1; 344 344 ellipsesBefore = false; ··· 352 352 previewStart = nextSpace + 1; 353 353 } 354 354 for (let k = 0; k < preview_words_after; k++) { 355 - const nextSpace = doc.content.indexOf(" ", previewEnd + 1); 356 - const nextDot = doc.content.indexOf(". ", previewEnd + 1); 355 + const nextSpace = searchItem.doc.indexOf(" ", previewEnd + 1); 356 + const nextDot = searchItem.doc.indexOf(". ", previewEnd + 1); 357 357 if (nextDot >= 0 && nextDot < nextSpace) { 358 358 previewEnd = nextDot; 359 359 ellipsesAfter = false; 360 360 break; 361 361 } 362 362 if (nextSpace < 0) { 363 - previewEnd = doc.content.length; 363 + previewEnd = searchItem.doc.length; 364 364 ellipsesAfter = false; 365 365 break; 366 366 } ··· 383 383 resultDocOrSection.innerHTML = ""; 384 384 addHighlightedText( 385 385 resultDocOrSection, 386 - doc.title, 386 + searchItem.title, 387 387 0, 388 - doc.title.length, 388 + searchItem.title.length, 389 389 titlePositions, 390 390 ); 391 391 } ··· 422 422 const resultPreviews = document.createElement("div"); 423 423 resultPreviews.classList.add("search-result-previews"); 424 424 resultLink.appendChild(resultPreviews); 425 - const content = doc.content; 425 + const content = searchItem.doc; 426 426 for ( 427 427 let j = 0; 428 428 j < Math.min(previewPositions.length, previews); ··· 449 449 } 450 450 const resultRelUrl = document.createElement("span"); 451 451 resultRelUrl.classList.add("search-result-rel-url"); 452 - resultRelUrl.innerText = doc.url; 452 + resultRelUrl.innerText = searchItem.ref; 453 453 resultTitle.appendChild(resultRelUrl); 454 454 } 455 455 ··· 567 567 }); 568 568 }; 569 569 570 - self.initSearch = function initSeach(docs) { 570 + self.initSearch = function initSeach(searchData) { 571 571 // enable support for hyphenated search words 572 572 lunr.tokenizer.separator = /[\s/]+/; 573 - 574 573 const index = lunr(function () { 575 574 this.ref("id"); 575 + // this.field("type"); 576 + // this.field("parentTitle"); 576 577 this.field("title", { boost: 200 }); 577 - this.field("content", { boost: 2 }); 578 - this.field("url"); 578 + this.field("doc", { boost: 2 }); 579 + this.field("ref"); 579 580 this.metadataWhitelist = ["position"]; 580 581 581 - for (let [i, entry] of docs.entries()) { 582 + for (let [i, entry] of searchData.items.entries()) { 582 583 this.add({ 583 584 id: i, 585 + // type: entry.type, 586 + parentTitle: entry.parentTitle, 584 587 title: entry.title, 585 - content: entry.content, 586 - url: `${window.unnest}/${entry.url}`, 588 + doc: entry.doc, 589 + ref: `${window.unnest}/${entry.ref}`, 587 590 }); 588 591 } 589 592 }); 590 - 591 - searchLoaded(index, docs); 593 + searchLoaded(index, searchData.items); 592 594 }; 593 595 594 596 const init = function () {