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

Code before:
		}

		if is_link && meta.is_symlink() {
			ck |= ChaKind::ORPHAN;
		} else if is_link {
			ck |= ChaKind::LINK;
		}

		#[cfg(unix)]
		if url.is_hidden() {
			ck |= ChaKind::HIDDEN;
		}
		#[cfg(windows)]
		{
			use std::os::windows::fs::MetadataExt;
			if meta.file_attributes() & 2 != 0 {
				ck |= ChaKind::HIDDEN;
			}
		}

		Self { url, cha: Cha::from(meta).with_kind(ck), link_to, icon: Default::default() }
	}

	pub async fn from_no_meta(url: Url, file_type: Option<FileType>) -> Self {
		// Failed to get metadata for this file, so marking it broken
		let mut ck = ChaKind::ORPHAN;

		if let Some(ft) = file_type {
			if ft.is_dir() {
				ck |= ChaKind::DIR;
			}

			if ft.is_symlink() {
				ck |= ChaKind::LINK;
			}
		}

		Self { url, cha: Cha::default().with_kind(ck), ..Default::default() }
	}

	#[inline]
	pub fn from_dummy(url: &Url) -> Self { Self { url: url.to_owned(), ..Default::default() } }
}

impl File {
	// --- Url
	#[inline]
	pub fn url(&self) -> Url { self.url.clone() }

	#[inline]
	pub fn name(&self) -> Option<&OsStr> { self.url.file_name() }

Review comment (bug):
We can't use `ORPHAN` to mark it as a broken file, because `ORPHAN` indicates a normal link file whose file linked to doesn't exist, not a file that itself is inaccessible for metadata (but exists and is a non-link file).

Code after:
		}

		if is_link && meta.is_symlink() {
			ck |= ChaKind::ORPHAN;
		} else if is_link {
			ck |= ChaKind::LINK;
		}

		#[cfg(unix)]
		if url.is_hidden() {
			ck |= ChaKind::HIDDEN;
		}
		#[cfg(windows)]
		{
			use std::os::windows::fs::MetadataExt;
			if meta.file_attributes() & 2 != 0 {
				ck |= ChaKind::HIDDEN;
			}
		}

		Self { url, cha: Cha::from(meta).with_kind(ck), link_to, icon: Default::default() }
	}

	#[inline]
	pub fn from_dummy(url: Url, ft: Option<FileType>) -> Self {
		// TODO: set dummy=true
		Self { url: url.to_owned(), cha: ft.map_or_else(Cha::default, Cha::from), ..Default::default() }
	}
}

impl File {
	// --- Url
	#[inline]
	pub fn url(&self) -> Url { self.url.clone() }

	#[inline]
	pub fn name(&self) -> Option<&OsStr> { self.url.file_name() }

	#[inline]
	pub fn stem(&self) -> Option<&OsStr> { self.url.file_stem() }

	#[inline]
	pub fn parent(&self) -> Option<Url> { self.url.parent_url() }
}
Repository: sxyazi/yazi
File: yazi-plugin/preset/ya.lua (Lua)

Code before:
	local i = 1
	while size > 1024.0 and i < #units do
		size = size / 1024.0
		i = i + 1
	end
	return string.format("%.1f%s", size, units[i])
end

function ya.readable_path(path)
	local home = os.getenv("HOME") or os.getenv("USERPROFILE")
	if not home then
		return path
	elseif string.sub(path, 1, #home) == home then
		return "~" .. string.sub(path, #home + 1)
	else
		return path
	end
end

function ya.owner(cha)
	if not cha.uid or not cha.gid then
		return nil
	end

	user = ya.user_name(cha.uid) or cha.uid
	group = ya.group_name(cha.gid) or cha.gid

	return user .. ":" .. group
end


Review comment (bug):
I wanted to write this helper function to handle possibly missing `uid` and `gid` values. It incidentally fixes a bug in Yazi where the linemode would fail if `uid` was available, but the user name was not.

Code after:
table.unpack = table.unpack or unpack

ya = ya or {}

function ya.clamp(min, x, max)
	if x < min then
		return min
	elseif x > max then
		return max
	else
		return x
	end
end

function ya.round(x) return x >= 0 and math.floor(x + 0.5) or math.ceil(x - 0.5) end

function ya.list_merge(a, b)
	for _, v in ipairs(b) do
		a[#a + 1] = v
	end
	return a
end

function ya.basename(str) return string.gsub(str, "(.*[/\\])(.*)", "%2") end

function ya.readable_size(size)
	local units = { "B", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q" }
	local i = 1
	while size > 1024.0 and i < #units do
		size = size / 1024.0
		i = i + 1
	end
	return string.format("%.1f%s", size, units[i])
end

function ya.readable_path(path)
	local home = os.getenv("HOME") or os.getenv("USERPROFILE")
	if not home then
		return path
	elseif string.sub(path, 1, #home) == home then
		return "~" .. string.sub(path, #home + 1)
	else
		return path
	end
end

function ya.child_at(position, children)
	for i = #children, 1, -1 do
		if children[i]._area:contains(position) then
			return children[i]
		end
	end
end
Repository: sxyazi/yazi
File: yazi-shared/src/fs/cha.rs (Rust)

Code before:
			},
			#[cfg(unix)]
			gid:                      {
				use std::os::unix::fs::MetadataExt;
				m.gid() as _
			},
			#[cfg(unix)]
			nlink:                    {
				use std::os::unix::fs::MetadataExt;
				m.nlink() as _
			},
		}
	}
}

impl From<FileType> for Cha {
	fn from(file_type: FileType) -> Self {
		let mut kind = ChaKind::empty();
		let mut permissions = 0;

		if file_type.is_dir() {
			kind |= ChaKind::DIR;

			#[cfg(unix)]
			{
				permissions |= libc::S_IFDIR;
			}
		}

		if file_type.is_symlink() {
			kind |= ChaKind::LINK;

			#[cfg(unix)]
			{
				permissions |= libc::S_IFLNK;
			}
		}

		Self {
			kind,

			#[cfg(unix)]
			permissions,

			..Default::default()
		}
	}
}

impl Cha {
	#[inline]

Review comment (security):
Why does the permission here only consider `libc::S_IFDIR`? What about the others?

https://github.com/sxyazi/yazi/blob/afa5936bf5102865ef9d9456823ede8e24ecc42e/yazi-shared/src/fs/fns.rs#L271-L280

Code after:
			if t.is_dir() {
				kind |= ChaKind::DIR;
				libc::S_IFDIR
			} else if t.is_symlink() {
				kind |= ChaKind::LINK;
				libc::S_IFLNK
			} else if t.is_block_device() {
				libc::S_IFBLK
			} else if t.is_char_device() {
				libc::S_IFCHR
			} else if t.is_fifo() {
				libc::S_IFIFO
			} else if t.is_socket() {
				libc::S_IFSOCK
			} else {
				0
			}
		};

		#[cfg(windows)]
		{
			if t.is_dir() {
				kind |= ChaKind::DIR;
			} else if t.is_symlink() {
				kind |= ChaKind::LINK;
			}
		}

		Self {
			kind,
			#[cfg(unix)]
			perm,
			..Default::default()
		}
	}
}

impl Cha {
	#[inline]
	pub fn with_kind(mut self, kind: ChaKind) -> Self {
		self.kind |= kind;
		self
	}
}

impl Cha {
	#[inline]
	pub const fn is_dir(&self) -> bool { self.kind.contains(ChaKind::DIR) }

	#[inline]
	pub const fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) }
Repository: sxyazi/yazi
File: yazi-plugin/src/utils/user.rs (Rust)

