# Biblicist

[![Crates.io](https://img.shields.io/crates/v/biblicist.svg)](https://crates.io/crates/biblicist)
[![Docs.rs](https://docs.rs/biblicist/badge.svg)](https://docs.rs/biblicist)

`biblicist` is a Rust crate designed to provide a robust toolkit for working with biblical data. Its core features include a powerful Bible reference parser, a comprehensive data store for all 66 canonical books, and a utility for parsing Greek morphological codes.

This crate is ideal for developers building Bible study applications, research tools, or any software that needs to interpret and handle scriptural references and related linguistic data.

---

> **Note**: This README and some of the crate's data (specifically the book chapter/verse layouts and the expanded list of aliases/abbreviations) were generated with assistance from AI. The data has been sourced from reputable public references but is still pending full verification. Please use with discretion and report any inaccuracies.

> **Other Note**: This crate is still in its infancy. Breaking changes may occur even on minor releases at this point.
## Features

- **Reference Parsing**: Find and parse Bible references from any string. It recognizes a vast array of book names, aliases, and abbreviations.
- **Comprehensive Book Data**: Access detailed information for all 66 books of the Protestant canon, including chapter counts, verse counts, and sort orders for various canons (English, Vulgate, Septuagint, etc.).
- **Flexible Reference Handling**: Parse references into `Single` verse, full `Chapter`, or `Range` types, with a user-friendly display format.
- **Text Analysis**: Locate references within a larger body of text and extract them along with their byte offsets.
- **Morphology Parsing**: Parse standard Greek morphological codes (e.g., Robinson, Tyndale) into structured `Parsing` objects.

## Usage

### Parsing References

The primary function of this crate is to find and parse Bible references from text. It can handle simple strings, text with surrounding content, and a wide variety of book name formats.

```rust
use biblicist::{parse_reference, Text};

fn main() {
    // Parse a simple reference
    let refs = parse_reference("For God so loved the world, that he gave his only Son (Jhn 3:16).");
    assert_eq!(refs[0].to_string(), "John 3:16");

    // Parse a reference with a common abbreviation and a range
    let refs_range = parse_reference("Read 1 Cor 13:4-7");
    assert_eq!(refs_range[0].to_string(), "1 Corinthians 13:4-7");

    // Parse a full chapter reference
    let chapter_ref = parse_reference("The sermon on the mount is in Matthew 5.");
    assert_eq!(chapter_ref[0].to_string(), "Matthew 5");

    // Use the Text struct to get references with their locations
    let text = Text::parse("See Gen 1 and also Exodus 20.");
    assert_eq!(text.references.len(), 2);
    assert_eq!(text.get_text(&text.references[0]), "Gen 1");
    assert_eq!(text.references[0].start, 4);
    assert_eq!(text.references[0].end, 9);

    // You can also get the original text with references stripped out
    assert_eq!(text.text_without_references(), "See and also");
}
```

### Working with Book Data

You can access data for any of the 66 books to get chapter counts, verse counts, or check names.

```rust
use biblicist::{get_book, GENESIS};

fn main() {
    // Get a book by its name, alias, or abbreviation
    let Some(book) = get_book("Gen") else { return };
    assert_eq!(book.title, "Genesis");

    // Get the number of chapters in the book
    assert_eq!(book.chapters(), 50);

    // Get the number of verses in a specific chapter
    assert_eq!(book.verses_in_chapter(1), Some(31));
    assert_eq!(book.verses_in_chapter(51), None); // Chapter 51 doesn't exist

    // You can also use the static book constants directly
    assert!(GENESIS.is_name("The First Book of Moses"));
}
```

### Sorting References

The `Reference` object provides a `sort()` method that returns a tuple of `u32` values, allowing for easy canonical sorting of references. It defaults to the standard English canon order.

```rust
use biblicist::{parse_reference, Reference};

fn main() {
    let mut refs = vec![
        parse_reference("Malachi 4:6").pop().unwrap(),
        parse_reference("Genesis 1:1").pop().unwrap(),
        parse_reference("Matthew 1:1").pop().unwrap(),
    ];

    // Sort references canonically
    refs.sort_by_key(|r| r.sort());

    assert_eq!(refs[0].to_string(), "Genesis 1:1");
    assert_eq!(refs[1].to_string(), "Malachi 4:6");
    assert_eq!(refs[2].to_string(), "Matthew 1:1");
}
```

### Morphology Parsing

Parse Greek morphology codes into a structured format. This is useful when working with interlinear or tagged biblical texts.

```rust
use biblicist::{Parsing, PartOfSpeech, Tense, Voice, Mood, Case, Number, Gender};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let code = "V-PAP-DSM";
    let parsing: Parsing = code.parse()?;

    assert_eq!(parsing.part_of_speech, Some(PartOfSpeech::Verb));
    assert_eq!(parsing.tense, Some(Tense::Present));
    assert_eq!(parsing.voice, Some(Voice::Active));
    assert_eq!(parsing.mood, Some(Mood::Participle));
    assert_eq!(parsing.case, Some(Case::Dative));
    assert_eq!(parsing.number, Some(Number::Singular));
    assert_eq!(parsing.gender, Some(Gender::Masculine));

    // You can also serialize it to JSON
    let json = parsing.to_json_string();
    println!("{}", json);
    // Output: {"part_of_speech":"verb","case":"dative","number":"singular","gender":"masculine","tense":"present","voice":"active","mood":"participle","person":null}

    Ok(())
}
```
Hebrew morphology is planned.

## Book Data & Abbreviations

This crate includes a comprehensive list of aliases and abbreviations for all 66 canonical books, ensuring a high degree of accuracy in parsing. The data is sourced and cross-referenced from multiple authoritative systems, including:

- Logos Bible Software
- The OSIS/CrossWire Standard
- USFM/Paratext Identifiers
- The SBL Handbook of Style
- BibleGateway

This allows the parser to recognize a wide variety of formats, from common abbreviations (`Gen`, `Ex`, `1 Cor`) to less common aliases (`1 Kingdoms` for 1 Samuel) and standard identifiers (`GEN` for Genesis).
