elio 1.3.0

Snappy, batteries-included terminal file manager with rich previews, inline images, bulk actions, and trash support.
Documentation
mod assets;
mod cache;
mod parse;
mod render;
mod toc;

use crate::preview::PreviewContent;
use std::{path::Path, time::SystemTime};

const EPUB_NAV_ENTRY_LIMIT_BYTES: usize = 96 * 1024;
const EPUB_CONTENT_ENTRY_LIMIT_BYTES: usize = 192 * 1024;
const EPUB_SECTION_TEXT_LIMIT_CHARS: usize = 32 * 1024;
const EPUB_COVER_ENTRY_LIMIT_BYTES: usize = 4 * 1024 * 1024;
const EPUB_SECTION_IMAGE_ENTRY_LIMIT_BYTES: usize = 32 * 1024 * 1024;
const EPUB_PACKAGE_CACHE_LIMIT: usize = 16;
const EPUB_ASSET_CACHE_VERSION: usize = 2;

pub(super) fn build_epub_preview(path: &Path, section_index: usize) -> Option<PreviewContent> {
    render::build_epub_preview(path, section_index)
}

#[cfg(test)]
pub(super) fn reset_epub_package_parse_count(path: &Path) {
    cache::reset_epub_package_parse_count(path);
}

#[cfg(test)]
pub(super) fn epub_package_parse_count(path: &Path) -> usize {
    cache::epub_package_parse_count(path)
}

#[cfg(test)]
pub(super) fn clear_epub_package_cache() {
    cache::clear_epub_package_cache();
}

fn append_epub_text_fragment(target: &mut String, fragment: &str) {
    let normalized = fragment.split_whitespace().collect::<Vec<_>>().join(" ");
    if normalized.is_empty() {
        return;
    }
    if !target.is_empty() && !target.chars().last().is_some_and(char::is_whitespace) {
        target.push(' ');
    }
    target.push_str(&normalized);
}

fn system_time_key(time: SystemTime) -> Option<(u64, u32)> {
    time.duration_since(SystemTime::UNIX_EPOCH)
        .ok()
        .map(|duration| (duration.as_secs(), duration.subsec_nanos()))
}