mirror of
https://github.com/sxyazi/yazi.git
synced 2024-11-23 17:32:50 +03:00
feat: support completely disabling mouse with mouse_events=[]
; add new cursor_blink
to control cursor style of input components (#1139)
This commit is contained in:
parent
94628cad9e
commit
1166f86523
@ -1 +1 @@
|
||||
{"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit"],"version":"0.2","flagWords":[],"language":"en"}
|
||||
{"version":"0.2","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt"],"language":"en","flagWords":[]}
|
@ -2,9 +2,9 @@ use std::{io::Write, path::Path, process::Stdio};
|
||||
|
||||
use ansi_to_tui::IntoText;
|
||||
use anyhow::{bail, Result};
|
||||
use crossterm::{cursor::MoveTo, queue};
|
||||
use ratatui::layout::Rect;
|
||||
use tokio::process::Command;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use crate::{Adaptor, Emulator};
|
||||
|
||||
@ -58,7 +58,7 @@ impl Chafa {
|
||||
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)?;
|
||||
queue!(stderr, MoveTo(max.x, max.y + i as u16 + 1))?;
|
||||
}
|
||||
Ok(area)
|
||||
})
|
||||
@ -68,7 +68,7 @@ impl Chafa {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |stderr| {
|
||||
for y in area.top()..area.bottom() {
|
||||
Term::move_to(stderr, area.x, y)?;
|
||||
queue!(stderr, MoveTo(area.x, y))?;
|
||||
write!(stderr, "{s}")?;
|
||||
}
|
||||
Ok(())
|
||||
|
35
yazi-adaptor/src/dimension.rs
Normal file
35
yazi-adaptor/src/dimension.rs
Normal file
@ -0,0 +1,35 @@
|
||||
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(s) = crossterm::terminal::size() {
|
||||
size.columns = s.0;
|
||||
size.rows = s.1;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)))
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
use std::{env, io::{stderr, LineWriter}};
|
||||
use std::{env, io::{stderr, LineWriter}, time::Duration};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use crossterm::{cursor::{RestorePosition, SavePosition}, execute, style::Print, terminal::{disable_raw_mode, enable_raw_mode}};
|
||||
use scopeguard::defer;
|
||||
use tracing::warn;
|
||||
use yazi_shared::{env_exists, term::Term};
|
||||
use tokio::{io::{AsyncReadExt, BufReader}, time::timeout};
|
||||
use tracing::{error, warn};
|
||||
use yazi_shared::env_exists;
|
||||
|
||||
use crate::{Adaptor, CLOSE, ESCAPE, START, TMUX};
|
||||
|
||||
@ -129,7 +130,7 @@ impl Emulator {
|
||||
RestorePosition
|
||||
)?;
|
||||
|
||||
let resp = futures::executor::block_on(Term::read_until_da1())?;
|
||||
let resp = futures::executor::block_on(Self::read_until_da1())?;
|
||||
let names = [
|
||||
("kitty", Self::Kitty),
|
||||
("Konsole", Self::Konsole),
|
||||
@ -187,4 +188,29 @@ impl Emulator {
|
||||
buf.flush()?;
|
||||
result
|
||||
}
|
||||
|
||||
pub async fn read_until_da1() -> Result<String> {
|
||||
let read = async {
|
||||
let mut stdin = BufReader::new(tokio::io::stdin());
|
||||
let mut buf = String::with_capacity(200);
|
||||
loop {
|
||||
let mut c = [0; 1];
|
||||
if stdin.read(&mut c).await? == 0 {
|
||||
bail!("unexpected EOF");
|
||||
}
|
||||
buf.push(c[0] as char);
|
||||
if c[0] == b'c' && buf.contains("\x1b[?") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(buf)
|
||||
};
|
||||
|
||||
let timeout = timeout(Duration::from_secs(10), read).await;
|
||||
if let Err(ref e) = timeout {
|
||||
error!("read_until_da1: {e:?}");
|
||||
}
|
||||
|
||||
timeout?
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ use exif::{In, Tag};
|
||||
use image::{codecs::jpeg::JpegEncoder, imageops::{self, FilterType}, io::Limits, DynamicImage};
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_config::{PREVIEW, TASKS};
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use crate::Dimension;
|
||||
|
||||
pub struct Image;
|
||||
|
||||
@ -77,7 +78,7 @@ impl Image {
|
||||
}
|
||||
|
||||
pub(super) fn max_pixel(rect: Rect) -> (u32, u32) {
|
||||
Term::ratio()
|
||||
Dimension::ratio()
|
||||
.map(|(r1, r2)| {
|
||||
let (w, h) = ((rect.width as f64 * r1) as u32, (rect.height as f64 * r2) as u32);
|
||||
(w.min(PREVIEW.max_width), h.min(PREVIEW.max_height))
|
||||
@ -86,7 +87,7 @@ impl Image {
|
||||
}
|
||||
|
||||
pub(super) fn pixel_area(size: (u32, u32), rect: Rect) -> Rect {
|
||||
Term::ratio()
|
||||
Dimension::ratio()
|
||||
.map(|(r1, r2)| Rect {
|
||||
x: rect.x,
|
||||
y: rect.y,
|
||||
|
@ -2,9 +2,9 @@ use std::{io::Write, path::Path};
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{engine::{general_purpose::STANDARD, Config}, Engine};
|
||||
use crossterm::{cursor::MoveTo, queue};
|
||||
use image::{codecs::jpeg::JpegEncoder, DynamicImage};
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use super::image::Image;
|
||||
use crate::{adaptor::Adaptor, Emulator, CLOSE, START};
|
||||
@ -29,7 +29,7 @@ impl Iterm2 {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |stderr| {
|
||||
for y in area.top()..area.bottom() {
|
||||
Term::move_to(stderr, area.x, y)?;
|
||||
queue!(stderr, MoveTo(area.x, y))?;
|
||||
write!(stderr, "{s}")?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -3,9 +3,9 @@ use std::{io::Write, path::Path};
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use crossterm::{cursor::MoveTo, queue};
|
||||
use image::DynamicImage;
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use super::image::Image;
|
||||
use crate::{adaptor::Adaptor, Emulator, CLOSE, ESCAPE, START};
|
||||
@ -333,7 +333,7 @@ impl Kitty {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |stderr| {
|
||||
for y in area.top()..area.bottom() {
|
||||
Term::move_to(stderr, area.x, y)?;
|
||||
queue!(stderr, MoveTo(area.x, y))?;
|
||||
write!(stderr, "{s}")?;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
mod adaptor;
|
||||
mod chafa;
|
||||
mod dimension;
|
||||
mod emulator;
|
||||
mod image;
|
||||
mod iterm2;
|
||||
@ -12,6 +13,7 @@ mod ueberzug;
|
||||
|
||||
pub use adaptor::*;
|
||||
use chafa::*;
|
||||
pub use dimension::*;
|
||||
pub use emulator::*;
|
||||
use iterm2::*;
|
||||
use kitty::*;
|
||||
|
@ -2,10 +2,10 @@ use std::{io::Write, path::Path};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use color_quant::NeuQuant;
|
||||
use crossterm::{cursor::MoveTo, queue};
|
||||
use image::DynamicImage;
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_config::PREVIEW;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use crate::{adaptor::Adaptor, Emulator, Image, CLOSE, ESCAPE, START};
|
||||
|
||||
@ -29,7 +29,7 @@ impl Sixel {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |stderr| {
|
||||
for y in area.top()..area.bottom() {
|
||||
Term::move_to(stderr, area.x, y)?;
|
||||
queue!(stderr, MoveTo(area.x, y))?;
|
||||
write!(stderr, "{s}")?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -33,12 +33,12 @@ edit = [
|
||||
{ run = 'code -w "%*"', block = true, desc = "code (block)", for = "windows" },
|
||||
]
|
||||
open = [
|
||||
{ run = 'xdg-open "$@"', desc = "Open", for = "linux" },
|
||||
{ run = 'xdg-open "$1"', desc = "Open", for = "linux" },
|
||||
{ run = 'open "$@"', desc = "Open", for = "macos" },
|
||||
{ run = 'start "" "%1"', orphan = true, desc = "Open", for = "windows" },
|
||||
]
|
||||
reveal = [
|
||||
{ run = 'xdg-open "$(dirname "$0")"', desc = "Reveal", for = "linux" },
|
||||
{ run = 'xdg-open "$(dirname "$1")"', desc = "Reveal", for = "linux" },
|
||||
{ run = 'open -R "$1"', desc = "Reveal", for = "macos" },
|
||||
{ run = 'explorer /select, "%1"', orphan = true, desc = "Reveal", for = "windows" },
|
||||
{ run = '''exiftool "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show EXIF", for = "unix" },
|
||||
@ -122,6 +122,8 @@ previewers = [
|
||||
]
|
||||
|
||||
[input]
|
||||
cursor_blink = true
|
||||
|
||||
# cd
|
||||
cd_title = "Change directory:"
|
||||
cd_origin = "top-center"
|
||||
|
@ -5,6 +5,8 @@ use crate::MERGED_YAZI;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Input {
|
||||
pub cursor_blink: bool,
|
||||
|
||||
// cd
|
||||
pub cd_title: String,
|
||||
pub cd_origin: Origin,
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crossterm::terminal::WindowSize;
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use super::{Offset, Origin};
|
||||
|
||||
@ -14,10 +13,9 @@ impl Position {
|
||||
#[inline]
|
||||
pub fn new(origin: Origin, offset: Offset) -> Self { Self { origin, offset } }
|
||||
|
||||
pub fn rect(&self) -> Rect {
|
||||
pub fn rect(&self, WindowSize { columns, rows, .. }: WindowSize) -> Rect {
|
||||
use Origin::*;
|
||||
let Offset { x, y, width, height } = self.offset;
|
||||
let WindowSize { columns, rows, .. } = Term::size();
|
||||
|
||||
let max_x = columns.saturating_sub(width);
|
||||
let new_x = match self.origin {
|
||||
@ -45,9 +43,8 @@ impl Position {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sticky(base: Rect, offset: Offset) -> Rect {
|
||||
pub fn sticky(WindowSize { columns, rows, .. }: WindowSize, base: Rect, offset: Offset) -> Rect {
|
||||
let Offset { x, y, width, height } = offset;
|
||||
let WindowSize { columns, rows, .. } = Term::size();
|
||||
|
||||
let above =
|
||||
base.y.saturating_add(base.height).saturating_add(height).saturating_add_signed(y) > rows;
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crossterm::event::KeyCode;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use yazi_adaptor::Dimension;
|
||||
use yazi_config::{keymap::{Control, Key}, KEYMAP};
|
||||
use yazi_shared::{render, render_and, term::Term, Layer};
|
||||
use yazi_shared::{render, render_and, Layer};
|
||||
|
||||
use super::HELP_MARGIN;
|
||||
use crate::input::Input;
|
||||
@ -22,7 +23,7 @@ pub struct Help {
|
||||
|
||||
impl Help {
|
||||
#[inline]
|
||||
pub fn limit() -> usize { Term::size().rows.saturating_sub(HELP_MARGIN) as usize }
|
||||
pub fn limit() -> usize { Dimension::available().rows.saturating_sub(HELP_MARGIN) as usize }
|
||||
|
||||
pub fn toggle(&mut self, layer: Layer) {
|
||||
self.visible = !self.visible;
|
||||
@ -106,7 +107,7 @@ impl Help {
|
||||
return None;
|
||||
}
|
||||
if let Some(kw) = self.keyword() {
|
||||
return Some((kw.width() as u16, Term::size().rows));
|
||||
return Some((kw.width() as u16, Dimension::available().rows));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
|
||||
use yazi_config::{OPEN, PREVIEW};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_proxy::{AppProxy, TasksProxy, HIDER, WATCHER};
|
||||
use yazi_shared::{fs::{max_common_root, maybe_exists, File, FilesOp, Url}, term::Term};
|
||||
use yazi_shared::{fs::{max_common_root, maybe_exists, File, FilesOp, Url}, terminal_clear};
|
||||
|
||||
use crate::manager::Manager;
|
||||
|
||||
@ -52,7 +52,7 @@ impl Manager {
|
||||
old: Vec<PathBuf>,
|
||||
new: Vec<PathBuf>,
|
||||
) -> Result<()> {
|
||||
Term::clear(&mut stderr())?;
|
||||
terminal_clear(&mut stderr())?;
|
||||
if old.len() != new.len() {
|
||||
eprintln!("Number of old and new differ, press ENTER to exit");
|
||||
stdin().read_exact(&mut [0]).await?;
|
||||
@ -108,7 +108,7 @@ impl Manager {
|
||||
}
|
||||
|
||||
async fn output_failed(failed: Vec<(PathBuf, PathBuf, anyhow::Error)>) -> Result<()> {
|
||||
Term::clear(&mut stderr())?;
|
||||
terminal_clear(&mut stderr())?;
|
||||
|
||||
{
|
||||
let mut stderr = BufWriter::new(stderr().lock());
|
||||
|
@ -4,7 +4,7 @@ use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
|
||||
use scopeguard::defer;
|
||||
use tokio::{io::{stdin, AsyncReadExt}, select, sync::mpsc, time};
|
||||
use yazi_proxy::{AppProxy, HIDER};
|
||||
use yazi_shared::{event::Cmd, term::Term};
|
||||
use yazi_shared::{event::Cmd, terminal_clear};
|
||||
|
||||
use crate::tasks::Tasks;
|
||||
|
||||
@ -30,7 +30,7 @@ impl Tasks {
|
||||
defer!(AppProxy::resume());
|
||||
AppProxy::stop().await;
|
||||
|
||||
Term::clear(&mut stderr()).ok();
|
||||
terminal_clear(&mut stderr()).ok();
|
||||
BufWriter::new(stderr().lock()).write_all(mem::take(&mut buffered).as_bytes()).ok();
|
||||
|
||||
defer! { disable_raw_mode().ok(); }
|
||||
|
@ -2,8 +2,9 @@ use std::{sync::Arc, time::Duration};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use tokio::{task::JoinHandle, time::sleep};
|
||||
use yazi_adaptor::Dimension;
|
||||
use yazi_scheduler::{Ongoing, Scheduler, TaskSummary};
|
||||
use yazi_shared::{emit, event::Cmd, term::Term, Layer};
|
||||
use yazi_shared::{emit, event::Cmd, Layer};
|
||||
|
||||
use super::{TasksProgress, TASKS_BORDER, TASKS_PADDING, TASKS_PERCENT};
|
||||
|
||||
@ -53,7 +54,8 @@ impl Tasks {
|
||||
|
||||
#[inline]
|
||||
pub fn limit() -> usize {
|
||||
(Term::size().rows * TASKS_PERCENT / 100).saturating_sub(TASKS_BORDER + TASKS_PADDING) as usize
|
||||
(Dimension::available().rows * TASKS_PERCENT / 100).saturating_sub(TASKS_BORDER + TASKS_PADDING)
|
||||
as usize
|
||||
}
|
||||
|
||||
pub fn paginate(&self) -> Vec<TaskSummary> {
|
||||
|
@ -4,9 +4,9 @@ use anyhow::Result;
|
||||
use crossterm::event::KeyEvent;
|
||||
use yazi_config::keymap::Key;
|
||||
use yazi_core::input::InputMode;
|
||||
use yazi_shared::{emit, event::{Cmd, Event, NEED_RENDER}, term::Term, Layer};
|
||||
use yazi_shared::{emit, event::{Cmd, Event, NEED_RENDER}, Layer};
|
||||
|
||||
use crate::{lives::Lives, Ctx, Executor, Router, Signals};
|
||||
use crate::{lives::Lives, Ctx, Executor, Router, Signals, Term};
|
||||
|
||||
pub(crate) struct App {
|
||||
pub(crate) cx: Ctx,
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::ffi::OsString;
|
||||
|
||||
use yazi_boot::ARGS;
|
||||
use yazi_shared::{event::EventQuit, term::Term};
|
||||
use yazi_shared::event::EventQuit;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::{app::App, Term};
|
||||
|
||||
impl App {
|
||||
pub(crate) fn quit(&mut self, opt: EventQuit) -> ! {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use yazi_shared::{event::Cmd, term::Term};
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::{app::App, Term};
|
||||
|
||||
impl App {
|
||||
pub(crate) fn resume(&mut self, _: Cmd) {
|
||||
|
@ -1,12 +1,13 @@
|
||||
use crossterm::terminal::WindowSize;
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_shared::{event::Cmd, term::Term};
|
||||
use yazi_adaptor::Dimension;
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use crate::{app::App, notify};
|
||||
|
||||
impl App {
|
||||
pub(crate) fn update_notify(&mut self, cmd: Cmd) {
|
||||
let WindowSize { rows, columns, .. } = Term::size();
|
||||
let WindowSize { rows, columns, .. } = Dimension::available();
|
||||
let area =
|
||||
notify::Layout::available(Rect { x: 0, y: 0, width: columns, height: rows });
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::path::MAIN_SEPARATOR;
|
||||
|
||||
use ratatui::{buffer::Buffer, layout::Rect, widgets::{Block, BorderType, List, ListItem, Widget}};
|
||||
use yazi_adaptor::Dimension;
|
||||
use yazi_config::{popup::{Offset, Position}, THEME};
|
||||
|
||||
use crate::Ctx;
|
||||
@ -40,7 +41,7 @@ impl<'a> Widget for Completion<'a> {
|
||||
.collect();
|
||||
|
||||
let input_area = self.cx.area(&self.cx.input.position);
|
||||
let mut area = Position::sticky(input_area, Offset {
|
||||
let mut area = Position::sticky(Dimension::available(), input_area, Offset {
|
||||
x: 1,
|
||||
y: 0,
|
||||
width: input_area.width.saturating_sub(2),
|
||||
|
@ -1,4 +1,5 @@
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_adaptor::Dimension;
|
||||
use yazi_config::popup::{Origin, Position};
|
||||
use yazi_core::{completion::Completion, help::Help, input::Input, manager::Manager, notify::Notify, select::Select, tasks::Tasks, which::Which};
|
||||
|
||||
@ -28,16 +29,17 @@ impl Ctx {
|
||||
}
|
||||
|
||||
pub fn area(&self, position: &Position) -> Rect {
|
||||
let ws = Dimension::available();
|
||||
if position.origin != Origin::Hovered {
|
||||
return position.rect();
|
||||
return position.rect(ws);
|
||||
}
|
||||
|
||||
if let Some(r) =
|
||||
self.manager.hovered().and_then(|h| self.manager.current().rect_current(&h.url))
|
||||
{
|
||||
Position::sticky(r, position.offset)
|
||||
Position::sticky(ws, r, position.offset)
|
||||
} else {
|
||||
Position::new(Origin::TopCenter, position.offset).rect()
|
||||
Position::new(Origin::TopCenter, position.offset).rect(ws)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,6 @@ impl<'a> Executor<'a> {
|
||||
on!(open_with);
|
||||
on!(process_exec);
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match cmd.name.as_str() {
|
||||
// Help
|
||||
"help" => self.app.cx.help.toggle(Layer::Tasks),
|
||||
@ -182,7 +181,6 @@ impl<'a> Executor<'a> {
|
||||
on!(close);
|
||||
on!(arrow);
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match cmd.name.as_str() {
|
||||
// Help
|
||||
"help" => self.app.cx.help.toggle(Layer::Select),
|
||||
@ -233,7 +231,6 @@ impl<'a> Executor<'a> {
|
||||
on!(undo);
|
||||
on!(redo);
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match cmd.name.as_str() {
|
||||
// Help
|
||||
"help" => self.app.cx.help.toggle(Layer::Input),
|
||||
@ -262,7 +259,6 @@ impl<'a> Executor<'a> {
|
||||
on!(arrow);
|
||||
on!(filter);
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match cmd.name.as_str() {
|
||||
"close" => self.app.cx.help.toggle(Layer::Help),
|
||||
// Plugin
|
||||
@ -285,7 +281,6 @@ impl<'a> Executor<'a> {
|
||||
on!(close);
|
||||
on!(arrow);
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match cmd.name.as_str() {
|
||||
"close_input" => self.app.cx.input.close(cmd),
|
||||
// Help
|
||||
|
@ -6,9 +6,8 @@ use syntect::easy::HighlightLines;
|
||||
use yazi_config::THEME;
|
||||
use yazi_core::input::InputMode;
|
||||
use yazi_plugin::external::Highlighter;
|
||||
use yazi_shared::term::Term;
|
||||
|
||||
use crate::Ctx;
|
||||
use crate::{Ctx, Term};
|
||||
|
||||
pub(crate) struct Input<'a> {
|
||||
cx: &'a Ctx,
|
||||
|
@ -21,6 +21,7 @@ mod router;
|
||||
mod select;
|
||||
mod signals;
|
||||
mod tasks;
|
||||
mod term;
|
||||
mod which;
|
||||
|
||||
use context::*;
|
||||
@ -31,6 +32,7 @@ use panic::*;
|
||||
use root::*;
|
||||
use router::*;
|
||||
use signals::*;
|
||||
use term::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use yazi_shared::term::Term;
|
||||
use crate::Term;
|
||||
|
||||
pub(super) struct Panic;
|
||||
|
||||
|
@ -1,19 +1,21 @@
|
||||
use std::{io::{self, stderr, BufWriter, Stderr, Write}, mem, ops::{Deref, DerefMut}, sync::atomic::{AtomicBool, Ordering}};
|
||||
use std::{io::{self, stderr, BufWriter, Stderr}, ops::{Deref, DerefMut}, sync::atomic::{AtomicBool, Ordering}};
|
||||
|
||||
use anyhow::Result;
|
||||
use crossterm::{cursor::{RestorePosition, SavePosition}, event::{DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture, KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}, execute, queue, style::Print, terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen, SetTitle, WindowSize}};
|
||||
use crossterm::{cursor::{RestorePosition, SavePosition}, event::{DisableBracketedPaste, EnableBracketedPaste, KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}, execute, queue, style::Print, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, SetTitle}};
|
||||
use ratatui::{backend::CrosstermBackend, buffer::Buffer, layout::Rect, CompletedFrame, Frame, Terminal};
|
||||
use yazi_adaptor::Emulator;
|
||||
use yazi_config::INPUT;
|
||||
|
||||
static CSI_U: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub struct Term {
|
||||
pub(super) struct Term {
|
||||
inner: Terminal<CrosstermBackend<BufWriter<Stderr>>>,
|
||||
last_area: Rect,
|
||||
last_buffer: Buffer,
|
||||
}
|
||||
|
||||
impl Term {
|
||||
pub fn start() -> Result<Self> {
|
||||
pub(super) fn start() -> Result<Self> {
|
||||
let mut term = Self {
|
||||
inner: Terminal::new(CrosstermBackend::new(BufWriter::new(stderr())))?,
|
||||
last_area: Default::default(),
|
||||
@ -25,13 +27,13 @@ impl Term {
|
||||
BufWriter::new(stderr()),
|
||||
EnterAlternateScreen,
|
||||
EnableBracketedPaste,
|
||||
EnableMouseCapture,
|
||||
mouse::SetMouse(true),
|
||||
SavePosition,
|
||||
Print("\x1b[?u\x1b[c"),
|
||||
RestorePosition
|
||||
)?;
|
||||
|
||||
let resp = futures::executor::block_on(Self::read_until_da1());
|
||||
let resp = futures::executor::block_on(Emulator::read_until_da1());
|
||||
if resp.is_ok_and(|s| s.contains("\x1b[?0u")) {
|
||||
queue!(
|
||||
stderr(),
|
||||
@ -56,7 +58,7 @@ impl Term {
|
||||
|
||||
execute!(
|
||||
stderr(),
|
||||
DisableMouseCapture,
|
||||
mouse::SetMouse(false),
|
||||
DisableBracketedPaste,
|
||||
LeaveAlternateScreen,
|
||||
crossterm::cursor::SetCursorStyle::DefaultUserShape
|
||||
@ -66,7 +68,7 @@ impl Term {
|
||||
Ok(disable_raw_mode()?)
|
||||
}
|
||||
|
||||
pub fn goodbye(f: impl FnOnce() -> bool) -> ! {
|
||||
pub(super) fn goodbye(f: impl FnOnce() -> bool) -> ! {
|
||||
if CSI_U.swap(false, Ordering::Relaxed) {
|
||||
execute!(stderr(), PopKeyboardEnhancementFlags).ok();
|
||||
}
|
||||
@ -74,7 +76,7 @@ impl Term {
|
||||
execute!(
|
||||
stderr(),
|
||||
SetTitle(""),
|
||||
DisableMouseCapture,
|
||||
mouse::SetMouse(false),
|
||||
DisableBracketedPaste,
|
||||
LeaveAlternateScreen,
|
||||
crossterm::cursor::SetCursorStyle::DefaultUserShape,
|
||||
@ -87,7 +89,7 @@ impl Term {
|
||||
std::process::exit(f() as i32);
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, f: impl FnOnce(&mut Frame)) -> io::Result<CompletedFrame> {
|
||||
pub(super) fn draw(&mut self, f: impl FnOnce(&mut Frame)) -> io::Result<CompletedFrame> {
|
||||
let last = self.inner.draw(f)?;
|
||||
|
||||
self.last_area = last.area;
|
||||
@ -95,7 +97,7 @@ impl Term {
|
||||
Ok(last)
|
||||
}
|
||||
|
||||
pub fn draw_partial(&mut self, f: impl FnOnce(&mut Frame)) -> io::Result<CompletedFrame> {
|
||||
pub(super) fn draw_partial(&mut self, f: impl FnOnce(&mut Frame)) -> io::Result<CompletedFrame> {
|
||||
self.inner.draw(|frame| {
|
||||
let buffer = frame.buffer_mut();
|
||||
for y in self.last_area.top()..self.last_area.bottom() {
|
||||
@ -111,43 +113,28 @@ impl Term {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn can_partial(&mut self) -> bool {
|
||||
pub(super) fn can_partial(&mut self) -> bool {
|
||||
self.inner.autoresize().is_ok() && self.last_area == self.inner.get_frame().size()
|
||||
}
|
||||
|
||||
pub fn size() -> 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(s) = crossterm::terminal::size() {
|
||||
size.columns = s.0;
|
||||
size.rows = s.1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use `CSI 14 t` to get the actual size of the terminal
|
||||
// if size.width == 0 || size.height == 0 {}
|
||||
|
||||
size
|
||||
#[inline]
|
||||
pub(super) fn set_cursor_block() -> Result<()> {
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
Ok(if INPUT.cursor_blink {
|
||||
queue!(stderr(), SetCursorStyle::BlinkingBlock)?
|
||||
} else {
|
||||
queue!(stderr(), SetCursorStyle::SteadyBlock)?
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ratio() -> Option<(f64, f64)> {
|
||||
let s = Self::size();
|
||||
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)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clear(w: &mut impl Write) -> Result<()> {
|
||||
queue!(w, Clear(ClearType::All))?;
|
||||
writeln!(w)?;
|
||||
Ok(w.flush()?)
|
||||
pub(super) fn set_cursor_bar() -> Result<()> {
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
Ok(if INPUT.cursor_blink {
|
||||
queue!(stderr(), SetCursorStyle::BlinkingBar)?
|
||||
} else {
|
||||
queue!(stderr(), SetCursorStyle::SteadyBar)?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,3 +151,43 @@ impl Deref for Term {
|
||||
impl DerefMut for Term {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
|
||||
}
|
||||
|
||||
// --- Mouse support
|
||||
mod mouse {
|
||||
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
|
||||
use yazi_config::MANAGER;
|
||||
|
||||
pub struct SetMouse(pub bool);
|
||||
|
||||
impl crossterm::Command for SetMouse {
|
||||
fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
|
||||
if MANAGER.mouse_events.is_empty() {
|
||||
Ok(())
|
||||
} else if self.0 {
|
||||
EnableMouseCapture.write_ansi(f)
|
||||
} else {
|
||||
DisableMouseCapture.write_ansi(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> std::io::Result<()> {
|
||||
if MANAGER.mouse_events.is_empty() {
|
||||
Ok(())
|
||||
} else if self.0 {
|
||||
EnableMouseCapture.execute_winapi()
|
||||
} else {
|
||||
DisableMouseCapture.execute_winapi()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn is_ansi_code_supported(&self) -> bool {
|
||||
if self.0 {
|
||||
EnableMouseCapture.is_ansi_code_supported()
|
||||
} else {
|
||||
DisableMouseCapture.is_ansi_code_supported()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use mlua::{FromLua, UserData};
|
||||
use yazi_shared::term::Term;
|
||||
use yazi_adaptor::Dimension;
|
||||
|
||||
#[derive(Debug, Clone, Copy, FromLua)]
|
||||
pub struct Window {
|
||||
@ -11,7 +11,7 @@ pub struct Window {
|
||||
|
||||
impl Default for Window {
|
||||
fn default() -> Self {
|
||||
let ws = Term::size();
|
||||
let ws = Dimension::available();
|
||||
Self { rows: ws.rows, cols: ws.columns, width: ws.width, height: ws.height }
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ mod natsort;
|
||||
mod number;
|
||||
mod os;
|
||||
mod ro_cell;
|
||||
pub mod term;
|
||||
mod terminal;
|
||||
pub mod theme;
|
||||
mod throttle;
|
||||
mod time;
|
||||
@ -30,6 +30,7 @@ pub use number::*;
|
||||
#[cfg(unix)]
|
||||
pub use os::*;
|
||||
pub use ro_cell::*;
|
||||
pub use terminal::*;
|
||||
pub use throttle::*;
|
||||
pub use time::*;
|
||||
pub use translit::*;
|
||||
|
@ -1,34 +0,0 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use tokio::{io::{stdin, AsyncReadExt, BufReader}, time::timeout};
|
||||
use tracing::error;
|
||||
|
||||
use super::Term;
|
||||
|
||||
impl Term {
|
||||
pub async fn read_until_da1() -> Result<String> {
|
||||
let read = async {
|
||||
let mut stdin = BufReader::new(stdin());
|
||||
let mut buf = String::with_capacity(200);
|
||||
loop {
|
||||
let mut c = [0; 1];
|
||||
if stdin.read(&mut c).await? == 0 {
|
||||
bail!("unexpected EOF");
|
||||
}
|
||||
buf.push(c[0] as char);
|
||||
if c[0] == b'c' && buf.contains("\x1b[?") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(buf)
|
||||
};
|
||||
|
||||
let timeout = timeout(Duration::from_secs(10), read).await;
|
||||
if let Err(ref e) = timeout {
|
||||
error!("read_until_da1: {e:?}");
|
||||
}
|
||||
|
||||
timeout?
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
use std::io::{stderr, Write};
|
||||
|
||||
use anyhow::Result;
|
||||
use crossterm::{cursor::{MoveTo, SetCursorStyle}, queue};
|
||||
|
||||
use super::Term;
|
||||
|
||||
impl Term {
|
||||
#[inline]
|
||||
pub fn move_to(w: &mut impl Write, x: u16, y: u16) -> Result<()> { Ok(queue!(w, MoveTo(x, y))?) }
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_block() -> Result<()> { Ok(queue!(stderr(), SetCursorStyle::BlinkingBlock)?) }
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_bar() -> Result<()> { Ok(queue!(stderr(), SetCursorStyle::BlinkingBar)?) }
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
mod csi_u;
|
||||
mod cursor;
|
||||
mod term;
|
||||
|
||||
pub use term::*;
|
10
yazi-shared/src/terminal.rs
Normal file
10
yazi-shared/src/terminal.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use std::io::Write;
|
||||
|
||||
use crossterm::queue;
|
||||
|
||||
#[inline]
|
||||
pub fn terminal_clear(w: &mut impl Write) -> std::io::Result<()> {
|
||||
queue!(w, crossterm::terminal::Clear(crossterm::terminal::ClearType::All))?;
|
||||
writeln!(w)?;
|
||||
w.flush()
|
||||
}
|
Loading…
Reference in New Issue
Block a user