use {
super::*,
crate::{
app::{AppContext, LineNumber},
command::ScrollCommand,
display::*,
errors::ProgramError,
hex::HexView,
image::ImageView,
pattern::InputPattern,
skin::PanelSkin,
syntactic::SyntacticView,
task_sync::Dam,
},
crossterm::{cursor, QueueableCommand},
std::{
io,
path::Path,
},
termimad::Area,
};
pub enum Preview {
Image(ImageView),
Syntactic(SyntacticView),
Hex(HexView),
ZeroLen(ZeroLenFileView),
IOError(io::Error),
}
impl Preview {
pub fn new(
path: &Path,
prefered_mode: Option<PreviewMode>,
con: &AppContext,
) -> Self {
match prefered_mode {
Some(PreviewMode::Hex) => Self::hex(path),
Some(PreviewMode::Image) => Self::image(path),
Some(PreviewMode::Text) => Self::unfiltered_text(path, con),
None => {
ImageView::new(path)
.map(Self::Image)
.unwrap_or_else(|_| Self::unfiltered_text(path, con))
}
}
}
pub fn with_mode(
path: &Path,
mode: PreviewMode,
con: &AppContext,
) -> Result<Self, ProgramError> {
match mode {
PreviewMode::Hex => {
Ok(HexView::new(path.to_path_buf()).map(Self::Hex)?)
}
PreviewMode::Image => {
ImageView::new(path).map(Self::Image)
}
PreviewMode::Text => {
Ok(
SyntacticView::new(path, InputPattern::none(), &mut Dam::unlimited(), con)
.transpose()
.expect("syntactic view without pattern shouldn't be none")
.map(Self::Syntactic)?,
)
}
}
}
pub fn image(path: &Path) -> Self {
ImageView::new(path)
.ok()
.map(Self::Image)
.unwrap_or_else(|| Self::hex(path))
}
pub fn unfiltered_text(
path: &Path,
con: &AppContext,
) -> Self {
match SyntacticView::new(path, InputPattern::none(), &mut Dam::unlimited(), con) {
Ok(Some(sv)) => Self::Syntactic(sv),
Err(ProgramError::ZeroLenFile) => {
debug!("zero len file - check if system file");
Self::ZeroLen(ZeroLenFileView::new(path.to_path_buf()))
}
_ => Self::hex(path),
}
}
pub fn filtered(
&self,
path: &Path,
pattern: InputPattern,
dam: &mut Dam,
con: &AppContext,
) -> Option<Self> {
match self {
Self::Syntactic(_) => {
match SyntacticView::new(path, pattern, dam, con) {
Ok(Some(sv)) => Some(Self::Syntactic(sv)),
Ok(None) => None,
Err(_) => Some(Self::hex(path)),
}
}
_ => None,
}
}
pub fn hex(path: &Path) -> Self {
match HexView::new(path.to_path_buf()) {
Ok(reader) => Self::Hex(reader),
Err(e) => {
warn!("error while previewing {:?} : {:?}", path, e);
Self::IOError(e)
}
}
}
pub fn get_mode(&self) -> Option<PreviewMode> {
match self {
Self::Image(_) => Some(PreviewMode::Image),
Self::Syntactic(_) => Some(PreviewMode::Text),
Self::ZeroLen(_) => Some(PreviewMode::Text),
Self::Hex(_) => Some(PreviewMode::Hex),
Self::IOError(_) => None,
}
}
pub fn pattern(&self) -> InputPattern {
match self {
Self::Syntactic(sv) => sv.pattern.clone(),
_ => InputPattern::none(),
}
}
pub fn try_scroll(
&mut self,
cmd: ScrollCommand,
) -> bool {
match self {
Self::Syntactic(sv) => sv.try_scroll(cmd),
Self::Hex(hv) => hv.try_scroll(cmd),
_ => false,
}
}
pub fn is_filterable(&self) -> bool {
matches!(self, Self::Syntactic(_))
}
pub fn get_selected_line(&self) -> Option<String> {
match self {
Self::Syntactic(sv) => sv.get_selected_line(),
_ => None,
}
}
pub fn get_selected_line_number(&self) -> Option<LineNumber> {
match self {
Self::Syntactic(sv) => sv.get_selected_line_number(),
_ => None,
}
}
pub fn try_select_line_number(&mut self, number: usize) -> bool {
match self {
Self::Syntactic(sv) => sv.try_select_line_number(number),
_ => false,
}
}
pub fn unselect(&mut self) {
if let Self::Syntactic(sv) = self {
sv.unselect();
}
}
pub fn try_select_y(&mut self, y: u16) -> bool {
match self {
Self::Syntactic(sv) => sv.try_select_y(y),
_ => false,
}
}
pub fn move_selection(&mut self, dy: i32, cycle: bool) {
match self {
Self::Syntactic(sv) => sv.move_selection(dy, cycle),
Self::Hex(hv) => {
hv.try_scroll(ScrollCommand::Lines(dy));
}
_ => {}
}
}
pub fn select_first(&mut self) {
match self {
Self::Syntactic(sv) => sv.select_first(),
Self::Hex(hv) => hv.select_first(),
_ => {}
}
}
pub fn select_last(&mut self) {
match self {
Self::Syntactic(sv) => sv.select_last(),
Self::Hex(hv) => hv.select_last(),
_ => {}
}
}
pub fn display(
&mut self,
w: &mut W,
screen: Screen,
panel_skin: &PanelSkin,
area: &Area,
con: &AppContext,
) -> Result<(), ProgramError> {
match self {
Self::Image(iv) => iv.display(w, screen, panel_skin, area, con),
Self::Syntactic(sv) => sv.display(w, screen, panel_skin, area, con),
Self::ZeroLen(zlv) => zlv.display(w, screen, panel_skin, area),
Self::Hex(hv) => hv.display(w, screen, panel_skin, area),
Self::IOError(err) => {
let mut y = area.top;
w.queue(cursor::MoveTo(area.left, y))?;
let mut cw = CropWriter::new(w, area.width as usize);
cw.queue_str(&panel_skin.styles.default, "An error prevents the preview:")?;
cw.fill(&panel_skin.styles.default, &SPACE_FILLING)?;
y += 1;
w.queue(cursor::MoveTo(area.left, y))?;
let mut cw = CropWriter::new(w, area.width as usize);
cw.queue_g_string(&panel_skin.styles.status_error, err.to_string())?;
cw.fill(&panel_skin.styles.default, &SPACE_FILLING)?;
y += 1;
while y < area.top + area.height {
w.queue(cursor::MoveTo(area.left, y))?;
let mut cw = CropWriter::new(w, area.width as usize);
cw.fill(&panel_skin.styles.default, &SPACE_FILLING)?;
y += 1;
}
Ok(())
}
}
}
pub fn display_info(
&mut self,
w: &mut W,
screen: Screen,
panel_skin: &PanelSkin,
area: &Area,
) -> Result<(), ProgramError> {
match self {
Self::Image(iv) => iv.display_info(w, screen, panel_skin, area),
Self::Syntactic(sv) => sv.display_info(w, screen, panel_skin, area),
Self::Hex(hv) => hv.display_info(w, screen, panel_skin, area),
_ => Ok(()),
}
}
}