You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

90 lines
2.5KB

  1. extern crate elasticlunr;
  2. #[macro_use]
  3. extern crate lazy_static;
  4. extern crate ammonia;
  5. #[macro_use]
  6. extern crate errors;
  7. extern crate library;
  8. use std::collections::{HashMap, HashSet};
  9. use elasticlunr::{Index, Language};
  10. use errors::Result;
  11. use library::{Library, Section};
  12. pub const ELASTICLUNR_JS: &str = include_str!("elasticlunr.min.js");
  13. lazy_static! {
  14. static ref AMMONIA: ammonia::Builder<'static> = {
  15. let mut clean_content = HashSet::new();
  16. clean_content.insert("script");
  17. clean_content.insert("style");
  18. let mut builder = ammonia::Builder::new();
  19. builder
  20. .tags(HashSet::new())
  21. .tag_attributes(HashMap::new())
  22. .generic_attributes(HashSet::new())
  23. .link_rel(None)
  24. .allowed_classes(HashMap::new())
  25. .clean_content_tags(clean_content);
  26. builder
  27. };
  28. }
  29. /// Returns the generated JSON index with all the documents of the site added using
  30. /// the language given
  31. /// Errors if the language given is not available in Elasticlunr
  32. /// TODO: is making `in_search_index` apply to subsections of a `false` section useful?
  33. pub fn build_index(lang: &str, library: &Library) -> Result<String> {
  34. let language = match Language::from_code(lang) {
  35. Some(l) => l,
  36. None => {
  37. bail!("Tried to build search index for language {} which is not supported", lang);
  38. }
  39. };
  40. let mut index = Index::with_language(language, &["title", "body"]);
  41. for section in library.sections_values() {
  42. if section.lang == lang {
  43. add_section_to_index(&mut index, section, library);
  44. }
  45. }
  46. Ok(index.to_json())
  47. }
  48. fn add_section_to_index(index: &mut Index, section: &Section, library: &Library) {
  49. if !section.meta.in_search_index {
  50. return;
  51. }
  52. // Don't index redirecting sections
  53. if section.meta.redirect_to.is_none() {
  54. index.add_doc(
  55. &section.permalink,
  56. &[
  57. &section.meta.title.clone().unwrap_or_default(),
  58. &AMMONIA.clean(&section.content).to_string(),
  59. ],
  60. );
  61. }
  62. for key in &section.pages {
  63. let page = library.get_page_by_key(*key);
  64. if !page.meta.in_search_index {
  65. continue;
  66. }
  67. index.add_doc(
  68. &page.permalink,
  69. &[
  70. &page.meta.title.clone().unwrap_or_default(),
  71. &AMMONIA.clean(&page.content).to_string(),
  72. ],
  73. );
  74. }
  75. }