binocular/preview/request/path/
fallback.rs1use 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}