Skip to main content

binocular/preview/request/path/
fallback.rs

1use crate::preview::{binary, encoding, rich_text::create_rich_text_document, PreviewContent};
2use ratatui::text::Text;
3use std::fs;
4use std::path::Path;
5
6pub(crate) enum FileContent {
7    Text(String),
8    Binary,
9    ReadError,
10}
11
12pub(crate) fn build_text_or_binary_preview(path: &Path) -> PreviewContent {
13    match read_file_content(path) {
14        FileContent::Text(text) => PreviewContent::RichText(create_rich_text_document(text, path)),
15        FileContent::Binary => PreviewContent::PlainText(binary::generate_preview(path)),
16        FileContent::ReadError => PreviewContent::PlainText(Text::from("Error opening file")),
17    }
18}
19
20fn read_file_content(path: &Path) -> FileContent {
21    match fs::read_to_string(path) {
22        Ok(content) => {
23            if content.as_bytes().contains(&0) {
24                FileContent::Binary
25            } else {
26                FileContent::Text(content)
27            }
28        }
29        Err(_) => read_non_utf8_file(path),
30    }
31}
32
33fn read_non_utf8_file(path: &Path) -> FileContent {
34    let bytes = match fs::read(path) {
35        Ok(bytes) => bytes,
36        Err(_) => return FileContent::ReadError,
37    };
38
39    if let Some(utf8_content) = encoding::try_decode_utf16(&bytes) {
40        return FileContent::Text(utf8_content);
41    }
42
43    let likely_binary = bytes.contains(&0)
44        || crate::text::proportion_of_printable_ascii_characters(&bytes)
45            < crate::text::PRINTABLE_ASCII_THRESHOLD;
46    if likely_binary {
47        return FileContent::Binary;
48    }
49
50    FileContent::Text(String::from_utf8_lossy(&bytes).into_owned())
51}