Code before:

		use crate::utils::HOSTNAME_CACHE;

		ya.raw_set("uid", lua.create_function(|_, ()| Ok(USERS_CACHE.get_current_uid()))?)?;

		ya.raw_set("gid", lua.create_function(|_, ()| Ok(USERS_CACHE.get_current_gid()))?)?;

		ya.raw_set(
			"user_name",
			lua.create_function(|lua, uid: Option<Option<u32>>| {
				let user_id = match uid {
					None => USERS_CACHE.get_current_uid(),
					Some(None) => return Ok(None),
					Some(Some(u)) => u,
				};

				USERS_CACHE
					.get_user_by_uid(user_id)
					.map(|s| lua.create_string(s.name().as_encoded_bytes()))
					.transpose()
			})?,
		)?;

		ya.raw_set(
			"group_name",
			lua.create_function(|lua, gid: Option<Option<u32>>| {
				let group_id = match gid {
					None => USERS_CACHE.get_current_gid(),
					Some(None) => return Ok(None),
					Some(Some(g)) => g,
				};

				USERS_CACHE
					.get_group_by_gid(group_id)
					.map(|s| lua.create_string(s.name().as_encoded_bytes()))
					.transpose()
			})?,
		)?;

		ya.raw_set(
			"host_name",
			lua.create_function(|lua, ()| {
				HOSTNAME_CACHE
					.get_or_init(|| hostname().ok())
					.as_ref()
					.map(|s| lua.create_string(s))
					.transpose()
			})?,
		)?;

		Ok(())

Review comment (suggestion):
In what case would the value passed from Lua be `Option<Option<u32>>`? If you call it with `ya.group_name(nil)`, it would only be an `Option<u32>`.

Code after:

		use crate::utils::HOSTNAME_CACHE;

		ya.raw_set("uid", lua.create_function(|_, ()| Ok(USERS_CACHE.get_current_uid()))?)?;

		ya.raw_set("gid", lua.create_function(|_, ()| Ok(USERS_CACHE.get_current_gid()))?)?;

		ya.raw_set(
			"user_name",
			lua.create_function(|lua, uid: Option<u32>| {
				USERS_CACHE
					.get_user_by_uid(uid.unwrap_or_else(|| USERS_CACHE.get_current_uid()))
					.map(|s| lua.create_string(s.name().as_encoded_bytes()))
					.transpose()
			})?,
		)?;

		ya.raw_set(
			"group_name",
			lua.create_function(|lua, gid: Option<u32>| {
				USERS_CACHE
					.get_group_by_gid(gid.unwrap_or_else(|| USERS_CACHE.get_current_gid()))
					.map(|s| lua.create_string(s.name().as_encoded_bytes()))
					.transpose()
			})?,
		)?;

		ya.raw_set(
			"host_name",
			lua.create_function(|lua, ()| {
				HOSTNAME_CACHE
					.get_or_init(|| hostname().ok())
					.as_ref()
					.map(|s| lua.create_string(s))
					.transpose()
			})?,
		)?;

		Ok(())
	}

	#[cfg(windows)]
	pub(super) fn user(_lua: &Lua, _ya: &Table) -> mlua::Result<()> { Ok(()) }
}
Repository: sxyazi/yazi
File: yazi-dds/src/body/delete.rs (Rust)

Code before:

use super::Body;

#[derive(Debug, Serialize, Deserialize)]
pub struct BodyDelete<'a> {
	pub urls: Cow<'a, Vec<Url>>,
}

impl<'a> BodyDelete<'a> {
	#[inline]
	pub fn borrowed(urls: &'a Vec<Url>) -> Body<'a> { Self { urls: Cow::Borrowed(urls) }.into() }
}

impl BodyDelete<'static> {
	#[inline]
	pub fn owned(urls: Vec<Url>) -> Body<'static> { Self { urls: Cow::Owned(urls) }.into() }
}

impl<'a> From<BodyDelete<'a>> for Body<'a> {
	fn from(value: BodyDelete<'a>) -> Self { Self::Delete(value) }
}

impl IntoLua<'_> for BodyDelete<'static> {
	fn into_lua(self, lua: &Lua) -> mlua::Result<Value<'_>> {
		let urls = lua.create_table_with_capacity(self.urls.len(), 0)?;
		for (i, url) in self.urls.iter().cloned().enumerate() {
			urls.raw_set(i + 1, lua.create_any_userdata(url)?)?;
		}
		lua.create_table_from([("urls", urls)])?.into_lua(lua)
	}
}


Review comment (suggestion):
This seems to be a false positive. In most cases, `self.urls` will be `Cow::Owned`, so `.into_owned().into_iter()` can avoid any cloning, whereas `.iter().cloned()` will clone each element.

