fix: missing a repeek on unyanking files in the hovered folder (#1988)

This commit is contained in:
三咲雅 · Misaki Masa 2024-12-05 08:45:18 +08:00 committed by GitHub
parent 2771aef677
commit c7d9265d25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 71 additions and 64 deletions

View file

@ -45,9 +45,9 @@ body:
Add any other context about the problem here. You can attach screenshots by clicking Add any other context about the problem here. You can attach screenshots by clicking
this area to highlight it and then drag the files in. this area to highlight it and then drag the files in.
- type: checkboxes - type: checkboxes
id: validations id: checklist
attributes: attributes:
label: Validations label: Checklist
description: Before submitting the post, please make sure you have completed the following description: Before submitting the post, please make sure you have completed the following
options: options:
- label: I have searched the existing discussions/issues - label: I have searched the existing discussions/issues

View file

@ -58,9 +58,9 @@ body:
Add any other context about the problem here. You can attach screenshots by clicking Add any other context about the problem here. You can attach screenshots by clicking
this area to highlight it and then drag the files in. this area to highlight it and then drag the files in.
- type: checkboxes - type: checkboxes
id: validations id: checklist
attributes: attributes:
label: Validations label: Checklist
description: Before submitting the issue, please make sure you have completed the following description: Before submitting the issue, please make sure you have completed the following
options: options:
- label: I tried the [latest nightly build](https://yazi-rs.github.io/docs/installation#official-binaries), and the issue is still reproducible - label: I tried the [latest nightly build](https://yazi-rs.github.io/docs/installation#official-binaries), and the issue is still reproducible

View file

@ -38,9 +38,9 @@ body:
label: Additional context label: Additional context
description: Add any other context or screenshots about the feature request here. description: Add any other context or screenshots about the feature request here.
- type: checkboxes - type: checkboxes
id: validations id: checklist
attributes: attributes:
label: Validations label: Checklist
description: Before submitting the issue, please make sure you have completed the following description: Before submitting the issue, please make sure you have completed the following
options: options:
- label: I have searched the existing issues/discussions - label: I have searched the existing issues/discussions

View file

@ -43,9 +43,9 @@ impl Manager {
let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]); let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]);
for u in selected { for u in selected {
if self.mimetype.contains(u) { if self.mimetype.contains(u) {
done.push((u.clone(), String::new())); done.push((u.clone(), Cow::Borrowed("")));
} else if self.guess_folder(u) { } else if self.guess_folder(u) {
done.push((u.clone(), MIME_DIR.to_owned())); done.push((u.clone(), Cow::Borrowed(MIME_DIR)));
} else { } else {
todo.push(u.clone()); todo.push(u.clone());
} }
@ -64,7 +64,7 @@ impl Manager {
} }
} }
done.extend(files.iter().map(|f| (f.url_owned(), String::new()))); done.extend(files.iter().map(|f| (f.url_owned(), Cow::Borrowed(""))));
for (fetcher, files) in PLUGIN.mime_fetchers(files) { for (fetcher, files) in PLUGIN.mime_fetchers(files) {
if let Err(e) = isolate::fetch(CmdCow::from(&fetcher.run), files).await { if let Err(e) = isolate::fetch(CmdCow::from(&fetcher.run), files).await {
error!("Fetch mime failed on opening: {e}"); error!("Fetch mime failed on opening: {e}");
@ -81,7 +81,7 @@ impl Manager {
.targets .targets
.into_iter() .into_iter()
.filter_map(|(u, m)| { .filter_map(|(u, m)| {
Some(m).filter(|m| !m.is_empty()).or_else(|| self.mimetype.get_owned(&u)).map(|m| (u, m)) Some(m).filter(|m| !m.is_empty()).or_else(|| self.mimetype.by_url_owned(&u)).map(|m| (u, m))
}) })
.collect(); .collect();

View file

@ -35,7 +35,7 @@ impl Manager {
return self.active_mut().preview.reset_image(); return self.active_mut().preview.reset_image();
} }
let mime = self.mimetype.get_owned(&hovered.url).unwrap_or_default(); let mime = self.mimetype.by_file_owned(&hovered).unwrap_or_default();
let folder = self.active().hovered_folder().map(|f| (f.offset, f.cha)); let folder = self.active().hovered_folder().map(|f| (f.offset, f.cha));
if !self.active().preview.same_url(&hovered.url) { if !self.active().preview.same_url(&hovered.url) {
@ -61,7 +61,7 @@ impl Manager {
if hovered.is_dir() { if hovered.is_dir() {
self.active_mut().preview.go_folder(hovered, folder.map(|(_, cha)| cha), opt.force); self.active_mut().preview.go_folder(hovered, folder.map(|(_, cha)| cha), opt.force);
} else { } else {
self.active_mut().preview.go(hovered, mime.into(), opt.force); self.active_mut().preview.go(hovered, mime, opt.force);
} }
} }
} }

View file

@ -1,6 +1,6 @@
use yazi_config::PLUGIN; use yazi_config::PLUGIN;
use yazi_plugin::isolate; use yazi_plugin::isolate;
use yazi_shared::{MIME_DIR, event::{CmdCow, Data}}; use yazi_shared::event::{CmdCow, Data};
use crate::manager::Manager; use crate::manager::Manager;
@ -20,11 +20,7 @@ impl Manager {
return self.active_mut().preview.reset(); return self.active_mut().preview.reset();
}; };
let mime = if hovered.is_dir() { let Some(mime) = self.mimetype.by_file(hovered) else {
MIME_DIR
} else if let Some(s) = self.mimetype.get(&hovered.url) {
s
} else {
return self.active_mut().preview.reset(); return self.active_mut().preview.reset();
}; };

View file

@ -1,6 +1,4 @@
use std::borrow::Cow; use yazi_shared::event::{CmdCow, Data};
use yazi_shared::{MIME_DIR, event::{CmdCow, Data}};
use crate::manager::Manager; use crate::manager::Manager;
@ -19,12 +17,7 @@ impl Manager {
return; return;
}; };
let mime = if hovered.is_dir() { let mime = self.mimetype.by_file_owned(&hovered).unwrap_or_default();
Cow::Borrowed(MIME_DIR)
} else {
Cow::Owned(self.mimetype.get_owned(&hovered.url).unwrap_or_default())
};
// if !self.active().spot.same_file(&hovered, &mime) { // if !self.active().spot.same_file(&hovered, &mime) {
// self.active_mut().spot.reset(); // self.active_mut().spot.reset();
// } // }

View file

@ -15,7 +15,12 @@ impl From<()> for Opt {
impl Manager { impl Manager {
#[yazi_codegen::command] #[yazi_codegen::command]
pub fn unyank(&mut self, _: Opt) { pub fn unyank(&mut self, _: Opt) {
let repeek = self.hovered().is_some_and(|f| f.is_dir() && self.yanked.contains_in(&f.url));
self.yanked.clear(); self.yanked.clear();
render!(self.yanked.catchup_revision(false)); render!(self.yanked.catchup_revision(false));
if repeek {
self.peek(true);
}
} }
} }

View file

@ -29,7 +29,7 @@ impl Manager {
.updates .updates
.into_iter() .into_iter()
.map(|(url, mime)| (Url::from(url.into_owned()), mime)) .map(|(url, mime)| (Url::from(url.into_owned()), mime))
.filter(|(url, mime)| self.mimetype.get(url) != Some(mime)) .filter(|(url, mime)| self.mimetype.by_url(url) != Some(mime))
.fold(HashMap::new(), |mut map, (u, m)| { .fold(HashMap::new(), |mut map, (u, m)| {
for u in linked.from_file(&u) { for u in linked.from_file(&u) {
map.insert(u, m.clone()); map.insert(u, m.clone());

View file

@ -1,24 +1,37 @@
use std::{collections::HashMap, path::PathBuf}; use std::{borrow::Cow, collections::HashMap, path::PathBuf};
use yazi_shared::url::{Url, UrlScheme}; use yazi_fs::File;
use yazi_shared::{MIME_DIR, url::{Url, UrlScheme}};
#[derive(Default)] #[derive(Default)]
pub struct Mimetype(HashMap<PathBuf, String>); pub struct Mimetype(HashMap<PathBuf, String>);
impl Mimetype { impl Mimetype {
#[inline] #[inline]
pub fn get(&self, url: &Url) -> Option<&str> { pub fn by_url(&self, url: &Url) -> Option<&str> {
let s = match url.scheme() { match url.scheme() {
UrlScheme::Regular => self.0.get(url.as_path()), UrlScheme::Regular => self.0.get(url.as_path()),
UrlScheme::Search => None, UrlScheme::Search => None,
UrlScheme::SearchItem => self.0.get(url.as_path()), UrlScheme::SearchItem => self.0.get(url.as_path()),
UrlScheme::Archive => None, UrlScheme::Archive => None,
}; }
s.map(|s| s.as_str()) .map(|s| s.as_str())
} }
#[inline] #[inline]
pub fn get_owned(&self, url: &Url) -> Option<String> { self.get(url).map(|s| s.to_owned()) } pub fn by_url_owned(&self, url: &Url) -> Option<Cow<'static, str>> {
self.by_url(url).map(|s| Cow::Owned(s.to_owned()))
}
#[inline]
pub fn by_file(&self, file: &File) -> Option<&str> {
if file.is_dir() { Some(MIME_DIR) } else { self.by_url(&file.url) }
}
#[inline]
pub fn by_file_owned(&self, file: &File) -> Option<Cow<'static, str>> {
if file.is_dir() { Some(Cow::Borrowed(MIME_DIR)) } else { self.by_url_owned(&file.url) }
}
#[inline] #[inline]
pub fn contains(&self, url: &Url) -> bool { pub fn contains(&self, url: &Url) -> bool {

View file

@ -61,9 +61,7 @@ impl Watcher {
let (mut parents, watched) = (HashSet::new(), WATCHED.read()); let (mut parents, watched) = (HashSet::new(), WATCHED.read());
for u in urls { for u in urls {
let Some(p) = u.parent_url() else { continue }; let Some(p) = u.parent_url() else { continue };
if !watched.contains(&p) if !watched.contains(&p) && !LINKED.read().from_dir(&p).any(|u| watched.contains(u)) {
&& LINKED.read().from_dir(&p).find(|&u| watched.contains(u)).is_none()
{
continue; continue;
} }
out_tx.send(u).ok(); out_tx.send(u).ok();

View file

@ -20,9 +20,7 @@ impl Deref for Yanked {
} }
impl Yanked { impl Yanked {
pub fn new(cut: bool, urls: HashSet<Url>) -> Self { pub fn new(cut: bool, urls: HashSet<Url>) -> Self { Self { cut, urls, ..Default::default() } }
Self { cut, urls, version: 0, ..Default::default() }
}
pub fn remove(&mut self, url: &Url) { pub fn remove(&mut self, url: &Url) {
if self.urls.remove(url) { if self.urls.remove(url) {
@ -39,6 +37,13 @@ impl Yanked {
self.revision += 1; self.revision += 1;
} }
pub fn contains_in(&self, dir: &Url) -> bool {
self.urls.iter().any(|u| {
let mut it = u.components();
it.next_back().is_some() && it == dir.components() && u.parent_url().as_ref() == Some(dir)
})
}
pub fn apply_op(&mut self, op: &FilesOp) { pub fn apply_op(&mut self, op: &FilesOp) {
let (removal, addition) = op.diff_recoverable(|u| self.contains(u)); let (removal, addition) = op.diff_recoverable(|u| self.contains(u));
if !removal.is_empty() { if !removal.is_empty() {

View file

@ -1,6 +1,5 @@
use yazi_config::{PLUGIN, plugin::MAX_PREWORKERS}; use yazi_config::{PLUGIN, plugin::MAX_PREWORKERS};
use yazi_fs::{File, Files, SortBy}; use yazi_fs::{File, Files, SortBy};
use yazi_shared::MIME_DIR;
use super::Tasks; use super::Tasks;
use crate::manager::Mimetype; use crate::manager::Mimetype;
@ -10,7 +9,7 @@ impl Tasks {
let mut loaded = self.scheduler.prework.loaded.lock(); let mut loaded = self.scheduler.prework.loaded.lock();
let mut tasks: [Vec<_>; MAX_PREWORKERS as usize] = Default::default(); let mut tasks: [Vec<_>; MAX_PREWORKERS as usize] = Default::default();
for f in paged { for f in paged {
let mime = if f.is_dir() { MIME_DIR } else { mimetype.get(&f.url).unwrap_or_default() }; let mime = mimetype.by_file(f).unwrap_or_default();
let factors = |s: &str| match s { let factors = |s: &str| match s {
"mime" => !mime.is_empty(), "mime" => !mime.is_empty(),
"dummy" => f.cha.is_dummy(), "dummy" => f.cha.is_dummy(),
@ -38,7 +37,7 @@ impl Tasks {
pub fn preload_paged(&self, paged: &[File], mimetype: &Mimetype) { pub fn preload_paged(&self, paged: &[File], mimetype: &Mimetype) {
let mut loaded = self.scheduler.prework.loaded.lock(); let mut loaded = self.scheduler.prework.loaded.lock();
for f in paged { for f in paged {
let mime = if f.is_dir() { MIME_DIR } else { mimetype.get(&f.url).unwrap_or_default() }; let mime = mimetype.by_file(f).unwrap_or_default();
for p in PLUGIN.preloaders(&f.url, mime) { for p in PLUGIN.preloaders(&f.url, mime) {
match loaded.get_mut(&f.url) { match loaded.get_mut(&f.url) {
Some(n) if *n & (1 << p.idx) != 0 => continue, Some(n) if *n & (1 << p.idx) != 0 => continue,

View file

@ -6,7 +6,7 @@ use yazi_shared::url::Url;
use super::Tasks; use super::Tasks;
impl Tasks { impl Tasks {
pub fn process_from_files(&self, hovered: Url, targets: Vec<(Url, String)>) { pub fn process_from_files(&self, hovered: Url, targets: Vec<(Url, Cow<str>)>) {
let mut openers = HashMap::new(); let mut openers = HashMap::new();
for (url, mime) in targets { for (url, mime) in targets {
if let Some(opener) = OPEN.openers(&url, mime).and_then(|o| o.first().copied()) { if let Some(opener) = OPEN.openers(&url, mime).and_then(|o| o.first().copied()) {

View file

@ -3,7 +3,6 @@ use std::ops::Deref;
use mlua::{AnyUserData, IntoLua, UserData, UserDataFields, UserDataMethods}; use mlua::{AnyUserData, IntoLua, UserData, UserDataFields, UserDataMethods};
use yazi_config::THEME; use yazi_config::THEME;
use yazi_plugin::{bindings::Range, elements::Style}; use yazi_plugin::{bindings::Range, elements::Style};
use yazi_shared::MIME_DIR;
use super::Lives; use super::Lives;
use crate::Ctx; use crate::Ctx;
@ -55,9 +54,9 @@ impl UserData for File {
Ok(if me.is_dir() { me.folder().files.sizes.get(me.urn()).copied() } else { Some(me.len) }) Ok(if me.is_dir() { me.folder().files.sizes.get(me.urn()).copied() } else { Some(me.len) })
}); });
methods.add_method("mime", |lua, me, ()| { methods.add_method("mime", |lua, me, ()| {
lua lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|cx: &Ctx| {
.named_registry_value::<AnyUserData>("cx")? cx.manager.mimetype.by_url(&me.url).map(|s| lua.create_string(s)).transpose()
.borrow_scoped(|cx: &Ctx| cx.manager.mimetype.get_owned(&me.url)) })?
}); });
methods.add_method("prefix", |lua, me, ()| { methods.add_method("prefix", |lua, me, ()| {
if !me.folder().url.is_search() { if !me.folder().url.is_search() {
@ -70,9 +69,7 @@ impl UserData for File {
}); });
methods.add_method("style", |lua, me, ()| { methods.add_method("style", |lua, me, ()| {
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|cx: &Ctx| { lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|cx: &Ctx| {
let mime = let mime = cx.manager.mimetype.by_file(me).unwrap_or_default();
if me.is_dir() { MIME_DIR } else { cx.manager.mimetype.get(&me.url).unwrap_or_default() };
THEME.filetypes.iter().find(|&x| x.matches(me, mime)).map(|x| Style::from(x.style)) THEME.filetypes.iter().find(|&x| x.matches(me, mime)).map(|x| Style::from(x.style))
}) })
}); });

View file

@ -3,7 +3,7 @@ use ratatui::widgets::Borders;
use super::Area; use super::Area;
#[derive(Clone, Default)] #[derive(Clone, Debug, Default)]
pub struct Bar { pub struct Bar {
area: Area, area: Area,

View file

@ -12,7 +12,7 @@ const THICK: u8 = 3;
const QUADRANT_INSIDE: u8 = 4; const QUADRANT_INSIDE: u8 = 4;
const QUADRANT_OUTSIDE: u8 = 5; const QUADRANT_OUTSIDE: u8 = 5;
#[derive(Clone, Default)] #[derive(Clone, Debug, Default)]
pub struct Border { pub struct Border {
pub(crate) area: Area, pub(crate) area: Area,

View file

@ -4,7 +4,7 @@ use super::Text;
const EXPECTED: &str = "expected a table of strings, Texts, Lines or Spans"; const EXPECTED: &str = "expected a table of strings, Texts, Lines or Spans";
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct Cell { pub struct Cell {
pub(super) text: ratatui::text::Text<'static>, pub(super) text: ratatui::text::Text<'static>,
} }

View file

@ -7,7 +7,7 @@ use super::Area;
pub static COLLISION: AtomicBool = AtomicBool::new(false); pub static COLLISION: AtomicBool = AtomicBool::new(false);
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct Clear { pub struct Clear {
pub area: Area, pub area: Area,
} }

View file

@ -4,7 +4,7 @@ use ratatui::widgets::Widget;
use super::{Area, Span}; use super::{Area, Span};
use crate::elements::Style; use crate::elements::Style;
#[derive(Clone, Default)] #[derive(Clone, Debug, Default)]
pub struct Gauge { pub struct Gauge {
area: Area, area: Area,

View file

@ -6,7 +6,7 @@ use super::{Area, Text};
const EXPECTED: &str = "expected a table of strings, Texts, Lines or Spans"; const EXPECTED: &str = "expected a table of strings, Texts, Lines or Spans";
// --- List // --- List
#[derive(Clone, Default)] #[derive(Clone, Debug, Default)]
pub struct List { pub struct List {
area: Area, area: Area,

View file

@ -4,7 +4,7 @@ use mlua::{FromLua, Lua, Table, UserData};
use super::Pad; use super::Pad;
#[derive(Clone, Copy, Default, FromLua)] #[derive(Clone, Copy, Debug, Default, FromLua)]
pub struct Rect(pub(super) ratatui::layout::Rect); pub struct Rect(pub(super) ratatui::layout::Rect);
impl Deref for Rect { impl Deref for Rect {

View file

@ -2,7 +2,7 @@ use mlua::{AnyUserData, ExternalError};
use super::{Bar, Border, Clear, Gauge, List, Table, Text}; use super::{Bar, Border, Clear, Gauge, List, Table, Text};
#[derive(Clone)] #[derive(Clone, Debug)]
pub enum Renderable { pub enum Renderable {
Text(Text), Text(Text),
List(List), List(List),

View file

@ -2,7 +2,7 @@ use mlua::{AnyUserData, FromLua, Lua, Table, UserData};
use super::Cell; use super::Cell;
#[derive(Clone, Default, FromLua)] #[derive(Clone, Debug, Default, FromLua)]
pub struct Row { pub struct Row {
pub(super) cells: Vec<Cell>, pub(super) cells: Vec<Cell>,
height: u16, height: u16,

View file

@ -5,7 +5,7 @@ use super::{Area, Row};
use crate::elements::{Constraint, Style}; use crate::elements::{Constraint, Style};
// --- Table // --- Table
#[derive(Clone, Default)] #[derive(Clone, Debug, Default)]
pub struct Table { pub struct Table {
pub(crate) area: Area, pub(crate) area: Area,

View file

@ -16,7 +16,7 @@ pub const WRAP_TRIM: u8 = 2;
const EXPECTED: &str = "expected a string, Line, Span, or a table of them"; const EXPECTED: &str = "expected a string, Line, Span, or a table of them";
#[derive(Clone, Default, FromLua)] #[derive(Clone, Debug, Default, FromLua)]
pub struct Text { pub struct Text {
pub area: Area, pub area: Area,

View file

@ -6,6 +6,7 @@ use yazi_shared::{Layer, errors::PeekError, event::Cmd};
use super::Utils; use super::Utils;
use crate::{elements::{Area, Rect, Renderable, Text, WRAP, WRAP_NO}, external::Highlighter, file::FileRef}; use crate::{elements::{Area, Rect, Renderable, Text, WRAP, WRAP_NO}, external::Highlighter, file::FileRef};
#[derive(Debug)]
pub struct PreviewLock { pub struct PreviewLock {
pub url: yazi_shared::url::Url, pub url: yazi_shared::url::Url,
pub cha: yazi_fs::Cha, pub cha: yazi_fs::Cha,

View file

@ -7,7 +7,7 @@ use yazi_shared::{event::CmdCow, url::Url};
#[derive(Default)] #[derive(Default)]
pub struct OpenDoOpt { pub struct OpenDoOpt {
pub hovered: Url, pub hovered: Url,
pub targets: Vec<(Url, String)>, pub targets: Vec<(Url, Cow<'static, str>)>,
pub interactive: bool, pub interactive: bool,
} }