mirror of https://github.com/bobwen-dev/hunter
big performance improvement
This commit is contained in:
parent
33a9562379
commit
8b1c4db9cf
|
@ -0,0 +1,35 @@
|
|||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||
pub struct DirtyBit(bool);
|
||||
|
||||
pub trait Dirtyable {
|
||||
fn get_bit(&self) -> &DirtyBit;
|
||||
fn get_bit_mut(&mut self) -> &mut DirtyBit;
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
self.get_bit().0
|
||||
}
|
||||
|
||||
fn set_dirty(&mut self) {
|
||||
self.get_bit_mut().0 = true;
|
||||
}
|
||||
fn set_clean(&mut self) {
|
||||
self.get_bit_mut().0 = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl DirtyBit {
|
||||
pub fn new() -> DirtyBit {
|
||||
DirtyBit(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Dirtyable for DirtyBit {
|
||||
fn get_bit(&self) -> &DirtyBit {
|
||||
self
|
||||
}
|
||||
fn get_bit_mut(&mut self) -> &mut DirtyBit {
|
||||
self
|
||||
}
|
||||
}
|
21
src/files.rs
21
src/files.rs
|
@ -13,6 +13,7 @@ use failure::Error;
|
|||
use notify::DebouncedEvent;
|
||||
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::dirty::{DirtyBit, Dirtyable};
|
||||
|
||||
|
||||
|
||||
|
@ -54,7 +55,8 @@ pub struct Files {
|
|||
pub sort: SortBy,
|
||||
pub dirs_first: bool,
|
||||
pub reverse: bool,
|
||||
pub show_hidden: bool
|
||||
pub show_hidden: bool,
|
||||
pub dirty: DirtyBit
|
||||
}
|
||||
|
||||
impl Index<usize> for Files {
|
||||
|
@ -65,7 +67,15 @@ impl Index<usize> for Files {
|
|||
}
|
||||
|
||||
|
||||
impl Dirtyable for Files {
|
||||
fn get_bit(&self) -> &DirtyBit {
|
||||
&self.dirty
|
||||
}
|
||||
|
||||
fn get_bit_mut(&mut self) -> &mut DirtyBit {
|
||||
&mut self.dirty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Files {
|
||||
|
@ -88,7 +98,8 @@ impl Files {
|
|||
sort: SortBy::Name,
|
||||
dirs_first: true,
|
||||
reverse: false,
|
||||
show_hidden: true
|
||||
show_hidden: true,
|
||||
dirty: DirtyBit::new()
|
||||
};
|
||||
|
||||
files.sort();
|
||||
|
@ -131,7 +142,8 @@ impl Files {
|
|||
sort: SortBy::Name,
|
||||
dirs_first: true,
|
||||
reverse: false,
|
||||
show_hidden: true
|
||||
show_hidden: true,
|
||||
dirty: DirtyBit::new()
|
||||
};
|
||||
|
||||
files.sort();
|
||||
|
@ -188,6 +200,7 @@ impl Files {
|
|||
if self.reverse {
|
||||
self.files.reverse();
|
||||
}
|
||||
self.set_dirty();
|
||||
}
|
||||
|
||||
pub fn cycle_sort(&mut self) {
|
||||
|
@ -216,6 +229,7 @@ impl Files {
|
|||
.collect();
|
||||
|
||||
self.files = files;
|
||||
self.set_dirty();
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self, event: &DebouncedEvent) -> HResult<()> {
|
||||
|
@ -247,6 +261,7 @@ impl Files {
|
|||
},
|
||||
_ => {},
|
||||
}
|
||||
self.set_dirty();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use termion::event::Key;
|
||||
use failure::Fail;
|
||||
use chrono::{DateTime, TimeZone, Local};
|
||||
use chrono::{DateTime, Local};
|
||||
|
||||
use crate::term;
|
||||
use crate::widget::Widget;
|
||||
use crate::listview::{ListView, Listable};
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::dirty::Dirtyable;
|
||||
|
||||
pub type LogView = ListView<Vec<LogEntry>>;
|
||||
|
||||
|
@ -82,25 +83,30 @@ pub trait FoldableWidgetExt {
|
|||
|
||||
impl FoldableWidgetExt for ListView<Vec<LogEntry>> {
|
||||
fn on_refresh(&mut self) -> HResult<()> {
|
||||
self.content.refresh_logs()
|
||||
if self.content.refresh_logs()? > 0 {
|
||||
self.core.set_dirty();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
trait LogList {
|
||||
fn refresh_logs(&mut self) -> HResult<()>;
|
||||
fn refresh_logs(&mut self) -> HResult<usize>;
|
||||
}
|
||||
|
||||
impl LogList for Vec<LogEntry> {
|
||||
fn refresh_logs(&mut self) -> HResult<()> {
|
||||
fn refresh_logs(&mut self) -> HResult<usize> {
|
||||
let logs = crate::fail::get_logs()?;
|
||||
|
||||
let mut logentries = logs.into_iter().map(|log| {
|
||||
LogEntry::from(log)
|
||||
}).collect();
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let n = logentries.len();
|
||||
|
||||
self.append(&mut logentries);
|
||||
//self.truncate(10);
|
||||
Ok(())
|
||||
|
||||
Ok(n)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +160,8 @@ where
|
|||
self.set_selection(fold_pos);
|
||||
}
|
||||
|
||||
self.refresh()
|
||||
self.core.set_dirty();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fold_start_pos(&self, fold: usize) -> usize {
|
||||
|
@ -201,11 +208,9 @@ where
|
|||
}
|
||||
|
||||
fn render(&self) -> Vec<String> {
|
||||
let (xsize, ysize) = self.core.coordinates.size_u();
|
||||
let offset = self.offset;
|
||||
let (xsize, _) = self.core.coordinates.size_u();
|
||||
self.content
|
||||
.iter()
|
||||
//.skip(offset)
|
||||
.map(|foldable|
|
||||
foldable
|
||||
.render()
|
||||
|
@ -213,8 +218,6 @@ where
|
|||
.map(|line| term::sized_string_u(line, xsize))
|
||||
.collect::<Vec<_>>())
|
||||
.flatten()
|
||||
.skip(offset)
|
||||
.take(ysize+1)
|
||||
.collect()
|
||||
}
|
||||
fn on_refresh(&mut self) -> HResult<()> {
|
||||
|
@ -223,18 +226,12 @@ where
|
|||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
Key::Up | Key::Char('p') => {
|
||||
self.move_up();
|
||||
self.refresh()?;
|
||||
}
|
||||
Key::Char('P') => { for _ in 0..10 { self.move_up() } self.refresh()?; }
|
||||
Key::Char('N') => { for _ in 0..10 { self.move_down() } self.refresh()?; }
|
||||
Key::Down | Key::Char('n') => {
|
||||
self.move_down();
|
||||
self.refresh()?;
|
||||
},
|
||||
Key::Char('t') => { self.toggle_fold()?; }
|
||||
Key::Char('l') => { self.popup_finnished()?; }
|
||||
Key::Up | Key::Char('p') => self.move_up(),
|
||||
Key::Char('P') => for _ in 0..10 { self.move_up() },
|
||||
Key::Char('N') => for _ in 0..10 { self.move_down() },
|
||||
Key::Down | Key::Char('n') => self.move_down(),
|
||||
Key::Char('t') => self.toggle_fold()?,
|
||||
Key::Char('l') => self.popup_finnished()?,
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::files::{File, Files};
|
|||
use crate::fail::{HResult, ErrorLog};
|
||||
use crate::term;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::dirty::Dirtyable;
|
||||
|
||||
pub trait Listable {
|
||||
fn len(&self) -> usize;
|
||||
|
@ -27,6 +28,11 @@ impl Listable for ListView<Files> {
|
|||
fn on_refresh(&mut self) -> HResult<()> {
|
||||
let visible_file_num = self.selection + self.get_coordinates()?.ysize() as usize;
|
||||
self.content.meta_upto(visible_file_num);
|
||||
|
||||
if self.content.is_dirty() {
|
||||
self.core.set_dirty();
|
||||
self.content.set_clean();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -366,13 +372,9 @@ impl ListView<Files>
|
|||
}
|
||||
|
||||
fn render(&self) -> Vec<String> {
|
||||
let ysize = self.get_coordinates().unwrap().ysize() as usize;
|
||||
let offset = self.offset;
|
||||
self.content
|
||||
.files
|
||||
.iter()
|
||||
.skip(offset)
|
||||
.take(ysize)
|
||||
.map(|file| self.render_line(&file))
|
||||
.collect()
|
||||
}
|
||||
|
@ -389,10 +391,15 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
|
|||
fn refresh(&mut self) -> HResult<()> {
|
||||
self.on_refresh().log();
|
||||
self.lines = self.len();
|
||||
|
||||
if self.selection >= self.lines && self.selection != 0 {
|
||||
self.selection -= 1;
|
||||
}
|
||||
self.buffer = self.render();
|
||||
|
||||
if self.core.is_dirty() || self.buffer.len() != self.len() {
|
||||
self.buffer = self.render();
|
||||
self.core.set_clean();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -400,10 +407,13 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
|
|||
fn get_drawlist(&self) -> HResult<String> {
|
||||
let mut output = term::reset();
|
||||
let (xpos, ypos) = self.get_coordinates().unwrap().position().position();
|
||||
let ysize = self.get_coordinates().unwrap().ysize() as usize;
|
||||
|
||||
output += &self
|
||||
.buffer
|
||||
.iter()
|
||||
.skip(self.offset)
|
||||
.take(ysize)
|
||||
.enumerate()
|
||||
.map(|(i, item)| {
|
||||
let mut output = term::normal_color();
|
||||
|
@ -425,9 +435,6 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
|
|||
|
||||
Ok(output)
|
||||
}
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
Ok(format!("{} files", self.len()))
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
Listable::on_key(self, key)
|
||||
|
|
|
@ -45,6 +45,8 @@ mod proclist;
|
|||
mod bookmarks;
|
||||
mod paths;
|
||||
mod foldview;
|
||||
mod dirty;
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ fn kill_proc() -> HResult<()> {
|
|||
}
|
||||
|
||||
pub fn is_stale(stale: &Arc<Mutex<bool>>) -> HResult<bool> {
|
||||
let stale = *(stale.try_lock().unwrap());
|
||||
let stale = *(stale.lock().unwrap());
|
||||
Ok(stale)
|
||||
}
|
||||
|
||||
|
@ -405,7 +405,6 @@ impl Previewer {
|
|||
.to_string();
|
||||
let mut textview = TextView {
|
||||
lines: output.lines().map(|s| s.to_string()).collect(),
|
||||
buffer: String::new(),
|
||||
core: core.clone(),
|
||||
follow: false,
|
||||
offset: 0};
|
||||
|
|
|
@ -150,6 +150,6 @@ impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
|
|||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
Tabbable::on_key(self, key)?;
|
||||
self.refresh()
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@ pub trait ScreenExt: Write {
|
|||
}
|
||||
fn reset(&mut self) -> HResult<()> {
|
||||
write!(self, "{}", termion::style::Reset)?;
|
||||
self.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
fn clear(&mut self) -> HResult<()> {
|
||||
|
@ -60,7 +59,6 @@ pub trait ScreenExt: Write {
|
|||
}
|
||||
fn write_str(&mut self, str: &str) -> HResult<()> {
|
||||
write!(self, "{}", str)?;
|
||||
self.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
fn goto_xy(&mut self, x: usize, y: usize) -> HResult<()> {
|
||||
|
@ -149,6 +147,9 @@ pub fn sized_string_u(string: &str, xsize: usize) -> String {
|
|||
|
||||
// Do these as constants
|
||||
|
||||
|
||||
|
||||
|
||||
pub fn highlight_color() -> String {
|
||||
format!(
|
||||
"{}",
|
||||
|
|
|
@ -4,11 +4,11 @@ use crate::files::File;
|
|||
use crate::term::sized_string;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::fail::HResult;
|
||||
use crate::dirty::Dirtyable;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct TextView {
|
||||
pub lines: Vec<String>,
|
||||
pub buffer: String,
|
||||
pub core: WidgetCore,
|
||||
pub follow: bool,
|
||||
pub offset: usize,
|
||||
|
@ -18,7 +18,6 @@ impl TextView {
|
|||
pub fn new_blank(core: &WidgetCore) -> TextView {
|
||||
TextView {
|
||||
lines: vec![],
|
||||
buffer: String::new(),
|
||||
core: core.clone(),
|
||||
follow: false,
|
||||
offset: 0,
|
||||
|
@ -35,7 +34,6 @@ impl TextView {
|
|||
|
||||
Ok(TextView {
|
||||
lines: lines,
|
||||
buffer: String::new(),
|
||||
core: core.clone(),
|
||||
follow: false,
|
||||
offset: 0,
|
||||
|
@ -56,7 +54,6 @@ impl TextView {
|
|||
|
||||
Ok(TextView {
|
||||
lines: lines,
|
||||
buffer: String::new(),
|
||||
core: core.clone(),
|
||||
follow: false,
|
||||
offset: 0,
|
||||
|
@ -66,6 +63,7 @@ impl TextView {
|
|||
pub fn set_text(&mut self, text: &str) -> HResult<()> {
|
||||
let lines = text.lines().map(|l| l.to_string()).collect();
|
||||
self.lines = lines;
|
||||
self.core.set_dirty();
|
||||
self.refresh()
|
||||
}
|
||||
|
||||
|
@ -94,6 +92,10 @@ impl TextView {
|
|||
self.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if offset != self.offset as isize {
|
||||
self.core.set_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_up(&mut self) {
|
||||
|
@ -140,8 +142,17 @@ impl Widget for TextView {
|
|||
self.scroll_bottom();
|
||||
}
|
||||
|
||||
if self.core.is_dirty() {
|
||||
self.core.set_clean();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
self.buffer = self.get_clearlist()? +
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
let (xsize, ysize) = self.get_coordinates()?.size().size();
|
||||
let (xpos, ypos) = self.get_coordinates()?.position().position();
|
||||
|
||||
let output = self.get_clearlist()? +
|
||||
&self
|
||||
.lines
|
||||
.iter()
|
||||
|
@ -156,10 +167,6 @@ impl Widget for TextView {
|
|||
sized_string(&line, xsize))
|
||||
})
|
||||
.collect::<String>();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
Ok(self.buffer.clone())
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||
use std::io::Write;
|
||||
|
||||
use termion::event::{Event, Key, MouseEvent};
|
||||
use termion::input::TermRead;
|
||||
|
@ -9,6 +10,7 @@ use crate::fail::{HResult, HError, ErrorLog};
|
|||
use crate::minibuffer::MiniBuffer;
|
||||
use crate::term;
|
||||
use crate::term::{Screen, ScreenExt};
|
||||
use crate::dirty::{Dirtyable, DirtyBit};
|
||||
|
||||
use std::io::stdin;
|
||||
|
||||
|
@ -47,7 +49,8 @@ pub struct WidgetCore {
|
|||
pub minibuffer: Arc<Mutex<Option<MiniBuffer>>>,
|
||||
pub event_sender: Sender<Events>,
|
||||
event_receiver: Arc<Mutex<Option<Receiver<Events>>>>,
|
||||
pub status_bar_content: Arc<Mutex<Option<String>>>
|
||||
pub status_bar_content: Arc<Mutex<Option<String>>>,
|
||||
dirty: DirtyBit
|
||||
}
|
||||
|
||||
impl WidgetCore {
|
||||
|
@ -66,7 +69,8 @@ impl WidgetCore {
|
|||
minibuffer: Arc::new(Mutex::new(None)),
|
||||
event_sender: sender,
|
||||
event_receiver: Arc::new(Mutex::new(Some(receiver))),
|
||||
status_bar_content: status_bar_content };
|
||||
status_bar_content: status_bar_content,
|
||||
dirty: DirtyBit::new() };
|
||||
|
||||
let minibuffer = MiniBuffer::new(&core);
|
||||
*core.minibuffer.lock().unwrap() = Some(minibuffer);
|
||||
|
@ -78,6 +82,17 @@ impl WidgetCore {
|
|||
}
|
||||
}
|
||||
|
||||
impl Dirtyable for WidgetCore {
|
||||
fn get_bit(&self) -> &DirtyBit {
|
||||
&self.dirty
|
||||
}
|
||||
|
||||
fn get_bit_mut(&mut self) -> &mut DirtyBit {
|
||||
&mut self.dirty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait Widget {
|
||||
fn get_core(&self) -> HResult<&WidgetCore>; // {
|
||||
// Err(HError::NoWidgetCoreError(Backtrace::new()))
|
||||
|
@ -89,8 +104,12 @@ pub trait Widget {
|
|||
Ok(&self.get_core()?.coordinates)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
|
||||
self.get_core_mut()?.coordinates = coordinates.clone();
|
||||
self.refresh()?;
|
||||
let widget_coords = &mut self.get_core_mut()?.coordinates;
|
||||
if widget_coords != coordinates {
|
||||
*widget_coords = coordinates.clone();
|
||||
self.get_core_mut()?.set_dirty();
|
||||
self.refresh()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
|
@ -235,8 +254,10 @@ pub trait Widget {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
self.refresh().log();
|
||||
self.draw().log();
|
||||
self.after_draw().log();
|
||||
self.get_core_mut()?.screen.flush().ok();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue