summaryrefslogtreecommitdiffstats
path: root/src/layout.rs
diff options
context:
space:
mode:
authorKyohei Uto <kyoheiu@outlook.com>2022-08-08 21:46:49 +0900
committerKyohei Uto <kyoheiu@outlook.com>2022-08-08 21:46:49 +0900
commit4c7b3525fa031531513e1475b7079e6792d7c9f3 (patch)
treeab23006959954e8075f847af418bbf980fe1210c /src/layout.rs
parentd655c236f6afe1f7225cb976d9c25b0dbfe86b9b (diff)
Refactor: create layout.rs
Diffstat (limited to 'src/layout.rs')
-rw-r--r--src/layout.rs203
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()),
+ }
+}