Code after:

use super::Body;

#[derive(Debug, Serialize, Deserialize)]
pub struct BodyDelete<'a> {
	pub urls: Cow<'a, Vec<Url>>,
}

impl<'a> BodyDelete<'a> {
	#[inline]
	pub fn borrowed(urls: &'a Vec<Url>) -> Body<'a> { Self { urls: Cow::Borrowed(urls) }.into() }
}

impl BodyDelete<'static> {
	#[inline]
	pub fn owned(urls: Vec<Url>) -> Body<'static> { Self { urls: Cow::Owned(urls) }.into() }
}

impl<'a> From<BodyDelete<'a>> for Body<'a> {
	fn from(value: BodyDelete<'a>) -> Self { Self::Delete(value) }
}

impl IntoLua<'_> for BodyDelete<'static> {
	fn into_lua(self, lua: &Lua) -> mlua::Result<Value<'_>> {
		let urls = lua.create_table_with_capacity(self.urls.len(), 0)?;

		// In most cases, `self.urls` will be `Cow::Owned`, so
		// `.into_owned().into_iter()` can avoid any cloning, whereas
		// `.iter().cloned()` will clone each element.
		#[allow(clippy::unnecessary_to_owned)]
		for (i, url) in self.urls.into_owned().into_iter().enumerate() {
			urls.raw_set(i + 1, lua.create_any_userdata(url)?)?;
		}

		lua.create_table_from([("urls", urls)])?.into_lua(lua)
	}
}
Repository: sxyazi/yazi
File: yazi-adapter/src/adapter.rs (Rust)

Code before:

		#[cfg(windows)]
		protocols.retain(|p| *p == Self::Iterm2);
		if env_exists("ZELLIJ_SESSION_NAME") {
			protocols.retain(|p| *p == Self::Sixel);
		} else if *TMUX {
			protocols.retain(|p| *p != Self::KittyOld);
		}
		if let Some(p) = protocols.first() {
			return *p;
		}

		// Currently Überzug++'s Wayland output only supports Sway, Hyprland and Wayfire
		// as it requires information from specific compositior socket directly.
		// These environment variables are from ueberzugpp src/canvas/wayland/config.cpp
		let supports_ueberzug_wayland = env_exists("SWAYSOCK")
			|| env_exists("HYPRLAND_INSTANCE_SIGNATURE")
			|| env_exists("WAYFIRE_SOCKET");

		match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
			"x11" => return Self::X11,
			"wayland" => {
				if supports_ueberzug_wayland {
					return Self::Wayland;
				}
			}
			_ => warn!("[Adapter] Could not identify XDG_SESSION_TYPE"),
		}
		if supports_ueberzug_wayland && env_exists("WAYLAND_DISPLAY") {
			return Self::Wayland;
		}
		if env_exists("DISPLAY") {
			return Self::X11;
		}
		if std::fs::symlink_metadata("/proc/sys/fs/binfmt_misc/WSLInterop").is_ok() {
			return Self::KittyOld;
		}

		warn!("[Adapter] Falling back to chafa");
		Self::Chafa
	}
}


Review comment (suggestion):
```suggestion
			"wayland" if supports_ueberzug_wayland => return Self::Wayland,
			"wayland" if !supports_ueberzug_wayland => warn!("[Adapter] Unsupported Wayland compositor"),
```

Code after:

		#[cfg(windows)]
		protocols.retain(|p| *p == Self::Iterm2);
		if env_exists("ZELLIJ_SESSION_NAME") {
			protocols.retain(|p| *p == Self::Sixel);
		} else if *TMUX {
			protocols.retain(|p| *p != Self::KittyOld);
		}
		if let Some(p) = protocols.first() {
			return *p;
		}

		let supported_compositor = Ueberzug::supported_compositor();
		match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
			"x11" => return Self::X11,
			"wayland" if supported_compositor => return Self::Wayland,
			"wayland" if !supported_compositor => warn!("[Adapter] Unsupported Wayland compositor"),
			_ => warn!("[Adapter] Could not identify XDG_SESSION_TYPE"),
		}
		if supported_compositor && env_exists("WAYLAND_DISPLAY") {
			return Self::Wayland;
		}
		if env_exists("DISPLAY") {
			return Self::X11;
		}
		if std::fs::symlink_metadata("/proc/sys/fs/binfmt_misc/WSLInterop").is_ok() {
			return Self::KittyOld;
		}

		warn!("[Adapter] Falling back to chafa");
		Self::Chafa
	}
}
Repository: sxyazi/yazi
File: yazi-adapter/src/dimension.rs (Rust)

