Repository: sxyazi/yazi
File: yazi-adapter/src/drivers/kgp.rs (Rust)

Code before:
impl Kgp {
	pub(crate) async fn image_show(url: &Url, max: Rect) -> Result<Rect> {
		let img = Image::downscale(url, max).await?;
		let area = Image::pixel_area((img.width(), img.height()), max);

		let b1 = Self::encode(img).await?;
		let b2 = Self::place(&area)?;

		Adapter::Kgp.image_hide()?;
		Adapter::shown_store(area);
		Emulator::move_lock((area.x, area.y), |w| {
			w.write_all(&b1)?;
			w.write_all(&b2)?;
			Ok(area)
		})
	}

	pub(crate) fn image_erase(area: Rect) -> Result<()> {
		let s = " ".repeat(area.width as usize);
		Emulator::move_lock((0, 0), |w| {
			for y in area.top()..area.bottom() {
				queue!(w, MoveTo(area.x, y))?;
				write!(w, "{s}")?;
			}

			// Delete only this instance's image by ID
			write!(w, "{START}_Gq=2,a=d,d=i,i={}{ESCAPE}\\{CLOSE}", get_image_id())?;
			Ok(())
		})
	}

	async fn encode(img: DynamicImage) -> Result<Vec<u8>> {
		fn output(raw: &[u8], format: u8, size: (u32, u32)) -> Result<Vec<u8>> {
			let b64 = general_purpose::STANDARD.encode(raw).into_bytes();

			let mut it = b64.chunks(4096).peekable();
			let mut buf = Vec::with_capacity(b64.len() + it.len() * 50);
			if let Some(first) = it.next() {
				write!(
					buf,
					"{START}_Gq=2,a=T,i={},C=1,U=1,f={format},s={},v={},m={};{}{ESCAPE}\\{CLOSE}",
					get_image_id(),
					size.0,
					size.1,
					it.peek().is_some() as u8,
					unsafe { str::from_utf8_unchecked(first) },
				)?;
			}

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

Review comment (bug):
The deletion command changes from deleting all images (`d=A`) to deleting by ID (`d=i,i={}`). This could potentially leave orphaned images if the instance crashes before cleanup. Consider documenting this behavior change or adding fallback cleanup.
```suggestion
			// Delete only this instance's image by ID.
			// WARNING: This may leave orphaned images if the process crashes before cleanup.
			// Consider adding a fallback cleanup (e.g., deleting all images with d=A on exit).
```

Code after:
			w.write_all(&b2)?;
			Ok(area)
		})
	}

	pub(crate) fn image_erase(area: Rect) -> Result<()> {
		let s = " ".repeat(area.width as usize);
		Emulator::move_lock((0, 0), |w| {
			for y in area.top()..area.bottom() {
				queue!(w, MoveTo(area.x, y))?;
				write!(w, "{s}")?;
			}

			write!(w, "{START}_Gq=2,a=d,d=i,i={}{ESCAPE}\\{CLOSE}", Self::image_id())?;
			Ok(())
		})
	}

	async fn encode(img: DynamicImage) -> Result<Vec<u8>> {
		fn output(raw: &[u8], format: u8, size: (u32, u32)) -> Result<Vec<u8>> {
			let b64 = general_purpose::STANDARD.encode(raw).into_bytes();

			let mut it = b64.chunks(4096).peekable();
			let mut buf = Vec::with_capacity(b64.len() + it.len() * 50);
			if let Some(first) = it.next() {
				write!(
					buf,
					"{START}_Gq=2,a=T,i={},C=1,U=1,f={format},s={},v={},m={};{}{ESCAPE}\\{CLOSE}",
					Kgp::image_id(),
					size.0,
					size.1,
					it.peek().is_some() as u8,
					unsafe { str::from_utf8_unchecked(first) },
				)?;
			}

			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),