ronantakizawa/codereview-bench huggingface dataset:
Repository: sxyazi/yazi
File: yazi-fs/src/services/services.rs (Rust)

Code before:
pub async fn canonicalize(url: impl AsRef<Url>) -> io::Result<Url> {
	Local::canonicalize(url.as_ref()).await.map(Into::into)
}

#[inline]
pub async fn create(url: impl AsRef<Url>) -> io::Result<tokio::fs::File> {
	Local::create(url.as_ref()).await
}

#[inline]
pub async fn create_dir(url: impl AsRef<Url>) -> io::Result<()> {
	Local::create_dir(url.as_ref()).await
}

#[inline]
pub async fn create_dir_all(url: impl AsRef<Url>) -> io::Result<()> {
	Local::create_dir_all(url.as_ref()).await
}

#[inline]
pub async fn metadata(url: impl AsRef<Url>) -> io::Result<std::fs::Metadata> {
	Local::metadata(url.as_ref()).await
}

#[inline]
pub async fn open(url: impl AsRef<Url>) -> io::Result<tokio::fs::File> {
	tokio::fs::File::open(url.as_ref()).await
}

#[inline]
pub async fn read_dir(url: impl AsRef<Url>) -> io::Result<tokio::fs::ReadDir> {
	Local::read_dir(url.as_ref()).await
}

#[inline]
pub async fn read_link(url: impl AsRef<Url>) -> io::Result<Url> {
	Local::read_link(url.as_ref()).await.map(Into::into)
}

#[inline]
pub async fn remove_dir(url: impl AsRef<Url>) -> io::Result<()> {
	Local::remove_dir(url.as_ref()).await
}

#[inline]
pub async fn remove_dir_all(url: impl AsRef<Url>) -> io::Result<()> {
	Local::remove_dir_all(url.as_ref()).await
}

#[inline]
pub async fn remove_file(url: impl AsRef<Url>) -> io::Result<()> {

Review comment (suggestion):
The `open` function bypasses the `Local` service layer and calls `tokio::fs::File::open` directly. This is inconsistent with other functions that delegate to `Local` methods. Consider adding a corresponding method to `Local` and delegating to it for consistency.

Code after:
pub async fn canonicalize(url: impl AsRef<Url>) -> io::Result<Url> {
	Local::canonicalize(url.as_ref()).await.map(Into::into)
}

#[inline]
pub async fn create(url: impl AsRef<Url>) -> io::Result<tokio::fs::File> {
	Local::create(url.as_ref()).await
}

#[inline]
pub async fn create_dir(url: impl AsRef<Url>) -> io::Result<()> {
	Local::create_dir(url.as_ref()).await
}

#[inline]
pub async fn create_dir_all(url: impl AsRef<Url>) -> io::Result<()> {
	Local::create_dir_all(url.as_ref()).await
}

#[inline]
pub async fn metadata(url: impl AsRef<Url>) -> io::Result<std::fs::Metadata> {
	Local::metadata(url.as_ref()).await
}

#[inline]
pub async fn open(url: impl AsRef<Url>) -> io::Result<tokio::fs::File> {
	Local::open(url.as_ref()).await
}

#[inline]
pub async fn read_dir(url: impl AsRef<Url>) -> io::Result<tokio::fs::ReadDir> {
	Local::read_dir(url.as_ref()).await
}

#[inline]
pub async fn read_link(url: impl AsRef<Url>) -> io::Result<Url> {
	Local::read_link(url.as_ref()).await.map(Into::into)
}

#[inline]
pub async fn remove_dir(url: impl AsRef<Url>) -> io::Result<()> {
	Local::remove_dir(url.as_ref()).await
}

#[inline]
pub async fn remove_dir_all(url: impl AsRef<Url>) -> io::Result<()> {
	Local::remove_dir_all(url.as_ref()).await
}

#[inline]
pub async fn remove_file(url: impl AsRef<Url>) -> io::Result<()> {
Repository: sxyazi/yazi
File: yazi-shared/src/url/scheme.rs (Rust)

Code before:
	fn decode_param(bytes: &[u8]) -> Result<(String, usize)> {
		let len = bytes.iter().copied().take_while(|&b| b != b'/').count();

		let s = match Cow::from(percent_decode(&bytes[..len])) {
			Cow::Borrowed(b) => str::from_utf8(b)?.to_owned(),
			Cow::Owned(b) => String::from_utf8(b)?,
		};

		let slash = bytes.get(len).is_some_and(|&b| b == b'/') as usize;
		Ok((s, len + slash))
	}

	#[inline]
	fn encode_param<'a>(s: &'a str) -> PercentEncode<'a> { percent_encode(s.as_bytes(), CONTROLS) }
}

impl Display for Scheme {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Regular => write!(f, "regular://"),
			Self::Search(kw) => write!(f, "search://{}/", Self::encode_param(kw)),
			Self::SearchItem => write!(f, "search_item://"),
			Self::Archive(id) => write!(f, "archive://{}/", Self::encode_param(id)),
			Self::Sftp(id) => write!(f, "sftp://{}/", Self::encode_param(id)),
		}
	}
}


Review comment (suggestion):
Similar to the Display implementation, this uses "search-item" with a hyphen while the enum variant is `SearchItem`. This creates the same inconsistency issue in the tilded encoding format.
```suggestion
			Self::SearchItem => format!("searchitem~://{loc}"),
```

Code after:
			Self::Regular | Self::Search(_) | Self::SearchItem => false,
			Self::Archive(_) | Self::Sftp(_) => true,
		}
	}

	fn decode_param(bytes: &[u8]) -> Result<(String, usize)> {
		let len = bytes.iter().copied().take_while(|&b| b != b'/').count();

		let s = match Cow::from(percent_decode(&bytes[..len])) {
			Cow::Borrowed(b) => str::from_utf8(b)?.to_owned(),
			Cow::Owned(b) => String::from_utf8(b)?,
		};

		let slash = bytes.get(len).is_some_and(|&b| b == b'/') as usize;
		Ok((s, len + slash))
	}

	#[inline]
	fn encode_param<'a>(s: &'a str) -> PercentEncode<'a> { percent_encode(s.as_bytes(), CONTROLS) }

	pub fn encode_tilded(&self, loc: &Loc) -> String {
		let loc = percent_encode(loc.as_os_str().as_encoded_bytes(), CONTROLS);
		match self {
			Self::Regular => format!("regular~://{loc}"),
			Self::Search(kw) => format!("search~://{}/{loc}", Self::encode_param(kw)),
			Self::SearchItem => format!("search-item~://{loc}"),
			Self::Archive(id) => format!("archive~://{}/{loc}", Self::encode_param(id)),
			Self::Sftp(id) => format!("sftp~://{}/{loc}", Self::encode_param(id)),
		}
	}
}

impl Display for Scheme {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Regular => write!(f, "regular://"),
			Self::Search(kw) => write!(f, "search://{}/", Self::encode_param(kw)),
			Self::SearchItem => write!(f, "search-item://"),
			Self::Archive(id) => write!(f, "archive://{}/", Self::encode_param(id)),
			Self::Sftp(id) => write!(f, "sftp://{}/", Self::encode_param(id)),
		}
	}
}
Repository: sxyazi/yazi
File: yazi-shared/src/url/url.rs (Rust)

Code before:
use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, hash::{BuildHasher, Hash, Hasher}, ops::Deref, path::{Path, PathBuf}};

use percent_encoding::percent_decode;
use serde::{Deserialize, Serialize};

use super::UrnBuf;
use crate::{IntoOsStr, url::{Components, Display, Loc, Scheme}};

#[derive(Clone, Default, Eq, Ord, PartialOrd)]
pub struct Url {
	pub loc:    Loc,
	pub scheme: Scheme,
}

impl Deref for Url {
	type Target = Loc;

	fn deref(&self) -> &Self::Target { &self.loc }
}

