summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/commands/preview_cursor_move.rs6
-rw-r--r--src/config/clean/app/preview/config.rs12
-rw-r--r--src/config/raw/app/display/preview.rs14
-rw-r--r--src/context/app_context.rs48
-rw-r--r--src/context/preview_context.rs198
-rw-r--r--src/event/app_event.rs18
-rw-r--r--src/event/process_event.rs45
-rw-r--r--src/preview/preview_default.rs18
-rw-r--r--src/preview/preview_file.rs107
-rw-r--r--src/ui/views/tui_folder_view.rs73
10 files changed, 354 insertions, 185 deletions
diff --git a/src/commands/preview_cursor_move.rs b/src/commands/preview_cursor_move.rs
index a59faa6..6959fb8 100644
--- a/src/commands/preview_cursor_move.rs
+++ b/src/commands/preview_cursor_move.rs
@@ -14,7 +14,7 @@ fn preview_cursor_move(context: &mut AppContext, new_index: usize) -> AppResult
let preview_context = context.preview_context_mut();
if let Some(file_path) = file_path {
- if let Some(PreviewFileState::Success { data }) =
+ if let Some(PreviewFileState::Success(data)) =
preview_context.previews_mut().get_mut(&file_path)
{
data.index = new_index;
@@ -32,7 +32,7 @@ pub fn preview_up(context: &mut AppContext, u: usize) -> AppResult {
let preview_context = context.preview_context_ref();
if let Some(file_path) = file_path {
- if let Some(PreviewFileState::Success { data }) =
+ if let Some(PreviewFileState::Success(data)) =
preview_context.previews_ref().get(file_path)
{
if data.index < u {
@@ -62,7 +62,7 @@ pub fn preview_down(context: &mut AppContext, u: usize) -> AppResult {
let preview_context = context.preview_context_ref();
if let Some(file_path) = file_path {
- if let Some(PreviewFileState::Success { data }) =
+ if let Some(PreviewFileState::Success(data)) =
preview_context.previews_ref().get(file_path)
{
Some(data.index + u)
diff --git a/src/config/clean/app/preview/config.rs b/src/config/clean/app/preview/config.rs
index 2fd50e5..e14407e 100644
--- a/src/config/clean/app/preview/config.rs
+++ b/src/config/clean/app/preview/config.rs
@@ -1,18 +1,18 @@
use std::path;
use crate::{
- config::{raw::app::display::preview::PreviewOptionRaw, search_directories},
+ config::{
+ raw::app::display::preview::{default_max_preview_size, PreviewOptionRaw, PreviewProtocol},
+ search_directories,
+ },
util::unix,
CONFIG_HIERARCHY,
};
-const fn default_max_preview_size() -> u64 {
- 2 * 1024 * 1024 // 2 MB
-}
-
#[derive(Clone, Debug)]
pub struct PreviewOption {
pub max_preview_size: u64,
+ pub preview_protocol: PreviewProtocol,
pub preview_script: Option<path::PathBuf>,
pub preview_shown_hook_script: Option<path::PathBuf>,
pub preview_removed_hook_script: Option<path::PathBuf>,
@@ -22,6 +22,7 @@ impl std::default::Default for PreviewOption {
fn default() -> Self {
Self {
max_preview_size: default_max_preview_size(),
+ preview_protocol: PreviewProtocol::Auto,
preview_script: None,
preview_shown_hook_script: None,
preview_removed_hook_script: None,
@@ -46,6 +47,7 @@ impl From<PreviewOptionRaw> for PreviewOption {
Self {
max_preview_size: raw.max_preview_size,
+ preview_protocol: raw.preview_protocol,
preview_script,
preview_shown_hook_script,
preview_removed_hook_script,
diff --git a/src/config/raw/app/display/preview.rs b/src/config/raw/app/display/preview.rs
index 60bb032..ee3682e 100644
--- a/src/config/raw/app/display/preview.rs
+++ b/src/config/raw/app/display/preview.rs
@@ -1,14 +1,27 @@
+use ratatui_image::picker::ProtocolType;
use serde::Deserialize;
pub const fn default_max_preview_size() -> u64 {
2 * 1024 * 1024 // 2 MB
}
+#[derive(Clone, Debug, Deserialize, Default)]
+#[serde(rename_all = "snake_case")]
+pub enum PreviewProtocol {
+ #[default]
+ Auto,
+ Disabled,
+ #[serde(untagged)]
+ ProtocolType(ProtocolType),
+}
+
#[derive(Clone, Debug, Deserialize)]
pub struct PreviewOptionRaw {
#[serde(default = "default_max_preview_size")]
pub max_preview_size: u64,
#[serde(default)]
+ pub preview_protocol: PreviewProtocol,
+ #[serde(default)]
pub preview_script: Option<String>,
#[serde(default)]
pub preview_shown_hook_script: Option<String>,
@@ -20,6 +33,7 @@ impl std::default::Default for PreviewOptionRaw {
fn default() -> Self {
Self {
max_preview_size: default_max_preview_size(),
+ preview_protocol: PreviewProtocol::Auto,
preview_script: None,
preview_shown_hook_script: None,
preview_removed_hook_script: None,
diff --git a/src/context/app_context.rs b/src/context/app_context.rs
index 35af553..0026a52 100644
--- a/src/context/app_context.rs
+++ b/src/context/app_context.rs
@@ -5,15 +5,17 @@ use std::thread;
use crate::commands::quit::QuitAction;
use crate::config::clean::app::AppConfig;
+use crate::config::raw::app::display::preview::PreviewProtocol;
use crate::context::{
CommandLineContext, LocalStateContext, MatchContext, MessageQueue, PreviewContext, TabContext,
UiContext, WorkerContext,
};
use crate::event::{AppEvent, Events};
-use crate::ui::views;
-use crate::ui::PreviewArea;
+use crate::preview::preview_file::PreviewFileState;
+use crate::ui::{views, AppBackend, PreviewArea};
use crate::Args;
use notify::{RecursiveMode, Watcher};
+use ratatui_image::picker::Picker;
use std::path;
pub struct AppContext {
@@ -51,6 +53,28 @@ pub struct AppContext {
impl AppContext {
pub fn new(config: AppConfig, args: Args) -> Self {
+ let picker = if config
+ .preview_options_ref()
+ .preview_shown_hook_script
+ .is_none()
+ {
+ Picker::from_termios().ok().and_then(|mut picker| {
+ match config.preview_options_ref().preview_protocol {
+ PreviewProtocol::Auto => {
+ picker.guess_protocol(); // Must run before Events::new() because it makes ioctl calls.
+ Some(picker)
+ }
+ PreviewProtocol::Disabled => None,
+ PreviewProtocol::ProtocolType(protocol_type) => {
+ picker.protocol_type = protocol_type;
+ Some(picker)
+ }
+ }
+ })
+ } else {
+ None
+ };
+
let events = Events::new();
let event_tx = events.event_tx.clone();
@@ -66,6 +90,8 @@ impl AppContext {
.unwrap();
let watched_paths = HashSet::with_capacity(3);
+ let preview_script = config.preview_options_ref().preview_script.clone();
+
Self {
quit: QuitAction::DoNot,
events,
@@ -74,8 +100,8 @@ impl AppContext {
local_state: None,
search_context: None,
message_queue: MessageQueue::new(),
- worker_context: WorkerContext::new(event_tx),
- preview_context: PreviewContext::new(),
+ worker_context: WorkerContext::new(event_tx.clone()),
+ preview_context: PreviewContext::new(picker, preview_script, event_tx),
ui_context: UiContext { layout: vec![] },
commandline_context,
config,
@@ -279,4 +305,18 @@ impl AppContext {
pub fn commandline_context_mut(&mut self) -> &mut CommandLineContext {
&mut self.commandline_context
}
+ pub fn load_preview(&mut self, backend: &AppBackend, path: path::PathBuf) {
+ // always load image without cache
+ self.preview_context_mut().set_image_preview(None);
+ self.preview_context
+ .load_preview_image(self, backend, path.clone());
+
+ let previews = self.preview_context_mut().previews_mut();
+ if previews.get(path.as_path()).is_none() {
+ // add to loading state
+ previews.insert(path.clone(), PreviewFileState::Loading);
+ self.preview_context
+ .load_preview_script(self, backend, path);
+ }
+ }
}
diff --git a/src/context/preview_context.rs b/src/context/preview_context.rs
index 51e593d..57184a8 100644
--- a/src/context/preview_context.rs
+++ b/src/context/preview_context.rs
@@ -1,25 +1,215 @@
use std::collections::HashMap;
-use std::path;
+use std::error::Error;
+use std::path::{self, PathBuf};
+use std::process::{Command, Stdio};
+use std::sync::mpsc::{self, Sender};
+use std::sync::Mutex;
+use std::{io, thread};
-use crate::preview::preview_file::PreviewFileState;
+use ratatui::layout::Rect;
+use ratatui_image::picker::Picker;
+use ratatui_image::protocol::Protocol;
+use ratatui_image::Resize;
+
+use crate::config::clean::app::AppConfig;
+use crate::event::{AppEvent, PreviewData};
+use crate::lazy_static;
+use crate::preview::preview_file::{FilePreview, PreviewFileState};
+use crate::ui::{views, AppBackend};
+use crate::AppContext;
+
+lazy_static! {
+ static ref GUARD: Mutex<()> = Mutex::new(());
+}
type FilePreviewMetadata = HashMap<path::PathBuf, PreviewFileState>;
pub struct PreviewContext {
previews: FilePreviewMetadata,
+ image_preview: Option<(PathBuf, Box<dyn Protocol>)>,
+ sender_script: Sender<(PathBuf, Rect)>,
+ sender_image: Option<Sender<(PathBuf, Rect)>>,
+ event_ts: Sender<AppEvent>,
}
impl PreviewContext {
- pub fn new() -> Self {
- Self {
+ pub fn new(
+ picker: Option<Picker>,
+ script: Option<PathBuf>,
+ event_ts: Sender<AppEvent>,
+ ) -> PreviewContext {
+ let (sender_script, receiver) = mpsc::channel::<(PathBuf, Rect)>();
+ let thread_script_event_ts = event_ts.clone();
+ thread::spawn(move || {
+ for (path, rect) in receiver {
+ if let Some(ref script) = script {
+ PreviewContext::spawn_command(
+ path.clone(),
+ script.to_path_buf(),
+ rect,
+ thread_script_event_ts.clone(),
+ );
+ }
+ }
+ });
+
+ let (sender_image, receiver) = mpsc::channel::<(PathBuf, Rect)>();
+ let sender_image = picker.map(|mut picker| {
+ let thread_image_event_ts = event_ts.clone();
+ thread::spawn(move || loop {
+ // Get last, or block for next.
+ if let Some((path, rect)) = receiver
+ .try_iter()
+ .last()
+ .or_else(|| receiver.iter().next())
+ {
+ let proto = image::io::Reader::open(path.as_path())
+ .and_then(|reader| reader.decode().map_err(Self::map_io_err))
+ .and_then(|dyn_img| {
+ picker
+ .new_protocol(dyn_img, rect, Resize::Fit)
+ .map_err(|err| {
+ io::Error::new(io::ErrorKind::Other, format!("{err}"))
+ })
+ });
+ if let Ok(proto) = proto {
+ let ev = AppEvent::PreviewFile {
+ path,
+ res: Ok(PreviewData::Image(proto)),
+ };
+ let _ = thread_image_event_ts.send(ev);
+ }
+ } else {
+ // Closed.
+ return;
+ }
+ });
+ sender_image
+ });
+
+ PreviewContext {
previews: HashMap::new(),
+ image_preview: None,
+ sender_script,
+ sender_image,
+ event_ts,
}
}
+ fn spawn_command(
+ path: PathBuf,
+ script: PathBuf,
+ rect: Rect,
+ thread_event_ts: Sender<AppEvent>,
+ ) {
+ let output = Command::new(script)
+ .stdout(Stdio::piped())
+ .stderr(Stdio::null())
+ .arg("--path")
+ .arg(path.as_path())
+ .arg("--preview-width")
+ .arg(rect.width.to_string())
+ .arg("--preview-height")
+ .arg(rect.height.to_string())
+ .output();
+
+ let res = match output {
+ Ok(output) => {
+ if output.status.success() {
+ let preview = FilePreview::from(output);
+ AppEvent::PreviewFile {
+ path,
+ res: Ok(PreviewData::Script(Box::new(preview))),
+ }
+ } else {
+ AppEvent::PreviewFile {
+ path,
+ res: Err(io::Error::new(io::ErrorKind::Other, "nonzero status")),
+ }
+ }
+ }
+ Err(err) => AppEvent::PreviewFile {
+ path,
+ res: Err(io::Error::new(io::ErrorKind::Other, format!("{err}"))),
+ },
+ };
+ let _ = thread_event_ts.send(res);
+ }
+
pub fn previews_ref(&self) -> &FilePreviewMetadata {
&self.previews
}
pub fn previews_mut(&mut self) -> &mut FilePreviewMetadata {
&mut self.previews
}
+ pub fn image_preview_ref(&self, other: &path::Path) -> Option<&dyn Protocol> {
+ match &self.image_preview {
+ Some((path, protocol)) if path == other => Some(protocol.as_ref()),
+ _ => None,
+ }
+ }
+ pub fn set_image_preview(&mut self, preview: Option<(path::PathBuf, Box<dyn Protocol>)>) {
+ self.image_preview = preview;
+ }
+
+ pub fn load_preview_script(
+ &self,
+ context: &AppContext,
+ backend: &AppBackend,
+ path: path::PathBuf,
+ ) {
+ if let Err(err) = Self::backend_rect(context.config_ref(), backend).and_then(|rect| {
+ self.sender_script
+ .send((path.clone(), rect))
+ .map_err(Self::map_io_err)
+ }) {
+ let ev = AppEvent::PreviewFile {
+ path,
+ res: Err(err),
+ };
+ let _ = self.event_ts.send(ev);
+ }
+ }
+
+ pub fn load_preview_image(
+ &self,
+ context: &AppContext,
+ backend: &AppBackend,
+ path: path::PathBuf,
+ ) {
+ if let Some(sender) = &self.sender_image {
+ if let Err(err) = Self::backend_rect(context.config_ref(), backend)
+ .and_then(|rect| sender.send((path.clone(), rect)).map_err(Self::map_io_err))
+ {
+ let ev = AppEvent::PreviewFile {
+ path,
+ res: Err(err),
+ };
+ let _ = self.event_ts.send(ev);
+ }
+ }
+ }
+
+ fn backend_rect(config: &AppConfig, backend: &AppBackend) -> io::Result<Rect> {
+ let area = backend.terminal_ref().size()?;
+ let area = Rect {
+ y: area.top() + 1,
+ height: area.height - 2,
+ ..area
+ };
+
+ let display_options = config.display_options_ref();
+ let constraints = &display_options.default_layout;
+ let layout = if display_options.show_borders() {
+ views::calculate_layout_with_borders(area, constraints)
+ } else {
+ views::calculate_layout(area, constraints)
+ };
+ Ok(layout[2])
+ }
+
+ #[inline]
+ fn map_io_err(err: impl Error) -> io::Error {
+ io::Error::new(io::ErrorKind::Other, format!("{err}"))
+ }
}
diff --git a/src/event/app_event.rs b/src/event/app_event.rs
index d628517..f6d538b 100644
--- a/src/event/app_event.rs
+++ b/src/event/app_event.rs
@@ -1,8 +1,10 @@
+use std::fmt::Debug;
use std::io;
use std::path;
use std::sync::mpsc;
use std::thread;
+use ratatui_image::protocol::Protocol;
use signal_hook::consts::signal;
use signal_hook::iterator::exfiltrator::SignalOnly;
use signal_hook::iterator::SignalsInfo;
@@ -17,6 +19,20 @@ use crate::fs::JoshutoDirList;
use crate::io::FileOperationProgress;
use crate::preview::preview_file::FilePreview;
+pub enum PreviewData {
+ Script(Box<FilePreview>),
+ Image(Box<dyn Protocol>),
+}
+
+impl Debug for PreviewData {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Script(_) => f.debug_tuple("Script").field(&"_").finish(),
+ Self::Image(_) => f.debug_tuple("Image").field(&"_").finish(),
+ }
+ }
+}
+
#[derive(Debug)]
pub enum AppEvent {
// User input events
@@ -38,7 +54,7 @@ pub enum AppEvent {
},
PreviewFile {
path: path::PathBuf,
- res: Box<io::Result<FilePreview>>,
+ res: io::Result<PreviewData>,
},
// terminal size change events
Signal(i32),
diff --git a/src/event/process_event.rs b/src/event/process_event.rs
index 6e308b7..0848dc8 100644
--- a/src/event/process_event.rs
+++ b/src/event/process_event.rs
@@ -13,12 +13,13 @@ use crate::config::clean::keymap::KeyMapping;
use crate::context::AppContext;
use crate::error::AppResult;
use crate::event::AppEvent;
+use crate::event::PreviewData;
use crate::fs::JoshutoDirList;
use crate::history::DirectoryHistory;
use crate::io::FileOperationProgress;
use crate::key_command::{AppExecute, Command, CommandKeybind};
use crate::preview::preview_dir::PreviewDirState;
-use crate::preview::preview_file::{FilePreview, PreviewFileState};
+use crate::preview::preview_file::PreviewFileState;
use crate::ui;
use crate::ui::views::TuiCommandMenu;
use crate::util::format;
@@ -64,7 +65,7 @@ pub fn process_noninteractive(event: AppEvent, context: &mut AppContext) {
AppEvent::FileOperationProgress(res) => process_worker_progress(context, res),
AppEvent::IoWorkerResult(res) => process_finished_worker(context, res),
AppEvent::PreviewDir { id, path, res } => process_dir_preview(context, id, path, *res),
- AppEvent::PreviewFile { path, res } => process_file_preview(context, path, *res),
+ AppEvent::PreviewFile { path, res } => process_file_preview(context, path, res),
AppEvent::Signal(signal::SIGWINCH) => {}
AppEvent::Filesystem(e) => process_filesystem_event(e, context),
AppEvent::ChildProcessComplete(child_id) => {
@@ -173,33 +174,29 @@ pub fn process_dir_preview(
pub fn process_file_preview(
context: &mut AppContext,
path: path::PathBuf,
- res: io::Result<FilePreview>,
+ res: io::Result<PreviewData>,
) {
+ let preview_context = context.preview_context_mut();
match res {
- Ok(preview) => {
- if preview.status.code().is_some() {
- context
- .preview_context_mut()
- .previews_mut()
- .insert(path, PreviewFileState::Success { data: preview });
- } else {
- context.preview_context_mut().previews_mut().insert(
- path,
- PreviewFileState::Error {
- message: "Unknown error".to_string(),
- },
- );
- }
+ Ok(PreviewData::Script(output)) if output.status.code().is_some() => {
+ preview_context
+ .previews_mut()
+ .insert(path, PreviewFileState::Success(*output));
+ }
+ Ok(PreviewData::Script(_)) => {
+ preview_context
+ .previews_mut()
+ .insert(path, PreviewFileState::Error("status error".to_owned()));
+ }
+ Ok(PreviewData::Image(protocol)) => {
+ preview_context.set_image_preview(Some((path, protocol)));
}
Err(e) => {
- context.preview_context_mut().previews_mut().insert(
- path,
- PreviewFileState::Error {
- message: e.to_string(),
- },
- );
+ preview_context
+ .previews_mut()
+ .insert(path, PreviewFileState::Error(e.to_string()));
}
- }
+ };
}
pub fn process_unsupported(
diff --git a/src/preview/preview_default.rs b/src/preview/preview_default.rs
index 28b85e1..35ced0c 100644
--- a/src/preview/preview_default.rs
+++ b/src/preview/preview_default.rs
@@ -2,11 +2,9 @@ use std::path;
use crate::context::AppContext;
use crate::fs::JoshutoMetadata;
-use crate::preview::{preview_dir, preview_file};
+use crate::preview::preview_dir;
use crate::ui::AppBackend;
-use super::preview_file::PreviewFileState;
-
pub fn load_preview_path(
context: &mut AppContext,
backend: &mut AppBackend,
@@ -33,19 +31,7 @@ pub fn load_preview_path(
preview_dir::Background::load_preview(context, p);
}
} else if metadata.len() <= preview_options.max_preview_size {
- let need_to_load = context
- .preview_context_ref()
- .previews_ref()
- .get(p.as_path())
- .map(|data| match data {
- PreviewFileState::Success { data } => data.modified < metadata.modified(),
- _ => false,
- })
- .unwrap_or(true);
-
- if need_to_load {
- preview_file::Background::preview_path_with_script(context, backend, p);
- }
+ context.load_preview(backend, p);
}
}
diff --git a/src/preview/preview_file.rs b/src/preview/preview_file.rs
index 9b4194a..ab73428 100644
--- a/src/preview/preview_file.rs
+++ b/src/preview/preview_file.rs
@@ -1,24 +1,20 @@
-use std::path;
-use std::process::{Command, Output};
-use std::sync::Mutex;
-use std::thread;
-use std::time;
-
-use ratatui::layout::Rect;
-
-use crate::context::AppContext;
-use crate::event::AppEvent;
-use crate::lazy_static;
-use crate::ui::{views, AppBackend};
-
-lazy_static! {
- static ref GUARD: Mutex<()> = Mutex::new(());
-}
+use std::fmt::Debug;
+use std::{process::Output, time};
pub enum PreviewFileState {
Loading,
- Error { message: String },
- Success { data: FilePreview },
+ Error(String),
+ Success(FilePreview),
+}
+
+impl Debug for PreviewFileState {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Loading => f.debug_tuple("Loading").finish(),
+ Self::Error(message) => f.debug_tuple("Error").field(message).finish(),
+ Self::Success(_) => f.debug_tuple("Success").finish(),
+ }
+ }
}
#[derive(Clone, Debug)]
@@ -43,78 +39,3 @@ impl std::convert::From<Output> for FilePreview {
}
}
}
-
-pub struct Background {}
-
-impl Background {
- pub fn preview_path_with_script(
- context: &mut AppContext,
- backend: &mut AppBackend,
- path: path::PathBuf,
- ) {
- let preview_options = context.config_ref().preview_options_ref();
- if let Some(script) = preview_options.preview_script.as_ref() {
- if let Ok(area) = backend.terminal_ref().size() {
- let area = Rect {
- y: area.top() + 1,
- height: area.height - 2,
- ..area
- };
-
- let config = context.config_ref();
- let display_options = config.display_options_ref();
- let constraints = &display_options.default_layout;
- let layout = if display_options.show_borders() {
- views::calculate_layout_with_borders(area, constraints)
- } else {
- views::calculate_layout(area, constraints)
- };
- let layout_rect = layout[2];
- let preview_width = layout_rect.width;
- let preview_height = layout_rect.height;
-
- if preview_width == 0 || preview_height == 0 {
- return;
- }
-
- let script = script.clone();
- let event_tx = context.clone_event_tx();
- context
- .preview_context_mut()
- .previews_mut()
- .insert(path.clone(), PreviewFileState::Loading);
-
- let _ = thread::spawn(move || {
- let _locked = GUARD.lock().unwrap();
- let file_full_path = path.as_path();
-
- let res = Command::new(script)
- .arg("--path")
- .arg(file_full_path)
- .arg("--preview-width")
- .arg(preview_width.to_string())
- .arg("--preview-height")
- .arg(preview_height.to_string())
- .output();
- match res {
- Ok(output) => {
- let preview = FilePreview::from(output);
- let res = AppEvent::PreviewFile {
- path,
- res: Box::new(Ok(preview)),
- };
- let _ = event_tx.send(res);
- }
- Err(e) => {
- let res = AppEvent::PreviewFile {
- path,
- res: Box::new(Err(e)),
- };
- let _ = event_tx.send(res);
- }
- }
- });
- }
- }
- }
-}
diff --git a/src/ui/views/tui_folder_view.rs b/src/ui/views/tui_folder_view.rs
index 68b94ad..2d9538c 100644
--- a/src/ui/views/tui_folder_view.rs
+++ b/src/ui/views/tui_folder_view.rs
@@ -4,6 +4,7 @@ use ratatui::style::{Color, Style};
use ratatui::symbols::line::{HORIZONTAL_DOWN, HORIZONTAL_UP};
use ratatui::text::Span;
use ratatui::widgets::{Block, Borders, Paragraph, Widget, Wrap};
+use ratatui_image::Image;
use crate::context::AppContext;
use crate::preview::preview_dir::PreviewDirState;
@@ -195,21 +196,32 @@ impl<'a> Widget for TuiFolderView<'a> {
.render(layout_rect[2], buf);
}
None => {
- let preview_area = calculate_preview(self.context, layout_rect[2]);
- if let Some(preview_area) = preview_area {
- let area = Rect {
- x: preview_area.preview_area.x,
- y: preview_area.preview_area.y,
- width: preview_area.preview_area.width,
- height: preview_area.preview_area.height,
- };
- if let Some(PreviewFileState::Success { data }) = preview_context
- .previews_ref()
- .get(&preview_area.file_preview_path)
- {
+ let image_offset = match preview_context.image_preview_ref(entry.file_path()) {
+ Some(protocol) => {
+ let area = layout_rect[2];
+ Image::new(protocol).render(area, buf);
+ protocol.rect().height
+ }
+ _ => 0,
+ };
+
+ if let Some(PreviewFileState::Success(data)) =
+ preview_context.previews_ref().get(entry.file_path())
+ {
+ let preview_area = calculate_preview(self.context, layout_rect[2]);
+ if let Some(preview_area) = preview_area {
+ let area = Rect {
+ x: preview_area.preview_area.x,
+ y: preview_area.preview_area.y + image_offset,
+ width: preview_area.preview_area.width,
+ height: preview_area
+ .preview_area
+ .height
+ .saturating_sub(image_offset),
+ };
TuiFilePreview::new(data).render(area, buf);
}
- }
+ };
}
}
} else {
@@ -268,11 +280,8 @@ pub fn get_constraints(context: &AppContext) -> &[Constraint; 3] {
&display_options.default_layout
}
Some(entry) => match preview_context.previews_ref().get(entry.file_path()) {
- Some(PreviewFileState::Success { data }) if data.status.code() != Some(1) => {
- &display_options.default_layout
- }
- Some(PreviewFileState::Loading) => &display_options.default_layout,
- _ => &display_options.no_preview_layout,
+ None => &display_options.no_preview_layout,
+ _ => &display_options.default_layout,
},
},
}
@@ -327,24 +336,18 @@ pub fn calculate_preview(context: &AppContext, rect: Rect) -> Option<PreviewArea
if child_list.as_ref().is_some() {
None
} else if let Some(entry) = curr_entry {
- if let Some(PreviewFileState::Success { data }) =
- preview_context.previews_ref().get(entry.file_path())
- {
- match data.status.code() {
- Some(1) | None => None,
- _ => {
- let file_preview_path = entry.file_path_buf();
- let preview_area = ui::Rect {
- x: rect.x,
- y: rect.y,
- width: rect.width,
- height: rect.height,
- };
- Some(PreviewArea::new(file_preview_path, preview_area))
- }
+ match preview_context.previews_ref().get(entry.file_path()) {
+ None | Some(PreviewFileState::Loading) | Some(PreviewFileState::Error(_)) => None,
+ _ => {
+ let file_preview_path = entry.file_path_buf();
+ let preview_area = ui::Rect {
+ x: rect.x,
+ y: rect.y,
+ width: rect.width,
+ height: rect.height,
+ };
+ Some(PreviewArea::new(file_preview_path, preview_area))
}
- } else {
- None
}
} else {
None