fix: task manager not re-rendering after progress update (#633)

This commit is contained in:
三咲雅 · Misaki Masa 2024-02-06 08:35:50 +08:00 committed by GitHub
parent 59e889a3b5
commit d754044aae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 68 additions and 51 deletions

View file

@ -357,7 +357,7 @@ impl Kitty {
async fn encode(img: DynamicImage) -> Result<Vec<u8>> { async fn encode(img: DynamicImage) -> Result<Vec<u8>> {
fn output(raw: &[u8], format: u8, size: (u32, u32)) -> Result<Vec<u8>> { fn output(raw: &[u8], format: u8, size: (u32, u32)) -> Result<Vec<u8>> {
let b64 = general_purpose::STANDARD.encode(raw).chars().collect::<Vec<_>>(); let b64: Vec<_> = general_purpose::STANDARD.encode(raw).chars().collect();
let mut it = b64.chunks(4096).peekable(); let mut it = b64.chunks(4096).peekable();
let mut buf = Vec::with_capacity(b64.len() + it.len() * 50); let mut buf = Vec::with_capacity(b64.len() + it.len() * 50);

View file

@ -35,7 +35,7 @@ impl KittyOld {
async fn encode(img: DynamicImage) -> Result<Vec<u8>> { async fn encode(img: DynamicImage) -> Result<Vec<u8>> {
fn output(raw: &[u8], format: u8, size: (u32, u32)) -> Result<Vec<u8>> { fn output(raw: &[u8], format: u8, size: (u32, u32)) -> Result<Vec<u8>> {
let b64 = general_purpose::STANDARD.encode(raw).chars().collect::<Vec<_>>(); let b64: Vec<_> = general_purpose::STANDARD.encode(raw).chars().collect();
let mut it = b64.chunks(4096).peekable(); let mut it = b64.chunks(4096).peekable();
let mut buf = Vec::with_capacity(b64.len() + it.len() * 50); let mut buf = Vec::with_capacity(b64.len() + it.len() * 50);

View file

@ -4,10 +4,10 @@
[manager] [manager]
ratio = [ 1, 4, 3 ] ratio = [ 1, 4, 3 ]
sort_by = "modified" sort_by = "alphabetical"
sort_sensitive = true sort_sensitive = false
sort_reverse = true sort_reverse = false
sort_dir_first = true sort_dir_first = false
linemode = "none" linemode = "none"
show_hidden = false show_hidden = false
show_symlink = true show_symlink = true

View file

@ -97,7 +97,7 @@ impl Filetype {
} }
.into(), .into(),
}) })
.collect::<Vec<_>>(), .collect(),
) )
} }
} }

View file

@ -35,7 +35,7 @@ impl Icon {
text: r.text, text: r.text,
style: StyleShadow { fg: r.fg, ..Default::default() }.into(), style: StyleShadow { fg: r.fg, ..Default::default() }.into(),
}) })
.collect::<Vec<_>>(), .collect(),
) )
} }
} }

View file

@ -72,7 +72,7 @@ impl InputSnap {
#[inline] #[inline]
pub(super) fn find_window(s: &str, offset: usize, limit: usize) -> Range<usize> { pub(super) fn find_window(s: &str, offset: usize, limit: usize) -> Range<usize> {
let mut width = 0; let mut width = 0;
let v = s let v: Vec<_> = s
.chars() .chars()
.enumerate() .enumerate()
.skip(offset) .skip(offset)
@ -80,7 +80,7 @@ impl InputSnap {
width += c.width().unwrap_or(0); width += c.width().unwrap_or(0);
if width < limit { Some(i) } else { None } if width < limit { Some(i) } else { None }
}) })
.collect::<Vec<_>>(); .collect();
if v.is_empty() { if v.is_empty() {
return 0..0; return 0..0;

View file

@ -12,30 +12,21 @@ impl From<Cmd> for Opt {
} }
} }
impl From<isize> for Opt {
fn from(step: isize) -> Self { Self { step } }
}
impl Tasks { impl Tasks {
#[allow(clippy::should_implement_trait)]
fn next(&mut self) {
let limit = Self::limit().min(self.len());
let old = self.cursor;
self.cursor = limit.saturating_sub(1).min(self.cursor + 1);
render!(old != self.cursor);
}
fn prev(&mut self) {
let old = self.cursor;
self.cursor = self.cursor.saturating_sub(1);
render!(old != self.cursor);
}
pub fn arrow(&mut self, opt: impl Into<Opt>) { pub fn arrow(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt; let old = self.cursor;
if opt.step > 0 { if opt.into().step > 0 {
self.next(); self.cursor += 1;
} else { } else {
self.prev(); self.cursor = self.cursor.saturating_sub(1);
} }
let max = Self::limit().min(self.summaries.len());
self.cursor = self.cursor.min(max.saturating_sub(1));
render!(self.cursor != old);
} }
} }

View file

@ -14,6 +14,12 @@ impl From<()> for Opt {
impl Tasks { impl Tasks {
pub fn toggle(&mut self, _: impl Into<Opt>) { pub fn toggle(&mut self, _: impl Into<Opt>) {
self.visible = !self.visible; self.visible = !self.visible;
if self.visible {
self.summaries = self.paginate();
self.arrow(0);
}
render!(); render!();
} }
} }

View file

@ -5,5 +5,6 @@ mod tasks;
pub use progress::*; pub use progress::*;
pub use tasks::*; pub use tasks::*;
pub const TASKS_BORDER: u16 = 2;
pub const TASKS_PADDING: u16 = 2; pub const TASKS_PADDING: u16 = 2;
pub const TASKS_PERCENT: u16 = 80; pub const TASKS_PERCENT: u16 = 80;

View file

@ -7,15 +7,16 @@ use yazi_plugin::ValueSendable;
use yazi_scheduler::{Scheduler, TaskSummary}; use yazi_scheduler::{Scheduler, TaskSummary};
use yazi_shared::{emit, event::Cmd, fs::{File, Url}, term::Term, Layer, MIME_DIR}; use yazi_shared::{emit, event::Cmd, fs::{File, Url}, term::Term, Layer, MIME_DIR};
use super::{TasksProgress, TASKS_PADDING, TASKS_PERCENT}; use super::{TasksProgress, TASKS_BORDER, TASKS_PADDING, TASKS_PERCENT};
use crate::{folder::Files, input::Input}; use crate::{folder::Files, input::Input};
pub struct Tasks { pub struct Tasks {
pub(super) scheduler: Arc<Scheduler>, pub(super) scheduler: Arc<Scheduler>,
pub visible: bool, pub visible: bool,
pub cursor: usize, pub cursor: usize,
pub progress: TasksProgress, pub progress: TasksProgress,
pub summaries: Vec<TaskSummary>,
} }
impl Tasks { impl Tasks {
@ -25,6 +26,7 @@ impl Tasks {
visible: false, visible: false,
cursor: 0, cursor: 0,
progress: Default::default(), progress: Default::default(),
summaries: Default::default(),
}; };
let running = tasks.scheduler.running.clone(); let running = tasks.scheduler.running.clone();
@ -46,7 +48,7 @@ impl Tasks {
#[inline] #[inline]
pub fn limit() -> usize { pub fn limit() -> usize {
(Term::size().rows * TASKS_PERCENT / 100).saturating_sub(TASKS_PADDING) as usize (Term::size().rows * TASKS_PERCENT / 100).saturating_sub(TASKS_BORDER + TASKS_PADDING) as usize
} }
pub fn paginate(&self) -> Vec<TaskSummary> { pub fn paginate(&self) -> Vec<TaskSummary> {

View file

@ -1,6 +1,6 @@
use ratatui::backend::Backend; use ratatui::backend::Backend;
use yazi_core::tasks::TasksProgress; use yazi_core::tasks::TasksProgress;
use yazi_shared::event::Cmd; use yazi_shared::{event::Cmd, render};
use crate::{app::App, components::Progress, lives::Lives}; use crate::{app::App, components::Progress, lives::Lives};
@ -22,7 +22,23 @@ impl App {
return; return;
}; };
self.cx.tasks.progress = opt.progress; // Update the progress of all tasks.
let tasks = &mut self.cx.tasks;
tasks.progress = opt.progress;
// If the task manager is visible, update the summaries with a complete render.
if tasks.visible {
let new = tasks.paginate();
if new.len() != tasks.summaries.len()
|| new.iter().zip(&tasks.summaries).any(|(a, b)| a.name != b.name)
{
tasks.summaries = new;
tasks.arrow(0);
return render!();
}
}
// Otherwise, only partially update the progress.
let Some(term) = &mut self.term else { let Some(term) = &mut self.term else {
return; return;
}; };

View file

@ -15,7 +15,7 @@ impl<'a> Completion<'a> {
impl<'a> Widget for Completion<'a> { impl<'a> Widget for Completion<'a> {
fn render(self, rect: Rect, buf: &mut Buffer) { fn render(self, rect: Rect, buf: &mut Buffer) {
let items = self let items: Vec<_> = self
.cx .cx
.completion .completion
.window() .window()
@ -37,7 +37,7 @@ impl<'a> Widget for Completion<'a> {
item item
}) })
.collect::<Vec<_>>(); .collect();
let input_area = self.cx.area(&self.cx.input.position); let input_area = self.cx.area(&self.cx.input.position);
let mut area = Position::sticky(input_area, Offset { let mut area = Position::sticky(input_area, Offset {

View file

@ -19,18 +19,18 @@ impl Widget for Bindings<'_> {
} }
// On // On
let col1 = let col1: Vec<_> =
bindings.iter().map(|c| ListItem::new(c.on()).style(THEME.help.on)).collect::<Vec<_>>(); bindings.iter().map(|c| ListItem::new(c.on()).style(THEME.help.on)).collect();
// Exec // Exec
let col2 = let col2: Vec<_> =
bindings.iter().map(|c| ListItem::new(c.exec()).style(THEME.help.exec)).collect::<Vec<_>>(); bindings.iter().map(|c| ListItem::new(c.exec()).style(THEME.help.exec)).collect();
// Desc // Desc
let col3 = bindings let col3: Vec<_> = bindings
.iter() .iter()
.map(|c| ListItem::new(c.desc.as_deref().unwrap_or("-")).style(THEME.help.desc)) .map(|c| ListItem::new(c.desc.as_deref().unwrap_or("-")).style(THEME.help.desc))
.collect::<Vec<_>>(); .collect();
let chunks = layout::Layout::horizontal([ let chunks = layout::Layout::horizontal([
Constraint::Ratio(2, 10), Constraint::Ratio(2, 10),

View file

@ -16,7 +16,7 @@ impl<'a> Widget for Select<'a> {
let select = &self.cx.select; let select = &self.cx.select;
let area = self.cx.area(&select.position); let area = self.cx.area(&select.position);
let items = select let items: Vec<_> = select
.window() .window()
.iter() .iter()
.enumerate() .enumerate()
@ -27,7 +27,7 @@ impl<'a> Widget for Select<'a> {
ListItem::new(format!("{v}")).style(THEME.select.active) ListItem::new(format!("{v}")).style(THEME.select.active)
}) })
.collect::<Vec<_>>(); .collect();
widgets::Clear.render(area, buf); widgets::Clear.render(area, buf);
List::new(items) List::new(items)

View file

@ -43,8 +43,9 @@ impl<'a> Widget for Layout<'a> {
let tasks = &self.cx.tasks; let tasks = &self.cx.tasks;
let items = tasks let items = tasks
.paginate() .summaries
.iter() .iter()
.take(area.height.saturating_sub(2) as usize)
.enumerate() .enumerate()
.map(|(i, v)| { .map(|(i, v)| {
let mut item = ListItem::new(v.name.clone()); let mut item = ListItem::new(v.name.clone());

View file

@ -34,8 +34,8 @@ impl Widget for Clear {
ADAPTOR.image_erase(r).ok(); ADAPTOR.image_erase(r).ok();
COLLISION.store(true, Ordering::Relaxed); COLLISION.store(true, Ordering::Relaxed);
for x in r.left()..r.right() { for x in area.left()..area.right() {
for y in r.top()..r.bottom() { for y in area.top()..area.bottom() {
buf.get_mut(x, y).set_skip(true); buf.get_mut(x, y).set_skip(true);
} }
} }