mirror of
https://github.com/sxyazi/yazi.git
synced 2024-09-11 10:26:35 +03: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
@ -41,7 +41,7 @@ https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265
|
||||
| Platform | Protocol | Support |
|
||||
| ----------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
@ -6,7 +6,7 @@ use ratatui::layout::Rect;
|
||||
use tokio::process::Command;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use crate::Adaptor;
|
||||
use crate::{Adaptor, Emulator};
|
||||
|
||||
pub(super) struct Chafa;
|
||||
|
||||
@ -54,7 +54,7 @@ impl Chafa {
|
||||
};
|
||||
|
||||
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() {
|
||||
stderr.write_all(line)?;
|
||||
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<()> {
|
||||
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() {
|
||||
Term::move_to(stderr, area.x, y)?;
|
||||
write!(stderr, "{s}")?;
|
||||
|
@ -155,4 +155,36 @@ impl Emulator {
|
||||
|
||||
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 super::image::Image;
|
||||
use crate::{adaptor::Adaptor, CLOSE, START};
|
||||
use crate::{adaptor::Adaptor, Emulator, CLOSE, START};
|
||||
|
||||
pub(super) struct Iterm2;
|
||||
|
||||
@ -19,7 +19,7 @@ impl Iterm2 {
|
||||
|
||||
Adaptor::Iterm2.image_hide()?;
|
||||
Adaptor::shown_store(area);
|
||||
Term::move_lock((max.x, max.y), |stderr| {
|
||||
Emulator::move_lock((max.x, max.y), |stderr| {
|
||||
stderr.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
@ -27,7 +27,7 @@ impl Iterm2 {
|
||||
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
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() {
|
||||
Term::move_to(stderr, area.x, y)?;
|
||||
write!(stderr, "{s}")?;
|
||||
|
@ -8,7 +8,7 @@ use ratatui::layout::Rect;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use super::image::Image;
|
||||
use crate::{adaptor::Adaptor, CLOSE, ESCAPE, START};
|
||||
use crate::{adaptor::Adaptor, Emulator, CLOSE, ESCAPE, START};
|
||||
|
||||
static DIACRITICS: [char; 297] = [
|
||||
'\u{0305}',
|
||||
@ -322,7 +322,7 @@ impl Kitty {
|
||||
|
||||
Adaptor::Kitty.image_hide()?;
|
||||
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(&b2)?;
|
||||
Ok(area)
|
||||
@ -331,7 +331,7 @@ impl Kitty {
|
||||
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
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() {
|
||||
Term::move_to(stderr, area.x, y)?;
|
||||
write!(stderr, "{s}")?;
|
||||
|
@ -5,10 +5,9 @@ use anyhow::Result;
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use image::DynamicImage;
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use super::image::Image;
|
||||
use crate::{adaptor::Adaptor, CLOSE, ESCAPE, START};
|
||||
use crate::{adaptor::Adaptor, Emulator, CLOSE, ESCAPE, START};
|
||||
|
||||
pub(super) struct KittyOld;
|
||||
|
||||
@ -20,7 +19,7 @@ impl KittyOld {
|
||||
|
||||
Adaptor::KittyOld.image_hide()?;
|
||||
Adaptor::shown_store(area);
|
||||
Term::move_lock((area.x, area.y), |stderr| {
|
||||
Emulator::move_lock((area.x, area.y), |stderr| {
|
||||
stderr.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
|
@ -7,7 +7,7 @@ use ratatui::layout::Rect;
|
||||
use yazi_config::PREVIEW;
|
||||
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;
|
||||
|
||||
@ -19,7 +19,7 @@ impl Sixel {
|
||||
|
||||
Adaptor::Sixel.image_hide()?;
|
||||
Adaptor::shown_store(area);
|
||||
Term::move_lock((area.x, area.y), |stderr| {
|
||||
Emulator::move_lock((area.x, area.y), |stderr| {
|
||||
stderr.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
@ -27,7 +27,7 @@ impl Sixel {
|
||||
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
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() {
|
||||
Term::move_to(stderr, area.x, y)?;
|
||||
write!(stderr, "{s}")?;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::io::{stderr, BufWriter, StderrLock, Write};
|
||||
use std::io::{stderr, Write};
|
||||
|
||||
use anyhow::Result;
|
||||
use crossterm::{cursor::{MoveTo, RestorePosition, SavePosition, SetCursorStyle}, queue};
|
||||
use crossterm::{cursor::{MoveTo, SetCursorStyle}, queue};
|
||||
|
||||
use super::Term;
|
||||
|
||||
@ -9,40 +9,6 @@ impl Term {
|
||||
#[inline]
|
||||
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]
|
||||
pub fn set_cursor_block() -> Result<()> { Ok(queue!(stderr(), SetCursorStyle::BlinkingBlock)?) }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user