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.

88 lines
2.4KB

  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. add_section_to_index(&mut index, section, library);
  43. }
  44. Ok(index.to_json())
  45. }
  46. fn add_section_to_index(index: &mut Index, section: &Section, library: &Library) {
  47. if !section.meta.in_search_index {
  48. return;
  49. }
  50. // Don't index redirecting sections
  51. if section.meta.redirect_to.is_none() {
  52. index.add_doc(
  53. &section.permalink,
  54. &[
  55. &section.meta.title.clone().unwrap_or_default(),
  56. &AMMONIA.clean(&section.content).to_string(),
  57. ],
  58. );
  59. }
  60. for key in &section.pages {
  61. let page = library.get_page_by_key(*key);
  62. if !page.meta.in_search_index {
  63. continue;
  64. }
  65. index.add_doc(
  66. &page.permalink,
  67. &[
  68. &page.meta.title.clone().unwrap_or_default(),
  69. &AMMONIA.clean(&page.content).to_string(),
  70. ],
  71. );
  72. }
  73. }