Code before:
use std::mem;

use crossterm::terminal::WindowSize;

pub struct Dimension;

impl Dimension {
	pub fn available() -> WindowSize {
		let mut size = WindowSize { rows: 0, columns: 0, width: 0, height: 0 };
		if let Ok(s) = crossterm::terminal::window_size() {
			_ = mem::replace(&mut size, s);
		}

		if size.rows == 0 || size.columns == 0 {
			if let Ok((columns, rows)) = crossterm::terminal::size() {
				size.columns = columns;
				size.rows = rows;
			}
		}

		// TODO: Use `CSI 14 t` to get the actual size of the terminal
		// if size.width == 0 || size.height == 0 {}

		size
	}

	#[inline]
	pub fn ratio() -> Option<(f64, f64)> {
		let s = Self::available();
		if s.width == 0 || s.height == 0 {
			return None;
		}
		Some((f64::from(s.width) / f64::from(s.columns), f64::from(s.height) / f64::from(s.rows)))
	}
}


Review comment (suggestion):
```suggestion
			if let Ok((cols, rows)) = crossterm::terminal::size() {
```

Code after:
use std::mem;

use crossterm::terminal::WindowSize;

pub struct Dimension;

impl Dimension {
	pub fn available() -> WindowSize {
		let mut size = WindowSize { rows: 0, columns: 0, width: 0, height: 0 };
		if let Ok(s) = crossterm::terminal::window_size() {
			_ = mem::replace(&mut size, s);
		}

		if size.rows == 0 || size.columns == 0 {
			if let Ok((cols, rows)) = crossterm::terminal::size() {
				size.columns = cols;
				size.rows = rows;
			}
		}

		// TODO: Use `CSI 14 t` to get the actual size of the terminal
		// if size.width == 0 || size.height == 0 {}

		size
	}

	#[inline]
	pub fn ratio() -> Option<(f64, f64)> {
		let s = Self::available();
		if s.width == 0 || s.height == 0 {
			return None;
		}
		Some((f64::from(s.width) / f64::from(s.columns), f64::from(s.height) / f64::from(s.rows)))
	}
}
Repository: sxyazi/yazi
File: yazi-fm/src/signals.rs (Rust)

Code before:
	}

	fn spawn(mut rx: mpsc::UnboundedReceiver<(bool, Option<oneshot::Sender<()>>)>) -> Result<()> {
		#[cfg(unix)]
		use libc::{SIGCONT, SIGHUP, SIGQUIT, SIGTERM, SIGTSTP};

		#[cfg(unix)]
		let mut sys = signal_hook_tokio::Signals::new([
			// Terminating signals
			SIGHUP, SIGTERM, SIGQUIT, //
			// Job control signals
			SIGTSTP, SIGCONT,
		])?;
		#[cfg(windows)]
		let mut sys = tokio_stream::empty();

		let mut term = Some(EventStream::new());

		tokio::spawn(async move {
			loop {
				if let Some(t) = &mut term {
					select! {
						biased;
						Some((s, mut cb)) = rx.recv() => {
							term = term.filter(|_| s);
							cb.take().map(|cb| cb.send(()));
						},
						Some(n) = sys.next() => if !Self::handle_sys(n) { return },
						Some(Ok(e)) = t.next() => Self::handle_term(e)
					}
				} else {
					select! {
						biased;
						Some((s, mut cb)) = rx.recv() => {
							term = s.then(EventStream::new);
							cb.take().map(|cb| cb.send(()));
						},
						Some(n) = sys.next() => if !Self::handle_sys(n) { return },
					}
				}
			}
		});

		Ok(())
	}
}


Review comment (suggestion):
I used `s` here because if we use `cb`, it will clash with the `cb` arg in `map(|cb|`, which lowers the recognizability

Code after:
	}

	fn spawn(mut rx: mpsc::UnboundedReceiver<(bool, Option<oneshot::Sender<()>>)>) -> Result<()> {
		#[cfg(unix)]
		use libc::{SIGCONT, SIGHUP, SIGQUIT, SIGTERM, SIGTSTP};

		#[cfg(unix)]
		let mut sys = signal_hook_tokio::Signals::new([
			// Terminating signals
			SIGHUP, SIGTERM, SIGQUIT, //
			// Job control signals
			SIGTSTP, SIGCONT,
		])?;
		#[cfg(windows)]
		let mut sys = tokio_stream::empty();

		let mut term = Some(EventStream::new());

		tokio::spawn(async move {
			loop {
				if let Some(t) = &mut term {
					select! {
						biased;
						Some((state, mut callback)) = rx.recv() => {
							term = term.filter(|_| state);
							callback.take().map(|cb| cb.send(()));
						},
						Some(n) = sys.next() => if !Self::handle_sys(n) { return },
						Some(Ok(e)) = t.next() => Self::handle_term(e)
					}
				} else {
					select! {
						biased;
						Some((state, mut callback)) = rx.recv() => {
							term = state.then(EventStream::new);
							callback.take().map(|cb| cb.send(()));
						},
						Some(n) = sys.next() => if !Self::handle_sys(n) { return },
					}
				}
			}
		});

		Ok(())
	}
}
Repository: sxyazi/yazi
File: yazi-fm/src/signals.rs (Rust)

Code before:
			_ => {}
		}
	}

	fn spawn(mut rx: mpsc::UnboundedReceiver<(bool, Option<oneshot::Sender<()>>)>) -> Result<()> {
		#[cfg(unix)]
		use libc::{SIGCONT, SIGHUP, SIGQUIT, SIGTERM, SIGTSTP};

		#[cfg(unix)]
		let mut sys = signal_hook_tokio::Signals::new([
			// Terminating signals
			SIGHUP, SIGTERM, SIGQUIT, //
			// Job control signals
			SIGTSTP, SIGCONT,
		])?;
		#[cfg(windows)]
		let mut sys = tokio_stream::empty();

		let mut term = Some(EventStream::new());

		tokio::spawn(async move {
			loop {
				if let Some(t) = &mut term {
					select! {
						biased;
						Some((status, mut callback)) = rx.recv() => {
							term = term.filter(|_| status);
							callback.take().map(|cb| cb.send(()));
						},
						Some(n) = sys.next() => if !Self::handle_sys(n) { return },
						Some(Ok(e)) = t.next() => Self::handle_term(e)
					}
				} else {
					select! {
						biased;
						Some((status, mut callback)) = rx.recv() => {
							term = status.then(EventStream::new);
							callback.take().map(|cb| cb.send(()));
						},
						Some(n) = sys.next() => if !Self::handle_sys(n) { return },
					}
				}
			}
		});

		Ok(())
	}
}


Review comment (suggestion):
nit

```suggestion
						Some((state, mut callback)) = rx.recv() => {
```

Code after:
			_ => {}
		}
	}

	fn spawn(mut rx: mpsc::UnboundedReceiver<(bool, Option<oneshot::Sender<()>>)>) -> Result<()> {
		#[cfg(unix)]
		use libc::{SIGCONT, SIGHUP, SIGQUIT, SIGTERM, SIGTSTP};

		#[cfg(unix)]
		let mut sys = signal_hook_tokio::Signals::new([
			// Terminating signals
			SIGHUP, SIGTERM, SIGQUIT, //
			// Job control signals
			SIGTSTP, SIGCONT,
		])?;
		#[cfg(windows)]
		let mut sys = tokio_stream::empty();

		let mut term = Some(EventStream::new());

		tokio::spawn(async move {
			loop {
				if let Some(t) = &mut term {
					select! {
						biased;
						Some((state, mut callback)) = rx.recv() => {
							term = term.filter(|_| state);
							callback.take().map(|cb| cb.send(()));
						},
						Some(n) = sys.next() => if !Self::handle_sys(n) { return },
						Some(Ok(e)) = t.next() => Self::handle_term(e)
					}
				} else {
					select! {
						biased;
						Some((state, mut callback)) = rx.recv() => {
							term = state.then(EventStream::new);
							callback.take().map(|cb| cb.send(()));
						},
						Some(n) = sys.next() => if !Self::handle_sys(n) { return },
					}
				}
			}
		});

		Ok(())
	}
}
Repository: sxyazi/yazi
File: yazi-plugin/src/elements/gauge.rs (Rust)

