binocular-cli 0.2.3

Not exactly a telescope, but it's useful sometimes. TUI to search/navigate through files and workspaces.
Documentation
mod analysis;
mod detect;
mod hex_dump;
mod metadata;
mod strings;

use crate::preview::doc::PreviewDoc;
use ratatui::text::Text;
use std::fs;
use std::io::Read;
use std::path::Path;

pub(super) const HEADER_READ_BYTES: usize = 512;
pub(super) const ENTROPY_SAMPLE_BYTES: usize = 1024 * 1024;
pub(super) const HEX_DUMP_BYTES: usize = 128;
pub(super) const STRINGS_SAMPLE_BYTES: usize = 8192;
pub(super) const MIN_PRINTABLE_STRING_LEN: usize = 6;
pub(super) const MAX_PRINTABLE_STRINGS_SHOWN: usize = 15;
pub(super) const MAX_STRING_PREVIEW_LEN: usize = 60;

pub(super) const SECTION_FILE_INFO: &str = "File Info";
pub(super) const SECTION_FILE_TYPE: &str = "File Type";
pub(super) const SECTION_ANALYSIS: &str = "Analysis";
pub(super) const SECTION_HEX_DUMP: &str = "Hex Dump (first 128 bytes)";
pub(super) const SECTION_PRINTABLE_STRINGS: &str = "Printable Strings";

pub use analysis::calculate_entropy;
pub use hex_dump::create_hex_dump;
pub use strings::extract_printable_strings;

pub fn generate_preview(path: &Path) -> Text<'static> {
    let mut doc = PreviewDoc::new();
    metadata::append_file_metadata(path, &mut doc);

    let Ok(mut file) = fs::File::open(path) else {
        return doc.into_text();
    };

    let header = read_prefix(&mut file, HEADER_READ_BYTES);
    if header.is_empty() {
        return doc.into_text();
    }

    detect::append_file_type_info(path, &header, &mut doc);
    analysis::append_analysis(&mut file, &mut doc);
    hex_dump::append_hex_dump(&header, &mut doc);
    strings::append_printable_strings(path, &mut doc);

    doc.into_text()
}

pub(super) fn read_prefix(file: &mut fs::File, max_bytes: usize) -> Vec<u8> {
    if max_bytes == 0 {
        return Vec::new();
    }

    let mut buffer = vec![0u8; max_bytes];
    let bytes_read = file.read(&mut buffer).unwrap_or(0);
    buffer.truncate(bytes_read);
    buffer
}