pub enum DocEntry { Section(&'static str), Topic(&'static str, &'static str), } use DocEntry::{Section, Topic}; pub const DOCS: &[DocEntry] = &[ // Getting Started Section("Getting Started"), Topic("Welcome", include_str!("../../docs/welcome.md")), Topic( "Navigation", include_str!("../../docs/getting-started/navigation.md"), ), Topic( "The Big Picture", include_str!("../../docs/getting-started/big_picture.md"), ), Topic( "Banks & Patterns", include_str!("../../docs/getting-started/banks_patterns.md"), ), Topic( "Stage / Commit", include_str!("../../docs/getting-started/staging.md"), ), Topic( "Using the Sequencer", include_str!("../../docs/getting-started/grid.md"), ), Topic( "Editing a Step", include_str!("../../docs/getting-started/editing.md"), ), Topic( "The Audio Engine", include_str!("../../docs/getting-started/engine.md"), ), Topic( "Options", include_str!("../../docs/getting-started/options.md"), ), Topic( "Saving & Loading", include_str!("../../docs/getting-started/saving.md"), ), Topic( "The Sample Browser", include_str!("../../docs/getting-started/samples.md"), ), // Forth fundamentals Section("Cagire's Forth"), Topic( "About Forth", include_str!("../../docs/forth/about_forth.md"), ), Topic( "The Dictionary", include_str!("../../docs/forth/dictionary.md"), ), Topic("The Stack", include_str!("../../docs/forth/stack.md")), Topic( "Creating Words", include_str!("../../docs/forth/definitions.md"), ), Topic( "Control Flow", include_str!("../../docs/forth/control_flow.md"), ), Topic("The Prelude", include_str!("../../docs/forth/prelude.md")), Topic( "Cagire vs Classic", include_str!("../../docs/forth/oddities.md"), ), // Audio Engine Section("Building sounds"), Topic("Introduction", include_str!("../../docs/engine/intro.md")), Topic("Settings", include_str!("../../docs/engine/settings.md")), Topic("Sources", include_str!("../../docs/engine/sources.md")), Topic("Samples", include_str!("../../docs/engine/samples.md")), Topic("Wavetables", include_str!("../../docs/engine/wavetable.md")), Topic("Filters", include_str!("../../docs/engine/filters.md")), Topic( "Modulation", include_str!("../../docs/engine/modulation.md"), ), Topic( "Distortion", include_str!("../../docs/engine/distortion.md"), ), Topic("Space & Time", include_str!("../../docs/engine/space.md")), Topic( "Audio-Rate Mod", include_str!("../../docs/engine/audio_modulation.md"), ), Topic("Words & Sounds", include_str!("../../docs/engine/words.md")), // MIDI Section("Branching out"), Topic("Introduction", include_str!("../../docs/midi/intro.md")), Topic("MIDI Output", include_str!("../../docs/midi/output.md")), Topic("MIDI Input", include_str!("../../docs/midi/input.md")), // Tutorials Section("Tutorials"), Topic( "Randomness", include_str!("../../docs/tutorials/randomness.md"), ), Topic( "Notes & Harmony", include_str!("../../docs/tutorials/harmony.md"), ), Topic( "Generators", include_str!("../../docs/tutorials/generators.md"), ), Topic("Timing with at", include_str!("../../docs/tutorials/at.md")), Topic( "Using Variables", include_str!("../../docs/tutorials/variables.md"), ), ]; pub fn topic_count() -> usize { DOCS.iter().filter(|e| matches!(e, Topic(_, _))).count() } pub fn section_count() -> usize { DOCS.iter().filter(|e| matches!(e, Section(_))).count() } pub fn section_index_for_topic(topic_idx: usize) -> usize { let mut section: usize = 0; let mut topic: usize = 0; for entry in DOCS.iter() { match entry { Section(_) => section += 1, Topic(_, _) => { if topic == topic_idx { return section.saturating_sub(1); } topic += 1; } } } section.saturating_sub(1) } pub fn first_topic_in_section(section_idx: usize) -> Option { let mut section: usize = 0; let mut topic: usize = 0; let mut in_target = false; for entry in DOCS.iter() { match entry { Section(_) => { if in_target { return None; } if section == section_idx { in_target = true; } section += 1; } Topic(_, _) => { if in_target { return Some(topic); } topic += 1; } } } None } pub fn get_topic(index: usize) -> Option<(&'static str, &'static str)> { DOCS.iter() .filter_map(|e| match e { Topic(name, content) => Some((*name, *content)), Section(_) => None, }) .nth(index) } pub fn find_match(query: &str) -> Option<(usize, usize)> { let query = query.to_lowercase(); for (topic_idx, (_, content)) in DOCS .iter() .filter_map(|e| match e { Topic(name, content) => Some((*name, *content)), Section(_) => None, }) .enumerate() { for (line_idx, line) in content.lines().enumerate() { if line.to_lowercase().contains(&query) { return Some((topic_idx, line_idx)); } } } None }