impl Debug for Url {
	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
		let Self { scheme, loc } = self;
		match scheme {
			Scheme::Regular => write!(f, "{scheme}{}", loc.display()),
			Scheme::Search(_) => write!(f, "{scheme}{}", loc.display()),

Review comment (bug):
The import statement removes `Hash` and `Hasher` but keeps `BuildHasher` which is unused after removing the custom `Hash` implementation. Consider removing `BuildHasher` from the imports as well.
```suggestion
use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, ops::Deref, path::{Path, PathBuf}};
```

Code after:
use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, hash::BuildHasher, ops::Deref, path::{Path, PathBuf}};

use percent_encoding::percent_decode;
use serde::{Deserialize, Serialize};

use super::UrnBuf;
use crate::{IntoOsStr, url::{Components, Display, Loc, Scheme}};

#[derive(Clone, Default, Eq, Ord, PartialOrd, PartialEq, Hash)]
pub struct Url {
	pub loc:    Loc,
	pub scheme: Scheme,
}

impl Deref for Url {
	type Target = Loc;

	fn deref(&self) -> &Self::Target { &self.loc }
}

impl From<Loc> for Url {
	fn from(loc: Loc) -> Self { Self { loc, scheme: Scheme::Regular } }
}

impl From<PathBuf> for Url {
	fn from(path: PathBuf) -> Self { Loc::from(path).into() }
Repository: sxyazi/yazi
File: yazi-shared/src/osstr.rs (Rust)

Code before:
		let bytes = self.as_encoded_bytes();
		for (i, &byte) in bytes.iter().enumerate().rev() {
			if !pat.predicate(byte) {
				continue;
			}

			let (a, b) = bytes.split_at(i);
			// SAFETY: These substrings were separated by a UTF-8 string.
			return Some(unsafe {
				(OsStr::from_encoded_bytes_unchecked(a), OsStr::from_encoded_bytes_unchecked(&b[1..]))
			});
		}
		None
	}
}

pub trait Pattern {
	fn predicate(&self, byte: u8) -> bool;
}

impl Pattern for char {
	fn predicate(&self, byte: u8) -> bool { *self == byte as char }
}

impl Pattern for [char] {
	fn predicate(&self, byte: u8) -> bool { self.contains(&(byte as char)) }
}


Review comment (bug):
Converting a byte to char using `as` is unsafe for non-ASCII bytes. This could cause incorrect behavior with UTF-8 encoded strings. Consider using proper UTF-8 validation or limiting to ASCII.
```suggestion
	fn predicate(&self, byte: u8) -> bool {
		if byte.is_ascii() {
			*self == byte as char
		} else {
			false
		}
	}
}

impl Pattern for [char] {
	fn predicate(&self, byte: u8) -> bool {
		if byte.is_ascii() {
			self.contains(&(byte as char))
		} else {
			false
		}
	}
```

Code after:
		let bytes = self.as_encoded_bytes();
		for (i, &byte) in bytes.iter().enumerate().rev() {
			if !pat.predicate(byte) {
				continue;
			}

			let (a, b) = bytes.split_at(i);
			// SAFETY: These substrings were separated by a UTF-8 string.
			return Some(unsafe {
				(OsStr::from_encoded_bytes_unchecked(a), OsStr::from_encoded_bytes_unchecked(&b[1..]))
			});
		}
		None
	}
}

pub trait Pattern {
	fn predicate(&self, byte: u8) -> bool;
}

impl Pattern for char {
	fn predicate(&self, byte: u8) -> bool { *self == byte as char }
}

impl Pattern for &[char] {
	fn predicate(&self, byte: u8) -> bool { self.contains(&(byte as char)) }
}
Repository: sxyazi/yazi
File: yazi-shared/src/osstr.rs (Rust)

Code before:
		let bytes = self.as_encoded_bytes();
		for (i, &byte) in bytes.iter().enumerate().rev() {
			if !pat.predicate(byte) {
				continue;
			}

			let (a, b) = bytes.split_at(i);
			// SAFETY: These substrings were separated by a UTF-8 string.
			return Some(unsafe {
				(OsStr::from_encoded_bytes_unchecked(a), OsStr::from_encoded_bytes_unchecked(&b[1..]))
			});
		}
		None
	}
}

pub trait Pattern {
	fn predicate(&self, byte: u8) -> bool;
}

impl Pattern for char {
	fn predicate(&self, byte: u8) -> bool { *self == byte as char }
}

