mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
fix: cursor gets out of sync occasionally at image previewing through IIP under tmux (#1070)
This commit is contained in:
parent
0ebfacb677
commit
f41e3c8d8b
8 changed files with 49 additions and 52 deletions
|
|
@ -41,7 +41,7 @@ https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265
|
||||||
| Platform | Protocol | Support |
|
| Platform | Protocol | Support |
|
||||||
| ----------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
| ----------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
||||||
| kitty | [Kitty unicode placeholders](https://sw.kovidgoyal.net/kitty/graphics-protocol/#unicode-placeholders) | ✅ Built-in |
|
| kitty | [Kitty unicode placeholders](https://sw.kovidgoyal.net/kitty/graphics-protocol/#unicode-placeholders) | ✅ Built-in |
|
||||||
| Konsole | [Kitty old protocol](https://github.com/sxyazi/yazi/blob/main/yazi-adaptor/src/kitty_old.rs) | ✅ Built-in |
|
| Konsole | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||||
| iTerm2 | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
| iTerm2 | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||||
| WezTerm | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
| WezTerm | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||||
| Mintty (Git Bash) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
| Mintty (Git Bash) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use ratatui::layout::Rect;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use yazi_shared::term::Term;
|
use yazi_shared::term::Term;
|
||||||
|
|
||||||
use crate::Adaptor;
|
use crate::{Adaptor, Emulator};
|
||||||
|
|
||||||
pub(super) struct Chafa;
|
pub(super) struct Chafa;
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ impl Chafa {
|
||||||
};
|
};
|
||||||
|
|
||||||
Adaptor::shown_store(area);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((max.x, max.y), |stderr| {
|
Emulator::move_lock((max.x, max.y), |stderr| {
|
||||||
for (i, line) in lines.into_iter().enumerate() {
|
for (i, line) in lines.into_iter().enumerate() {
|
||||||
stderr.write_all(line)?;
|
stderr.write_all(line)?;
|
||||||
Term::move_to(stderr, max.x, max.y + i as u16 + 1)?;
|
Term::move_to(stderr, max.x, max.y + i as u16 + 1)?;
|
||||||
|
|
@ -65,7 +65,7 @@ impl Chafa {
|
||||||
|
|
||||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||||
let s = " ".repeat(area.width as usize);
|
let s = " ".repeat(area.width as usize);
|
||||||
Term::move_lock((0, 0), |stderr| {
|
Emulator::move_lock((0, 0), |stderr| {
|
||||||
for y in area.top()..area.bottom() {
|
for y in area.top()..area.bottom() {
|
||||||
Term::move_to(stderr, area.x, y)?;
|
Term::move_to(stderr, area.x, y)?;
|
||||||
write!(stderr, "{s}")?;
|
write!(stderr, "{s}")?;
|
||||||
|
|
|
||||||
|
|
@ -155,4 +155,36 @@ impl Emulator {
|
||||||
|
|
||||||
Ok(Self::Unknown(adapters))
|
Ok(Self::Unknown(adapters))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn move_lock<F, T>((x, y): (u16, u16), cb: F) -> Result<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut std::io::BufWriter<std::io::StderrLock>) -> Result<T>,
|
||||||
|
{
|
||||||
|
use std::{io::Write, thread, time::Duration};
|
||||||
|
|
||||||
|
use crossterm::{cursor::{Hide, MoveTo, RestorePosition, SavePosition, Show}, queue};
|
||||||
|
|
||||||
|
let mut buf = std::io::BufWriter::new(stderr().lock());
|
||||||
|
|
||||||
|
// I really don't want to add this,
|
||||||
|
// But tmux and ConPTY sometimes cause the cursor position to get out of sync.
|
||||||
|
if *TMUX || cfg!(windows) {
|
||||||
|
execute!(buf, SavePosition, MoveTo(x, y), Show)?;
|
||||||
|
execute!(buf, MoveTo(x, y), Show)?;
|
||||||
|
execute!(buf, MoveTo(x, y), Show)?;
|
||||||
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
} else {
|
||||||
|
queue!(buf, SavePosition, MoveTo(x, y))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = cb(&mut buf);
|
||||||
|
if *TMUX || cfg!(windows) {
|
||||||
|
queue!(buf, Hide, RestorePosition)?;
|
||||||
|
} else {
|
||||||
|
queue!(buf, RestorePosition)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.flush()?;
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use ratatui::layout::Rect;
|
||||||
use yazi_shared::term::Term;
|
use yazi_shared::term::Term;
|
||||||
|
|
||||||
use super::image::Image;
|
use super::image::Image;
|
||||||
use crate::{adaptor::Adaptor, CLOSE, START};
|
use crate::{adaptor::Adaptor, Emulator, CLOSE, START};
|
||||||
|
|
||||||
pub(super) struct Iterm2;
|
pub(super) struct Iterm2;
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ impl Iterm2 {
|
||||||
|
|
||||||
Adaptor::Iterm2.image_hide()?;
|
Adaptor::Iterm2.image_hide()?;
|
||||||
Adaptor::shown_store(area);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((max.x, max.y), |stderr| {
|
Emulator::move_lock((max.x, max.y), |stderr| {
|
||||||
stderr.write_all(&b)?;
|
stderr.write_all(&b)?;
|
||||||
Ok(area)
|
Ok(area)
|
||||||
})
|
})
|
||||||
|
|
@ -27,7 +27,7 @@ impl Iterm2 {
|
||||||
|
|
||||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||||
let s = " ".repeat(area.width as usize);
|
let s = " ".repeat(area.width as usize);
|
||||||
Term::move_lock((0, 0), |stderr| {
|
Emulator::move_lock((0, 0), |stderr| {
|
||||||
for y in area.top()..area.bottom() {
|
for y in area.top()..area.bottom() {
|
||||||
Term::move_to(stderr, area.x, y)?;
|
Term::move_to(stderr, area.x, y)?;
|
||||||
write!(stderr, "{s}")?;
|
write!(stderr, "{s}")?;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use ratatui::layout::Rect;
|
||||||
use yazi_shared::term::Term;
|
use yazi_shared::term::Term;
|
||||||
|
|
||||||
use super::image::Image;
|
use super::image::Image;
|
||||||
use crate::{adaptor::Adaptor, CLOSE, ESCAPE, START};
|
use crate::{adaptor::Adaptor, Emulator, CLOSE, ESCAPE, START};
|
||||||
|
|
||||||
static DIACRITICS: [char; 297] = [
|
static DIACRITICS: [char; 297] = [
|
||||||
'\u{0305}',
|
'\u{0305}',
|
||||||
|
|
@ -322,7 +322,7 @@ impl Kitty {
|
||||||
|
|
||||||
Adaptor::Kitty.image_hide()?;
|
Adaptor::Kitty.image_hide()?;
|
||||||
Adaptor::shown_store(area);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((area.x, area.y), |stderr| {
|
Emulator::move_lock((area.x, area.y), |stderr| {
|
||||||
stderr.write_all(&b1)?;
|
stderr.write_all(&b1)?;
|
||||||
stderr.write_all(&b2)?;
|
stderr.write_all(&b2)?;
|
||||||
Ok(area)
|
Ok(area)
|
||||||
|
|
@ -331,7 +331,7 @@ impl Kitty {
|
||||||
|
|
||||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||||
let s = " ".repeat(area.width as usize);
|
let s = " ".repeat(area.width as usize);
|
||||||
Term::move_lock((0, 0), |stderr| {
|
Emulator::move_lock((0, 0), |stderr| {
|
||||||
for y in area.top()..area.bottom() {
|
for y in area.top()..area.bottom() {
|
||||||
Term::move_to(stderr, area.x, y)?;
|
Term::move_to(stderr, area.x, y)?;
|
||||||
write!(stderr, "{s}")?;
|
write!(stderr, "{s}")?;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,9 @@ use anyhow::Result;
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{engine::general_purpose, Engine};
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
use ratatui::layout::Rect;
|
use ratatui::layout::Rect;
|
||||||
use yazi_shared::term::Term;
|
|
||||||
|
|
||||||
use super::image::Image;
|
use super::image::Image;
|
||||||
use crate::{adaptor::Adaptor, CLOSE, ESCAPE, START};
|
use crate::{adaptor::Adaptor, Emulator, CLOSE, ESCAPE, START};
|
||||||
|
|
||||||
pub(super) struct KittyOld;
|
pub(super) struct KittyOld;
|
||||||
|
|
||||||
|
|
@ -20,7 +19,7 @@ impl KittyOld {
|
||||||
|
|
||||||
Adaptor::KittyOld.image_hide()?;
|
Adaptor::KittyOld.image_hide()?;
|
||||||
Adaptor::shown_store(area);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((area.x, area.y), |stderr| {
|
Emulator::move_lock((area.x, area.y), |stderr| {
|
||||||
stderr.write_all(&b)?;
|
stderr.write_all(&b)?;
|
||||||
Ok(area)
|
Ok(area)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use ratatui::layout::Rect;
|
||||||
use yazi_config::PREVIEW;
|
use yazi_config::PREVIEW;
|
||||||
use yazi_shared::term::Term;
|
use yazi_shared::term::Term;
|
||||||
|
|
||||||
use crate::{adaptor::Adaptor, Image, CLOSE, ESCAPE, START};
|
use crate::{adaptor::Adaptor, Emulator, Image, CLOSE, ESCAPE, START};
|
||||||
|
|
||||||
pub(super) struct Sixel;
|
pub(super) struct Sixel;
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ impl Sixel {
|
||||||
|
|
||||||
Adaptor::Sixel.image_hide()?;
|
Adaptor::Sixel.image_hide()?;
|
||||||
Adaptor::shown_store(area);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((area.x, area.y), |stderr| {
|
Emulator::move_lock((area.x, area.y), |stderr| {
|
||||||
stderr.write_all(&b)?;
|
stderr.write_all(&b)?;
|
||||||
Ok(area)
|
Ok(area)
|
||||||
})
|
})
|
||||||
|
|
@ -27,7 +27,7 @@ impl Sixel {
|
||||||
|
|
||||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||||
let s = " ".repeat(area.width as usize);
|
let s = " ".repeat(area.width as usize);
|
||||||
Term::move_lock((0, 0), |stderr| {
|
Emulator::move_lock((0, 0), |stderr| {
|
||||||
for y in area.top()..area.bottom() {
|
for y in area.top()..area.bottom() {
|
||||||
Term::move_to(stderr, area.x, y)?;
|
Term::move_to(stderr, area.x, y)?;
|
||||||
write!(stderr, "{s}")?;
|
write!(stderr, "{s}")?;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::io::{stderr, BufWriter, StderrLock, Write};
|
use std::io::{stderr, Write};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::{cursor::{MoveTo, RestorePosition, SavePosition, SetCursorStyle}, queue};
|
use crossterm::{cursor::{MoveTo, SetCursorStyle}, queue};
|
||||||
|
|
||||||
use super::Term;
|
use super::Term;
|
||||||
|
|
||||||
|
|
@ -9,40 +9,6 @@ impl Term {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn move_to(w: &mut impl Write, x: u16, y: u16) -> Result<()> { Ok(queue!(w, MoveTo(x, y))?) }
|
pub fn move_to(w: &mut impl Write, x: u16, y: u16) -> Result<()> { Ok(queue!(w, MoveTo(x, y))?) }
|
||||||
|
|
||||||
// FIXME: remove this function
|
|
||||||
#[inline]
|
|
||||||
pub fn move_lock<F, T>((x, y): (u16, u16), cb: F) -> Result<T>
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut BufWriter<StderrLock>) -> Result<T>,
|
|
||||||
{
|
|
||||||
let mut buf = BufWriter::new(stderr().lock());
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
use std::{thread, time::Duration};
|
|
||||||
|
|
||||||
use crossterm::cursor::{Hide, Show};
|
|
||||||
queue!(buf, SavePosition, MoveTo(x, y), Show)?;
|
|
||||||
|
|
||||||
// I really don't want to add this,
|
|
||||||
// but on Windows the cursor position will not synchronize in time occasionally
|
|
||||||
buf.flush()?;
|
|
||||||
thread::sleep(Duration::from_millis(1));
|
|
||||||
|
|
||||||
let result = cb(&mut buf);
|
|
||||||
queue!(buf, Hide, RestorePosition)?;
|
|
||||||
buf.flush()?;
|
|
||||||
result
|
|
||||||
}
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
queue!(buf, SavePosition, MoveTo(x, y))?;
|
|
||||||
let result = cb(&mut buf);
|
|
||||||
queue!(buf, RestorePosition)?;
|
|
||||||
buf.flush()?;
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_block() -> Result<()> { Ok(queue!(stderr(), SetCursorStyle::BlinkingBlock)?) }
|
pub fn set_cursor_block() -> Result<()> { Ok(queue!(stderr(), SetCursorStyle::BlinkingBlock)?) }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue