Repository: sxyazi/yazi
File: yazi-plugin/src/utils/layer.rs (Rust)

Code before:
use std::{str::FromStr, time::Duration};

use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value};
use tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream;
use yazi_binding::{deprecate, elements::{Line, Pos, Text}, runtime};
use yazi_config::{keymap::{Chord, Key}, popup::{ConfirmCfg, InputCfg}};
use yazi_macro::relay;
use yazi_parser::which::ShowOpt;
use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy, WhichProxy};
use yazi_shared::Debounce;

use super::Utils;
use crate::bindings::InputRx;

impl Utils {
	pub(super) fn which(lua: &Lua) -> mlua::Result<Function> {
		lua.create_async_function(|lua, t: Table| async move {
			if runtime!(lua)?.initing {
				return Err("Cannot call `ya.which()` during app initialization".into_lua_err());
			}

			let (tx, mut rx) = mpsc::channel::<usize>(1);
			let mut cands = Vec::with_capacity(t.raw_len());

			for (i, cand) in t.raw_get::<Table>("cands")?.sequence_values::<Table>().enumerate() {
				let cand = cand?;
				cands.push(Chord {
					on:    Self::parse_keys(cand.raw_get("on")?)?,
					run:   vec![relay!(which:callback, [i]).with_any("tx", tx.clone())],
					desc:  cand.raw_get("desc").ok(),
					r#for: None,
				});
			}

			drop(tx);
			WhichProxy::show(ShowOpt { cands, silent: t.raw_get("silent").unwrap_or_default() });

			Ok(rx.recv().await.map(|idx| idx + 1))
		})
	}

	pub(super) fn input(lua: &Lua) -> mlua::Result<Function> {
		lua.create_async_function(|lua, t: Table| async move {
			if runtime!(lua)?.initing {
				return Err("Cannot call `ya.input()` during app initialization".into_lua_err());
			}

			let mut pos = t.raw_get::<Value>("pos")?;

Review comment (bug):
The capacity allocation for `cands` vector may be incorrect. The code uses `t.raw_len()` which returns the length of the parent table `t`, but then iterates over `t.raw_get::<Table>("cands")?.sequence_values::<Table>()` which is a nested table. The capacity should be based on the length of the `cands` sub-table, not the parent table `t`. Consider using `t.raw_get::<Table>("cands")?.raw_len()` instead, or if that's not available before the iteration, keep the original magic number or use a default capacity like `Vec::new()`.

Code after:
use std::{str::FromStr, time::Duration};

use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value};
use tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream;
use yazi_binding::{deprecate, elements::{Line, Pos, Text}, runtime};
use yazi_config::{keymap::{Chord, Key}, popup::{ConfirmCfg, InputCfg}};
use yazi_macro::relay;
use yazi_parser::which::ShowOpt;
use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy, WhichProxy};
use yazi_shared::Debounce;

use super::Utils;
use crate::bindings::InputRx;

impl Utils {
	pub(super) fn which(lua: &Lua) -> mlua::Result<Function> {
		lua.create_async_function(|lua, t: Table| async move {
			if runtime!(lua)?.initing {
				return Err("Cannot call `ya.which()` during app initialization".into_lua_err());
			}

			let (tx, mut rx) = mpsc::channel::<usize>(1);
			let cands: Vec<_> = t
				.raw_get::<Table>("cands")?
				.sequence_values::<Table>()
				.enumerate()
				.map(|(i, cand)| {
					let cand = cand?;
					Ok(Chord {
						on:    Self::parse_keys(cand.raw_get("on")?)?,
						run:   vec![relay!(which:callback, [i]).with_any("tx", tx.clone())],
						desc:  cand.raw_get("desc").ok(),
						r#for: None,
					})
				})
				.collect::<mlua::Result<_>>()?;

			drop(tx);
			WhichProxy::show(ShowOpt { cands, silent: t.raw_get("silent").unwrap_or_default() });

			Ok(rx.recv().await.map(|idx| idx + 1))
		})
	}

	pub(super) fn input(lua: &Lua) -> mlua::Result<Function> {
		lua.create_async_function(|lua, t: Table| async move {
			if runtime!(lua)?.initing {
				return Err("Cannot call `ya.input()` during app initialization".into_lua_err());