mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
fix: task manager not re-rendering after progress update (#633)
This commit is contained in:
parent
59e889a3b5
commit
d754044aae
16 changed files with 68 additions and 51 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ impl Filetype {
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue