diff options
author | qkzk <qu3nt1n@gmail.com> | 2022-10-07 16:09:38 +0200 |
---|---|---|
committer | qkzk <qu3nt1n@gmail.com> | 2022-10-07 16:09:38 +0200 |
commit | e747bc2aaf6ada3756f3d40ba0bbd006b34e7ff1 (patch) | |
tree | 617c817a4104435ceb31c922cf99140406438177 | |
parent | 6b219ea85fb7e33fc747f9007b016b16a740bcf2 (diff) |
WIP: preview binary files
-rw-r--r-- | Cargo.lock | 10 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/display.rs | 47 | ||||
-rw-r--r-- | src/fileinfo.rs | 6 | ||||
-rw-r--r-- | src/preview.rs | 43 |
5 files changed, 102 insertions, 5 deletions
@@ -135,6 +135,15 @@ dependencies = [ ] [[package]] +name = "content_inspector" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +dependencies = [ + "memchr", +] + +[[package]] name = "core-foundation-sys" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -206,6 +215,7 @@ version = "0.1.0" dependencies = [ "chrono", "clap", + "content_inspector", "regex", "serde_yaml", "shellexpand", @@ -21,3 +21,4 @@ shellexpand = "2.1.2" syntect = "5.0" tuikit = "*" users = "0.11.0" +content_inspector = "0.2.4" diff --git a/src/display.rs b/src/display.rs index 4b2a34ef..4829c378 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,4 +1,5 @@ use std::cmp::min; +use std::io::Read; use tuikit::attr::*; use tuikit::term::Term; @@ -239,8 +240,54 @@ impl Display { let _ = self.term.print(row, line_number_width + 3, line); } } + Preview::Binary(bin) => { + let mut reader = + std::io::BufReader::new(std::fs::File::open(bin.path.clone()).unwrap()); + let mut buffer = Box::new(vec![]); + reader.read_to_end(&mut buffer).unwrap(); + let mut line: Vec<u8> = vec![]; + for (i, byte) in buffer + .iter() + .enumerate() + .skip(16 * status.window.top) + .take(min(length, 16 * status.window.bottom + 1)) + { + let row = i + ContentWindow::WINDOW_MARGIN_TOP - status.window.top; + if line.len() < 16 { + line.push(*byte); + } else { + let _ = self.term.print_with_attr( + row / 16, + 0, + &format_line_nr_hex((i + 1 + status.window.top) / 16), + Attr { + fg: Color::CYAN, + ..Default::default() + }, + ); + let _ = self.term.print( + row / 16, + line_number_width + 3, + &format_line_of_bytes(line), + ); + line = vec![]; + } + } + } Preview::Empty => (), } } } } + +fn format_line_nr_hex(line_nr: usize) -> String { + format!("{:x>}", line_nr) +} + +fn format_line_of_bytes(bytes: Vec<u8>) -> String { + bytes + .iter() + .map(|byte| format!("{:02x}", byte)) + .collect::<Vec<String>>() + .join(" ") +} diff --git a/src/fileinfo.rs b/src/fileinfo.rs index ee91f03e..02f77cf2 100644 --- a/src/fileinfo.rs +++ b/src/fileinfo.rs @@ -105,6 +105,8 @@ pub struct FileInfo { pub path: path::PathBuf, /// Filename pub filename: String, + /// size (nb of bytes) of the file + pub size: u64, /// File size as a `String`, already human formated. pub file_size: String, /// First symbol displaying the kind of file. @@ -129,7 +131,8 @@ impl FileInfo { pub fn new(direntry: &DirEntry) -> Result<FileInfo, &'static str> { let path = direntry.path(); let filename = extract_filename(direntry); - let file_size = human_size(extract_file_size(direntry)); + let size = extract_file_size(direntry); + let file_size = human_size(size); let permissions = extract_permissions_string(direntry); let owner = extract_owner(direntry); let system_time = extract_datetime(direntry); @@ -144,6 +147,7 @@ impl FileInfo { Ok(FileInfo { path, filename, + size, file_size, dir_symbol, permissions, diff --git a/src/preview.rs b/src/preview.rs index 6e56b703..5d1162b8 100644 --- a/src/preview.rs +++ b/src/preview.rs @@ -1,5 +1,7 @@ -use std::io::BufRead; +use std::io::{BufRead, Read}; +use std::path::PathBuf; +use content_inspector::{inspect, ContentType}; use syntect::easy::HighlightLines; use syntect::highlighting::{Style, ThemeSet}; use syntect::parsing::{SyntaxReference, SyntaxSet}; @@ -11,6 +13,7 @@ use crate::fileinfo::PathContent; pub enum Preview { SyntaxedPreview(SyntaxedContent), TextPreview(TextContent), + Binary(BinaryContent), Empty, } @@ -23,10 +26,21 @@ impl Preview { let ps = SyntaxSet::load_defaults_nonewlines(); match path_content.selected_file() { Some(file) => { - if let Some(syntaxset) = ps.find_syntax_by_extension(&file.extension) { - Self::SyntaxedPreview(SyntaxedContent::new(ps.clone(), path_content, syntaxset)) + let mut f = std::fs::File::open(file.path.clone()).unwrap(); + let mut buffer = vec![0; 1024]; + f.read_exact(&mut buffer).unwrap(); + if inspect(&buffer) == ContentType::BINARY { + Self::Binary(BinaryContent::new(path_content.to_owned())) } else { - Self::TextPreview(TextContent::from_file(path_content)) + if let Some(syntaxset) = ps.find_syntax_by_extension(&file.extension) { + Self::SyntaxedPreview(SyntaxedContent::new( + ps.clone(), + path_content, + syntaxset, + )) + } else { + Self::TextPreview(TextContent::from_file(path_content)) + } } } None => Self::Empty, @@ -38,6 +52,7 @@ impl Preview { Self::SyntaxedPreview(syntaxed) => syntaxed.len(), Self::TextPreview(text) => text.len(), Self::Empty => 0, + Self::Binary(binary) => binary.len(), } } @@ -173,3 +188,23 @@ impl SyntaxedString { let _ = term.print_with_attr(row, self.col + offset + 2, &self.content, self.attr); } } + +pub struct BinaryContent { + pub path: PathBuf, + length: u64, +} + +impl BinaryContent { + fn new(path_content: PathContent) -> Self { + let file = path_content.selected_file().unwrap(); + + Self { + path: file.path.clone(), + length: file.size, + } + } + + fn len(&self) -> usize { + self.length as usize + } +} |