diff options
author | Kyohei Uto <kyoheiu@outlook.com> | 2022-08-08 21:46:49 +0900 |
---|---|---|
committer | Kyohei Uto <kyoheiu@outlook.com> | 2022-08-08 21:46:49 +0900 |
commit | 4c7b3525fa031531513e1475b7079e6792d7c9f3 (patch) | |
tree | ab23006959954e8075f847af418bbf980fe1210c /src/layout.rs | |
parent | d655c236f6afe1f7225cb976d9c25b0dbfe86b9b (diff) |
Refactor: create layout.rs
Diffstat (limited to 'src/layout.rs')
-rw-r--r-- | src/layout.rs | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/layout.rs b/src/layout.rs new file mode 100644 index 0000000..fba0a09 --- /dev/null +++ b/src/layout.rs @@ -0,0 +1,203 @@ +use super::config::*; +use super::errors::FxError; +use super::functions::*; +use super::state::{FileType, ItemInfo, BEGINNING_ROW}; +use termion::{clear, color, cursor}; + +/// cf: https://docs.rs/image/latest/src/image/image.rs.html#84-112 +pub const MAX_SIZE_TO_PREVIEW: u64 = 1_000_000_000; +pub const IMAGE_EXTENSION: [&str; 20] = [ + "avif", "jpg", "jpeg", "png", "gif", "webp", "tif", "tiff", "tga", "dds", "bmp", "ico", "hdr", + "exr", "pbm", "pam", "ppm", "pgm", "ff", "farbfeld", +]; +pub const CHAFA_WARNING: &str = + "From v1.1.0, the image preview needs chafa. For more details, please see help by `:h` "; + +#[derive(Debug, Clone)] +pub struct Layout { + pub y: u16, + pub terminal_row: u16, + pub terminal_column: u16, + pub name_max_len: usize, + pub time_start_pos: u16, + pub use_full: Option<bool>, + pub option_name_len: Option<usize>, + pub colors: Color, + pub preview: bool, + pub preview_start_column: u16, + pub preview_width: u16, + pub has_chafa: bool, + pub is_kitty: bool, +} + +pub enum PreviewType { + TooBigSize, + Directory, + Image, + Text, + Binary, +} + +impl Layout { + /// Print preview according to the preview type. + pub fn print_preview(&self, item: &ItemInfo, y: u16) { + //At least print the item name + self.print_file_name(item); + //Clear preview space + self.clear_preview(self.preview_start_column); + + match check_preview_type(item) { + PreviewType::TooBigSize => { + print!("(Too big size to preview)"); + } + PreviewType::Directory => { + self.preview_content(item, true); + } + PreviewType::Image => { + if self.has_chafa { + if let Err(e) = self.preview_image(item, y) { + print_warning(e, y); + } + } else { + let help = format_txt(CHAFA_WARNING, self.terminal_column - 1, false); + for (i, line) in help.iter().enumerate() { + print!( + "{}", + cursor::Goto(self.preview_start_column, BEGINNING_ROW + i as u16) + ); + print!("{}", line,); + if BEGINNING_ROW + i as u16 == self.terminal_row - 1 { + break; + } + } + } + } + PreviewType::Text => { + self.preview_content(item, false); + } + PreviewType::Binary => { + print!("(Binary file)"); + } + } + } + + /// Print item name at the top. + fn print_file_name(&self, item: &ItemInfo) { + print!( + "{}{}", + cursor::Goto(self.preview_start_column, 1), + clear::UntilNewline + ); + let mut file_name = format!("[{}]", item.file_name); + if file_name.len() > self.preview_width.into() { + file_name = file_name.chars().take(self.preview_width.into()).collect(); + } + print!("{}", file_name); + } + + /// Print text preview on the right half of the terminal. + fn preview_content(&self, item: &ItemInfo, is_dir: bool) { + let content = if is_dir { + if let Ok(content) = list_up_contents(item.file_path.clone()) { + if let Ok(content) = make_tree(content) { + format_txt(&content, self.preview_width, false) + } else { + vec![] + } + } else { + vec![] + } + } else { + let item = item.file_path.clone(); + let column = self.terminal_column; + let content = std::fs::read_to_string(item); + if let Ok(content) = content { + let content = content.replace('\t', " "); + format_txt(&content, column - 1, false) + } else { + vec![] + } + }; + + //Print preview (wrapping) + for (i, line) in content.iter().enumerate() { + print!( + "{}", + cursor::Goto(self.preview_start_column, BEGINNING_ROW + i as u16) + ); + print!( + "{}{}{}", + color::Fg(color::LightBlack), + line, + color::Fg(color::Reset) + ); + if BEGINNING_ROW + i as u16 == self.terminal_row - 1 { + break; + } + } + } + + /// Print text preview on the right half of the terminal (Experimental). + fn preview_image(&self, item: &ItemInfo, y: u16) -> Result<(), FxError> { + let wxh = format!( + "--size={}x{}", + self.preview_width, + self.terminal_row - BEGINNING_ROW + ); + + let file_path = item.file_path.to_str(); + if file_path.is_none() { + print_warning("Cannot read the file path correctly.", y); + return Ok(()); + } + + let output = std::process::Command::new("chafa") + .args(["--animate=false", &wxh, file_path.unwrap()]) + .output()? + .stdout; + let output = String::from_utf8(output).unwrap(); + for (i, line) in output.lines().enumerate() { + let next_line: u16 = BEGINNING_ROW + (i as u16) + 1; + print!("{}", line); + print!("{}", cursor::Goto(self.preview_start_column, next_line)); + } + Ok(()) + } + + /// Clear the preview space. + fn clear_preview(&self, preview_start_column: u16) { + for i in 0..self.terminal_row { + print!( + "{}", + cursor::Goto(preview_start_column, BEGINNING_ROW + i as u16) + ); + print!("{}", clear::UntilNewline); + } + print!("{}", cursor::Goto(self.preview_start_column, BEGINNING_ROW)); + } +} + +/// Check preview type. +fn check_preview_type(item: &ItemInfo) -> PreviewType { + if item.file_size > MAX_SIZE_TO_PREVIEW { + PreviewType::TooBigSize + } else if item.file_type == FileType::Directory { + PreviewType::Directory + } else if is_supported_ext(item) { + PreviewType::Image + } else { + let content_type = content_inspector::inspect(&std::fs::read(&item.file_path).unwrap()); + if content_type.is_text() { + PreviewType::Text + } else { + PreviewType::Binary + } + } +} + +fn is_supported_ext(item: &ItemInfo) -> bool { + match &item.file_ext { + None => false, + Some(ext) => IMAGE_EXTENSION.contains(&ext.as_str()), + } +} |