impl Pattern for [char] {
	fn predicate(&self, byte: u8) -> bool { self.contains(&(byte as char)) }
}


Review comment (bug):
Same issue as above - converting byte to char using `as` is unsafe for non-ASCII bytes. This could cause incorrect behavior with UTF-8 encoded strings.
```suggestion
	fn predicate(&self, byte: u8) -> bool {
		if let Ok(s) = std::str::from_utf8(&[byte]) {
			if let Some(c) = s.chars().next() {
				return self.contains(&c);
			}
		}
		false
	}
```

Code after:
		let bytes = self.as_encoded_bytes();
		for (i, &byte) in bytes.iter().enumerate().rev() {
			if !pat.predicate(byte) {
				continue;
			}

			let (a, b) = bytes.split_at(i);
			// SAFETY: These substrings were separated by a UTF-8 string.
			return Some(unsafe {
				(OsStr::from_encoded_bytes_unchecked(a), OsStr::from_encoded_bytes_unchecked(&b[1..]))
			});
		}
		None
	}
}

pub trait Pattern {
	fn predicate(&self, byte: u8) -> bool;
}

impl Pattern for char {
	fn predicate(&self, byte: u8) -> bool { *self == byte as char }
}

impl Pattern for &[char] {
	fn predicate(&self, byte: u8) -> bool { self.contains(&(byte as char)) }
}
Repository: sxyazi/yazi
File: yazi-adapter/src/drivers/kgp.rs (Rust)

Code before:
use core::str;
use std::{io::Write, sync::OnceLock};

use anyhow::Result;
use base64::{Engine, engine::general_purpose};
use crossterm::{cursor::MoveTo, queue};
use image::DynamicImage;
use ratatui::layout::Rect;
use yazi_shared::url::Url;

use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter, image::Image};

// Generate unique image ID per Yazi instance to prevent tmux overlap
// This ID is encoded in the foreground color of Unicode placeholders
static INSTANCE_ID: OnceLock<u32> = OnceLock::new();

fn get_image_id() -> u32 {
	*INSTANCE_ID.get_or_init(|| {
		// Use PID to get unique ID per instance
		// Limit to 24-bit RGB color space (0xFFFFFF)
		(std::process::id() % 0xFFFFFE) + 1
	})
}

static DIACRITICS: [char; 297] = [
	'\u{0305}',
	'\u{030D}',
	'\u{030E}',
	'\u{0310}',
	'\u{0312}',
	'\u{033D}',
	'\u{033E}',
	'\u{033F}',
	'\u{0346}',
	'\u{034A}',
	'\u{034B}',
	'\u{034C}',
	'\u{0350}',
	'\u{0351}',
	'\u{0352}',
	'\u{0357}',
	'\u{035B}',
	'\u{0363}',
	'\u{0364}',
	'\u{0365}',

Review comment (suggestion):
The magic number 0xFFFFFE lacks explanation. Consider adding a comment explaining this represents the maximum 24-bit RGB value minus 1 to avoid black (0x000000).
```suggestion
		// Limit to 24-bit RGB color space (0xFFFFFF)
		// Use 0xFFFFFE (max 24-bit RGB value minus 1) to avoid generating 0x000000 (black) as an ID
```

Code after:
use core::str;
use std::{io::Write, path::Path};

use anyhow::Result;
use base64::{Engine, engine::general_purpose};
use crossterm::{cursor::MoveTo, queue};
use image::DynamicImage;
use ratatui::layout::Rect;
use yazi_shared::SyncCell;

use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter, image::Image};

static DIACRITICS: [char; 297] = [
	'\u{0305}',
	'\u{030D}',
	'\u{030E}',
	'\u{0310}',
	'\u{0312}',
	'\u{033D}',
	'\u{033E}',
	'\u{033F}',
	'\u{0346}',
	'\u{034A}',
	'\u{034B}',
	'\u{034C}',
	'\u{0350}',
	'\u{0351}',
	'\u{0352}',
	'\u{0357}',
	'\u{035B}',
	'\u{0363}',
	'\u{0364}',
	'\u{0365}',
	'\u{0366}',
	'\u{0367}',
	'\u{0368}',
	'\u{0369}',
	'\u{036A}',
	'\u{036B}',
	'\u{036C}',
	'\u{036D}',
	'\u{036E}',
	'\u{036F}',
	'\u{0483}',
	'\u{0484}',
Repository: sxyazi/yazi
File: yazi-adapter/src/drivers/kgp.rs (Rust)

Code before:
use core::str;
use std::{io::Write, sync::OnceLock};

use anyhow::Result;
use base64::{Engine, engine::general_purpose};
use crossterm::{cursor::MoveTo, queue};
use image::DynamicImage;
use ratatui::layout::Rect;
use yazi_shared::url::Url;

use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter, image::Image};