Code before:
}

impl UserData for Gauge {
	fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
		crate::impl_area_method!(methods);
		crate::impl_style_method!(methods, style);

		methods.add_function_mut("percent", |_, (ud, percent): (AnyUserData, u8)| {
			if percent > 100 {
				return Err("percent must be between 0 and 100".into_lua_err());
			}

			ud.borrow_mut::<Self>()?.ratio = percent as f64 / 100.0;
			Ok(ud)
		});

		methods.add_function_mut("ratio", |_, (ud, ratio): (AnyUserData, f64)| {
			if !(0.0..1.0).contains(&ratio) {
				return Err("ratio must be between 0 and 1".into_lua_err());
			}

			ud.borrow_mut::<Self>()?.ratio = ratio;
			Ok(ud)
		});

		methods.add_function_mut("label", |_, (ud, Span(label)): (AnyUserData, Span)| {
			ud.borrow_mut::<Self>()?.label = Some(label);
			Ok(ud)
		});

		methods.add_function_mut("gauge_style", |_, (ud, value): (AnyUserData, Value)| {
			ud.borrow_mut::<Self>()?.gauge_style = Style::try_from(value)?.0;
			Ok(ud)
		});
	}
}

impl Renderable for Gauge {
	fn area(&self) -> ratatui::layout::Rect { *self.area }

	fn render(self: Box<Self>, buf: &mut ratatui::buffer::Buffer) {
		let mut gauge = ratatui::widgets::Gauge::default()
			.ratio(self.ratio)
			.style(self.style)
			.gauge_style(self.gauge_style);

		if let Some(s) = self.label {
			gauge = gauge.label(s)
		}

		gauge.render(*self.area, buf);

Review comment (suggestion):
Please keep the original code here since I want to avoid the `Span` twice

Code after:
}

impl UserData for Gauge {
	fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
		crate::impl_area_method!(methods);
		crate::impl_style_method!(methods, style);

		methods.add_function_mut("percent", |_, (ud, percent): (AnyUserData, u8)| {
			if percent > 100 {
				return Err("percent must be between 0 and 100".into_lua_err());
			}

			ud.borrow_mut::<Self>()?.ratio = percent as f64 / 100.0;
			Ok(ud)
		});

		methods.add_function_mut("ratio", |_, (ud, ratio): (AnyUserData, f64)| {
			if !(0.0..1.0).contains(&ratio) {
				return Err("ratio must be between 0 and 1".into_lua_err());
			}

			ud.borrow_mut::<Self>()?.ratio = ratio;
			Ok(ud)
		});

		methods.add_function_mut("label", |_, (ud, label): (AnyUserData, Span)| {
			ud.borrow_mut::<Self>()?.label = Some(label.0);
			Ok(ud)
		});

		methods.add_function_mut("gauge_style", |_, (ud, value): (AnyUserData, Value)| {
			ud.borrow_mut::<Self>()?.gauge_style = Style::try_from(value)?.0;
			Ok(ud)
		});
	}
}

impl Renderable for Gauge {
	fn area(&self) -> ratatui::layout::Rect { *self.area }

	fn render(self: Box<Self>, buf: &mut ratatui::buffer::Buffer) {
		let mut gauge = ratatui::widgets::Gauge::default()
			.ratio(self.ratio)
			.style(self.style)
			.gauge_style(self.gauge_style);

		if let Some(s) = self.label {
			gauge = gauge.label(s)
		}

		gauge.render(*self.area, buf);