use termion::event::Key;
use unicode_width::UnicodeWidthStr;
use std::path::{Path, PathBuf};
use crate::files::{File, Files};
use crate::fail::{HResult, HError, ErrorLog};
use crate::term;
use crate::widget::{Widget, WidgetCore};
use crate::dirty::Dirtyable;
pub trait Listable {
fn len(&self) -> usize;
fn render(&self) -> Vec<String>;
fn render_header(&self) -> HResult<String> { Ok("".to_string()) }
fn render_footer(&self) -> HResult<String> { Ok("".to_string()) }
fn on_new(&mut self) -> HResult<()> { Ok(()) }
fn on_refresh(&mut self) -> HResult<()> { Ok(()) }
fn on_key(&mut self, _key: Key) -> HResult<()> { Ok(()) }
}
use crate::keybind::{Acting, Bindings, FileListAction, Movement};
impl Acting for ListView<Files> {
type Action=FileListAction;
fn search_in(&self) -> Bindings<Self::Action> {
self.core.config().keybinds.filelist
}
fn movement(&mut self, movement: &Movement) -> HResult<()> {
use Movement::*;
match movement {
Up(n) => { for _ in 0..*n { self.move_up(); }; self.refresh()?; }
Down(n) => { for _ in 0..*n { self.move_down(); }; self.refresh()?; }
PageUp => self.page_up(),
PageDown => self.page_down(),
Top => self.move_top(),
Bottom => self.move_bottom(),
Left | Right => {}
}
Ok(())
}
fn do_action(&mut self, action: &Self::Action) -> HResult<()> {
use FileListAction::*;
match action {
Search => self.search_file()?,
SearchNext => self.search_next()?,
SearchPrev => self.search_prev()?,
Filter => self.filter()?,
Select => self.multi_select_file(),
InvertSelection => self.invert_selection(),
ClearSelection => self.clear_selections(),
FilterSelection => self.toggle_filter_selected(),
ToggleTag => self.toggle_tag()?,
ToggleHidden => self.toggle_hidden(),
ReverseSort => self.reverse_sort(),
CycleSort => self.cycle_sort(),
ToNextMtime => self.select_next_mtime(),
ToPrevMtime => self.select_prev_mtime(),
ToggleDirsFirst => self.toggle_dirs_first(),
}
Ok(())
}
}
impl Listable for ListView<Files> {
fn len(&self) -> usize {
self.content.len()
}
fn render(&self)-> Vec<String> {
self.render()
}
fn on_new(&mut self) -> HResult<()> {
let show_hidden = self.core.config().show_hidden();
self.content.show_hidden = show_hidden;
Ok(())
}
fn on_refresh(&mut self) -> HResult<()> {
if self.content.len() == 0 {
let path = &self.content.directory.path;
let placeholder = File::new_placeholder(&path)?;
self.content.files.push(placeholder);
}
let sender = self.core.get_sender();
let visible_files = self.core.coordinates.size_u().1 + self.offset + 1;
self.content.meta_upto(visible_files, Some(sender.clone()));
self.refresh_files().log();
if self.content.is_dirty() {
self.content.set_clean();
self.core.set_dirty();
}
if self.content.dirty_meta.is_dirty() {
self.content.meta_upto(visible_files, Some(sender.clone()));
self.core.set_dirty();
}
Ok(())
}
fn on_key(&mut self, key: Key) -> HResult<()> {
self.do_key(key)
}
}
#[derive(Debug, PartialEq)]
pub struct ListView<T> where ListView<T>: Listable
{
pub content: T,
pub lines: usize,
selection: usize,
pub offset: usize,
pub buffer: Vec<String>,
pub core: WidgetCore,
seeking: bool,
searching: Option<String>,
}
impl<T> ListView<T>
where
ListView<T>: Widget,
ListView<T>: Listable
{
pub fn new(core: &WidgetCore, content: T) -> ListView<T> {
let mut view = ListView::<T> {
content: content,
lines: 0,
selection: 0,
offset: 0,
buffer: Vec::new(),
core: core.clone(),
seeking: false,
searching: None
};
view.on_new().log();
view
}
pub fn move_up(&mut self