// Generate unique image ID per Yazi instance to prevent tmux overlap
// This ID is encoded in the foreground color of Unicode placeholders
static INSTANCE_ID: OnceLock<u32> = OnceLock::new();

fn get_image_id() -> u32 {
	*INSTANCE_ID.get_or_init(|| {
		// Use PID to get unique ID per instance
		// Limit to 24-bit RGB color space (0xFFFFFF)
		(std::process::id() % 0xFFFFFE) + 1
	})
}

static DIACRITICS: [char; 297] = [
	'\u{0305}',
	'\u{030D}',
	'\u{030E}',
	'\u{0310}',
	'\u{0312}',
	'\u{033D}',
	'\u{033E}',
	'\u{033F}',
	'\u{0346}',
	'\u{034A}',
	'\u{034B}',
	'\u{034C}',
	'\u{0350}',
	'\u{0351}',
	'\u{0352}',
	'\u{0357}',
	'\u{035B}',
	'\u{0363}',
	'\u{0364}',
	'\u{0365}',
	'\u{0366}',

Review comment (suggestion):
Using PID modulo for unique IDs can cause collisions when PIDs wrap around or in environments with PID reuse. Consider using a combination of PID and timestamp or a random component to reduce collision probability.

Code after:
use core::str;
use std::{io::Write, path::Path};

use anyhow::Result;
use base64::{Engine, engine::general_purpose};
use crossterm::{cursor::MoveTo, queue};
use image::DynamicImage;
use ratatui::layout::Rect;
use yazi_shared::SyncCell;

use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter, image::Image};

static DIACRITICS: [char; 297] = [
	'\u{0305}',
	'\u{030D}',
	'\u{030E}',
	'\u{0310}',
	'\u{0312}',
	'\u{033D}',
	'\u{033E}',
	'\u{033F}',
	'\u{0346}',
	'\u{034A}',
	'\u{034B}',
	'\u{034C}',
	'\u{0350}',
	'\u{0351}',
	'\u{0352}',
	'\u{0357}',
	'\u{035B}',
	'\u{0363}',
	'\u{0364}',
	'\u{0365}',
	'\u{0366}',
	'\u{0367}',
	'\u{0368}',
	'\u{0369}',
	'\u{036A}',
	'\u{036B}',
	'\u{036C}',
	'\u{036D}',
	'\u{036E}',
	'\u{036F}',
	'\u{0483}',
	'\u{0484}',
	'\u{0485}',
Repository: sxyazi/yazi
File: yazi-adapter/src/drivers/kgp.rs (Rust)

Code before:

			while let Some(chunk) = it.next() {
				write!(buf, "{START}_Gm={};{}{ESCAPE}\\{CLOSE}", it.peek().is_some() as u8, unsafe {
					str::from_utf8_unchecked(chunk)
				})?;
			}

			write!(buf, "{CLOSE}")?;
			Ok(buf)
		}

		let size = (img.width(), img.height());
		tokio::task::spawn_blocking(move || match img {
			DynamicImage::ImageRgb8(v) => output(v.as_raw(), 24, size),
			DynamicImage::ImageRgba8(v) => output(v.as_raw(), 32, size),
			v => output(v.into_rgb8().as_raw(), 24, size),
		})
		.await?
	}

	fn place(area: &Rect) -> Result<Vec<u8>> {
		let mut buf = Vec::with_capacity(area.width as usize * area.height as usize * 3 + 50);
		write!(buf, "\x1b[38;2;0;0;1m")?;
		for y in 0..area.height {
			write!(buf, "\x1b[{};{}H", area.y + y + 1, area.x + 1)?;
			for x in 0..area.width {
				write!(buf, "\u{10EEEE}")?;
				write!(buf, "{}", *DIACRITICS.get(y as usize).unwrap_or(&DIACRITICS[0]))?;
				write!(buf, "{}", *DIACRITICS.get(x as usize).unwrap_or(&DIACRITICS[0]))?;
			}
		}
		Ok(buf)
	}
}


Review comment (refactor):
The bit manipulation operations for RGB extraction should include comments explaining the 24-bit color encoding format, as this is critical for understanding the Kitty graphics protocol implementation.

Code after:
				)?;
			}

			while let Some(chunk) = it.next() {
				write!(buf, "{START}_Gm={};{}{ESCAPE}\\{CLOSE}", it.peek().is_some() as u8, unsafe {
					str::from_utf8_unchecked(chunk)
				})?;
			}

			write!(buf, "{CLOSE}")?;
			Ok(buf)
		}

		let size = (img.width(), img.height());
		tokio::task::spawn_blocking(move || match img {
			DynamicImage::ImageRgb8(v) => output(v.as_raw(), 24, size),
			DynamicImage::ImageRgba8(v) => output(v.as_raw(), 32, size),
			v => output(v.into_rgb8().as_raw(), 24, size),
		})
		.await?
	}

	fn place(area: &Rect) -> Result<Vec<u8>> {
		let mut buf = Vec::with_capacity(area.width as usize * area.height as usize * 3 + 50);

		let id = Self::image_id();
		let (r, g, b) = ((id >> 16) & 0xff, (id >> 8) & 0xff, id & 0xff);
		write!(buf, "\x1b[38;2;{r};{g};{b}m")?;

		for y in 0..area.height {
			write!(buf, "\x1b[{};{}H", area.y + y + 1, area.x + 1)?;
			for x in 0..area.width {
				write!(buf, "\u{10EEEE}")?;
				write!(buf, "{}", *DIACRITICS.get(y as usize).unwrap_or(&DIACRITICS[0]))?;
				write!(buf, "{}", *DIACRITICS.get(x as usize).unwrap_or(&DIACRITICS[0]))?;
			}
		}
		Ok(buf)
	}

	fn image_id() -> u32 {
		static CACHE: SyncCell<Option<u32>> = SyncCell::new(None);
		match CACHE.get() {
			Some(n) => n,
			None => {
				let n = std::process::id() % (0xffffff + 1);
				CACHE.set(Some(n));
				n
			}
		}
	}
Repository: sxyazi/yazi
File: yazi-actor/src/mgr/sort.rs (Rust)

Code before:
use anyhow::Result;
use yazi_macro::{act, succ};
use yazi_parser::mgr::SortOpt;
use yazi_shared::event::Data;

use crate::{Actor, Ctx};

pub struct Sort;

impl Actor for Sort {
	type Options = SortOpt;

	const NAME: &str = "sort";

	fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
		let mut new = cx.tab().pref.clone();
		new.sort_by = opt.by.unwrap_or(new.sort_by);
		new.sort_reverse = opt.reverse.unwrap_or(new.sort_reverse);
		new.sort_dir_first = opt.dir_first.unwrap_or(new.sort_dir_first);
		new.sort_sensitive = opt.sensitive.unwrap_or(new.sort_sensitive);
		new.sort_translit = opt.translit.unwrap_or(new.sort_translit);

		if new == cx.tab().pref {
			succ!();
		}

		cx.tab_mut().pref = new;
		cx.tab_mut().apply_files_attrs();
		act!(mgr:hover, cx)?;

		cx.tasks.prework_sorted(&cx.mgr.tabs[cx.tab].current.files);
		act!(mgr:peek, cx)?;
		act!(mgr:watch, cx)?;
		act!(mgr:update_paged, cx)?;

		succ!();
	}
}


Review comment (refactor):
[nitpick] The complex pattern matching with boolean operations makes this logic hard to follow. Consider extracting this into a separate method or using clearer variable names for the boolean results.
```suggestion
		let current_applied = apply(cx.current_mut());
		let parent_applied = cx.parent_mut().map(apply);
		let any_applied = match parent_applied {
			Some(b) => current_applied || b,
			None => current_applied,
		};
		if any_applied {
```

Code after:
	const NAME: &str = "sort";

	fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
		let pref = &mut cx.tab_mut().pref;
		pref.sort_by = opt.by.unwrap_or(pref.sort_by);
		pref.sort_reverse = opt.reverse.unwrap_or(pref.sort_reverse);
		pref.sort_dir_first = opt.dir_first.unwrap_or(pref.sort_dir_first);
		pref.sort_sensitive = opt.sensitive.unwrap_or(pref.sort_sensitive);
		pref.sort_translit = opt.translit.unwrap_or(pref.sort_translit);

		let sorter = FilesSorter::from(&*pref);
		let hovered = cx.hovered().map(|f| f.urn_owned());
		let apply = |f: &mut Folder| {
			if f.stage == FolderStage::Loading {
				render!();
				false
			} else {
				f.files.set_sorter(sorter);
				render_and!(f.files.catchup_revision())
			}
		};

		// Apply to CWD and parent
		if let (a, Some(b)) = (apply(cx.current_mut()), cx.parent_mut().map(apply))
			&& (a | b)
		{
			act!(mgr:hover, cx)?;
			act!(mgr:update_paged, cx)?;
			cx.tasks.prework_sorted(&cx.mgr.tabs[cx.tab].current.files);
		}

		// Apply to hovered
		if let Some(h) = cx.hovered_folder_mut()
			&& apply(h)
		{
			render!(h.repos(None));
			act!(mgr:peek, cx, true)?;
		} else if hovered.as_deref() != cx.hovered().map(|f| f.urn()) {
			act!(mgr:peek, cx)?;
			act!(mgr:watch, cx)?;
		}

		succ!();
	}
}
Repository: sxyazi/yazi
File: yazi-actor/src/mgr/hidden.rs (Rust)

Code before:
pub struct Hidden;

impl Actor for Hidden {
	type Options = HiddenOpt;

	const NAME: &str = "hidden";

	fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
		let tab = cx.tab_mut();
		tab.pref.show_hidden = opt.state.unwrap_or(!tab.pref.show_hidden);

		let hovered = tab.hovered().map(|f| f.url_owned());
		tab.apply_files_attrs();

		if hovered.as_ref() != tab.hovered().map(|f| &f.url) {
			act!(mgr:hover, cx, hovered)?;
			act!(mgr:peek, cx)?;
			act!(mgr:watch, cx)?;
		} else if tab.hovered().is_some_and(|f| f.is_dir()) {
			act!(mgr:peek, cx, true)?;
		}

		act!(mgr:update_paged, cx)?;
		succ!();
	}
}


Review comment (refactor):
This pattern is duplicated from the sort.rs file. Consider extracting this common logic into a shared utility function to reduce code duplication.

Code after:
use crate::{Actor, Ctx};

pub struct Hidden;

impl Actor for Hidden {
	type Options = HiddenOpt;

	const NAME: &str = "hidden";

	fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
		let state = opt.state.bool(cx.tab().pref.show_hidden);
		cx.tab_mut().pref.show_hidden = state;

		let hovered = cx.hovered().map(|f| f.urn_owned());
		let apply = |f: &mut Folder| {
			if f.stage == FolderStage::Loading {
				render!();
				false
			} else {
				f.files.set_show_hidden(state);
				render_and!(f.files.catchup_revision())
			}
		};

		// Apply to CWD and parent
		if let (a, Some(b)) = (apply(cx.current_mut()), cx.parent_mut().map(apply))
			&& (a | b)
		{
			act!(mgr:hover, cx)?;
			act!(mgr:update_paged, cx)?;
		}

		// Apply to hovered
		if let Some(h) = cx.hovered_folder_mut()
			&& apply(h)
		{
			render!(h.repos(None));
			act!(mgr:peek, cx, true)?;
		} else if hovered.as_deref() != cx.hovered().map(|f| f.urn()) {
			act!(mgr:peek, cx)?;
			act!(mgr:watch, cx)?;
		}

		succ!()
	}
}