mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 14:51:03 +00:00
feat: Lua API for printing escape sequences to the terminal (#4059)
This commit is contained in:
parent
ab8d634f8e
commit
84a5be0b6a
34 changed files with 245 additions and 191 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
|
@ -375,9 +375,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitvec"
|
name = "bitvec"
|
||||||
version = "1.0.1"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"funty",
|
"funty",
|
||||||
"radium",
|
"radium",
|
||||||
|
|
@ -519,9 +519,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.11.1"
|
version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "castaway"
|
name = "castaway"
|
||||||
|
|
@ -1393,9 +1393,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
"version_check",
|
"version_check",
|
||||||
|
|
@ -1407,7 +1407,7 @@ version = "1.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2e55f16dcf0e9c00efbe2e655ffe45fc98e7066b52bc92f8a79e64060a79351"
|
checksum = "c2e55f16dcf0e9c00efbe2e655ffe45fc98e7066b52bc92f8a79e64060a79351"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.9",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","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","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","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","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","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg","foldhash","tilded","futs","chdir","hashbrown","JEMALLOC","RUSTFLAGS","RDONLY","GETPATH","fcntl","casefold","inodes","Splatable","casefied","thiserror","memchr","memmem","russh","deadpool","keepalive","nodelay","publickey","deadpool","initing","treelize","TOCTOU","fellback","watchee","Textlike","sstr","pointee","writef","wakeup","nonblocking","sigwinch","timespec","termios","tcgetattr","tcsetattr","tcgetwinsize","rustix","codepoint","codepoints","Raterm","mimetypes","Mimelist","renderables","redrawer"],"language":"en","version":"0.2","flagWords":[]}
|
{"flagWords":[],"version":"0.2","language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","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","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","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","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","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg","foldhash","tilded","futs","chdir","hashbrown","JEMALLOC","RUSTFLAGS","RDONLY","GETPATH","fcntl","casefold","inodes","Splatable","casefied","thiserror","memchr","memmem","russh","deadpool","keepalive","nodelay","publickey","deadpool","initing","treelize","TOCTOU","fellback","watchee","Textlike","sstr","pointee","writef","wakeup","nonblocking","sigwinch","timespec","termios","tcgetattr","tcsetattr","tcgetwinsize","rustix","codepoint","codepoints","Raterm","mimetypes","Mimelist","renderables","redrawer","Padable"]}
|
||||||
|
|
@ -25,7 +25,7 @@ impl Actor for Close {
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(guard);
|
drop(guard);
|
||||||
cx.input.main_visible = false;
|
cx.input.main.visible = false;
|
||||||
|
|
||||||
act!(cmp:close, cx)?;
|
act!(cmp:close, cx)?;
|
||||||
succ!(render!());
|
succ!(render!());
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ratatui_widgets::block::Padding;
|
use ratatui_core::layout::Margin;
|
||||||
use yazi_config::{THEME, YAZI};
|
use yazi_config::{THEME, YAZI};
|
||||||
use yazi_macro::{act, render, succ};
|
use yazi_macro::{act, render, succ};
|
||||||
use yazi_parser::input::ShowForm;
|
use yazi_parser::input::ShowForm;
|
||||||
|
|
@ -17,15 +19,16 @@ impl Actor for Show {
|
||||||
fn act(cx: &mut Ctx, Self::Form { mut opt }: Self::Form) -> Result<Data> {
|
fn act(cx: &mut Ctx, Self::Form { mut opt }: Self::Form) -> Result<Data> {
|
||||||
act!(input:close, cx)?;
|
act!(input:close, cx)?;
|
||||||
|
|
||||||
|
let area = cx.mgr.area(opt.position);
|
||||||
let input = &mut cx.input;
|
let input = &mut cx.input;
|
||||||
input.main_visible = true;
|
input.main.visible = true;
|
||||||
input.main_title = opt.title.clone();
|
input.main.title = opt.title.clone();
|
||||||
input.main_position = opt.position;
|
input.main.position = opt.position;
|
||||||
|
|
||||||
opt.styles = (&THEME.input).into();
|
opt.styles = (&THEME.input).into();
|
||||||
opt.blinking = YAZI.input.cursor_blink;
|
opt.blinking = YAZI.input.cursor_blink;
|
||||||
opt.position = opt.position.padding(Padding::uniform(1));
|
*input.main.deref_mut() = yazi_widgets::input::Input::new(opt)?;
|
||||||
input.main = yazi_widgets::input::Input::new(opt)?;
|
input.main.repos(area.inner(Margin::new(1, 1)));
|
||||||
|
|
||||||
succ!(render!());
|
succ!(render!());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,20 @@
|
||||||
use std::{ops::Deref, sync::Arc};
|
use std::ops::Deref;
|
||||||
|
|
||||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||||
use parking_lot::Mutex;
|
|
||||||
use yazi_shim::mlua::UserDataFieldsExt;
|
use yazi_shim::mlua::UserDataFieldsExt;
|
||||||
|
|
||||||
use super::{Lives, PtrCell};
|
use super::{Lives, PtrCell};
|
||||||
|
|
||||||
pub(super) struct InputAlt(PtrCell<Arc<Mutex<yazi_widgets::input::Input>>>);
|
pub(super) struct InputAlt(PtrCell<yazi_core::input::InputAlt>);
|
||||||
|
|
||||||
impl Deref for InputAlt {
|
impl Deref for InputAlt {
|
||||||
type Target = Arc<Mutex<yazi_widgets::input::Input>>;
|
type Target = yazi_core::input::InputAlt;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target { &self.0 }
|
fn deref(&self) -> &Self::Target { &self.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputAlt {
|
impl InputAlt {
|
||||||
pub(super) fn make(inner: &Arc<Mutex<yazi_widgets::input::Input>>) -> mlua::Result<AnyUserData> {
|
pub(super) fn make(inner: &yazi_core::input::InputAlt) -> mlua::Result<AnyUserData> {
|
||||||
Lives::scoped_userdata(Self(inner.into()))
|
Lives::scoped_userdata(Self(inner.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, Value};
|
use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, Value};
|
||||||
|
use yazi_shim::ratatui::Padable;
|
||||||
|
|
||||||
use super::{Pos, Rect};
|
use super::Rect;
|
||||||
use crate::position::Position;
|
use crate::position::Position;
|
||||||
|
|
||||||
const EXPECTED: &str = "expected a Pos or Rect";
|
const EXPECTED: &str = "expected a Pos or Rect";
|
||||||
|
|
@ -10,7 +11,7 @@ const EXPECTED: &str = "expected a Pos or Rect";
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Area {
|
pub enum Area {
|
||||||
Rect(Rect),
|
Rect(Rect),
|
||||||
Pos(Pos),
|
Pos(Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Area {
|
impl Default for Area {
|
||||||
|
|
@ -26,6 +27,15 @@ impl Debug for Area {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Area> for Position {
|
||||||
|
fn from(value: Area) -> Self {
|
||||||
|
match value {
|
||||||
|
Area::Rect(rect) => Self::from(*rect),
|
||||||
|
Area::Pos(pos) => pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Area {
|
impl Area {
|
||||||
pub fn size(self) -> ratatui_core::layout::Size {
|
pub fn size(self) -> ratatui_core::layout::Size {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -34,13 +44,10 @@ impl Area {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(self, padding: ratatui_widgets::block::Padding) -> Self {
|
pub fn padding(self, padding: ratatui_widgets::block::Padding) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Rect(rect) => Self::Rect(rect.pad(padding.into())),
|
Self::Rect(rect) => Self::Rect(rect.padding(padding).into()),
|
||||||
Self::Pos(mut pos) => {
|
Self::Pos(pos) => Self::Pos(pos.padding(padding)),
|
||||||
pos.pad += padding;
|
|
||||||
Self::Pos(pos)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,7 +57,7 @@ impl Area {
|
||||||
) -> ratatui_core::layout::Rect {
|
) -> ratatui_core::layout::Rect {
|
||||||
match self {
|
match self {
|
||||||
Self::Rect(rect) => *rect,
|
Self::Rect(rect) => *rect,
|
||||||
Self::Pos(pos) => *Rect(f(*pos)).pad(pos.pad),
|
Self::Pos(pos) => f(pos),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +80,7 @@ impl TryFrom<&AnyUserData> for Area {
|
||||||
fn try_from(value: &AnyUserData) -> Result<Self, Self::Error> {
|
fn try_from(value: &AnyUserData) -> Result<Self, Self::Error> {
|
||||||
Ok(if let Ok(rect) = value.borrow::<Rect>() {
|
Ok(if let Ok(rect) = value.borrow::<Rect>() {
|
||||||
Self::Rect(*rect)
|
Self::Rect(*rect)
|
||||||
} else if let Ok(pos) = value.borrow::<Pos>() {
|
} else if let Ok(pos) = value.borrow::<Position>() {
|
||||||
Self::Pos(*pos)
|
Self::Pos(*pos)
|
||||||
} else {
|
} else {
|
||||||
return Err(EXPECTED.into_lua_err());
|
return Err(EXPECTED.into_lua_err());
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
yazi_macro::mod_flat!(align area bar border cell color constraint edge fill gauge layout line list pad pos rect row span spatial table text wrap);
|
yazi_macro::mod_flat!(align area bar border cell color constraint edge fill gauge layout line list pad rect row span spatial table text wrap);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,11 @@ impl Deref for Pad {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ratatui_widgets::block::Padding> for Pad {
|
impl From<ratatui_widgets::block::Padding> for Pad {
|
||||||
fn from(pad: ratatui_widgets::block::Padding) -> Self { Self(pad) }
|
fn from(value: ratatui_widgets::block::Padding) -> Self { Self(value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Pad> for ratatui_widgets::block::Padding {
|
||||||
|
fn from(value: Pad) -> Self { value.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pad {
|
impl Pad {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataFields, UserDataMethods, Value};
|
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataFields, UserDataMethods, Value};
|
||||||
|
use yazi_shim::ratatui::Padable;
|
||||||
|
|
||||||
use super::Pad;
|
use super::Pad;
|
||||||
|
|
||||||
|
|
@ -44,16 +45,6 @@ impl Rect {
|
||||||
rect.into_lua(lua)
|
rect.into_lua(lua)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn pad(self, pad: Pad) -> Self {
|
|
||||||
let mut r = *self;
|
|
||||||
r.x = r.x.saturating_add(pad.left);
|
|
||||||
r.y = r.y.saturating_add(pad.top);
|
|
||||||
|
|
||||||
r.width = r.width.saturating_sub(pad.left + pad.right);
|
|
||||||
r.height = r.height.saturating_sub(pad.top + pad.bottom);
|
|
||||||
Self(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn patch(self, t: Table) -> mlua::Result<Self> {
|
fn patch(self, t: Table) -> mlua::Result<Self> {
|
||||||
Ok(Self(ratatui_core::layout::Rect {
|
Ok(Self(ratatui_core::layout::Rect {
|
||||||
x: t.raw_get::<Option<_>>("x")?.unwrap_or(self.x),
|
x: t.raw_get::<Option<_>>("x")?.unwrap_or(self.x),
|
||||||
|
|
@ -83,7 +74,7 @@ impl UserData for Rect {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||||
methods.add_method("pad", |_, me, pad: Pad| Ok(me.pad(pad)));
|
methods.add_method("pad", |_, me, pad: Pad| Ok(Self(me.padding(pad))));
|
||||||
methods.add_method("contains", |_, me, Self(rect)| Ok(me.contains(rect.into())));
|
methods.add_method("contains", |_, me, Self(rect)| Ok(me.contains(rect.into())));
|
||||||
|
|
||||||
methods.add_meta_method(MetaMethod::Call, |_, me, t: Table| me.patch(t));
|
methods.add_meta_method(MetaMethod::Call, |_, me, t: Table| me.patch(t));
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,13 @@
|
||||||
use std::{ops::Deref, str::FromStr};
|
use std::str::FromStr;
|
||||||
|
|
||||||
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataFields, UserDataMethods, Value};
|
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataFields, UserDataMethods, Value};
|
||||||
use yazi_shim::strum::IntoStr;
|
use yazi_shim::strum::IntoStr;
|
||||||
|
|
||||||
use super::Pad;
|
use crate::{elements::Pad, position::{Offset, Origin, Position}};
|
||||||
use crate::position::{Offset, Origin, Position};
|
|
||||||
|
|
||||||
const EXPECTED: &str = "expected a Pos";
|
const EXPECTED: &str = "expected a Pos";
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
impl TryFrom<&AnyUserData> for Position {
|
||||||
pub struct Pos {
|
|
||||||
inner: Position,
|
|
||||||
|
|
||||||
pub(super) pad: Pad,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Pos {
|
|
||||||
type Target = Position;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target { &self.inner }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Position> for Pos {
|
|
||||||
fn from(value: Position) -> Self { Self { inner: value, ..Default::default() } }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Pos> for Position {
|
|
||||||
fn from(value: Pos) -> Self { value.inner }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<&AnyUserData> for Pos {
|
|
||||||
type Error = mlua::Error;
|
type Error = mlua::Error;
|
||||||
|
|
||||||
fn try_from(ud: &AnyUserData) -> Result<Self, Self::Error> {
|
fn try_from(ud: &AnyUserData) -> Result<Self, Self::Error> {
|
||||||
|
|
@ -37,23 +15,24 @@ impl TryFrom<&AnyUserData> for Pos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Table> for Pos {
|
impl TryFrom<Table> for Position {
|
||||||
type Error = mlua::Error;
|
type Error = mlua::Error;
|
||||||
|
|
||||||
fn try_from(t: Table) -> Result<Self, Self::Error> {
|
fn try_from(t: Table) -> Result<Self, Self::Error> {
|
||||||
Ok(Self::from(Position {
|
Ok(Self::from(Position {
|
||||||
origin: Origin::from_str(&t.raw_get::<mlua::String>(1)?.to_str()?).into_lua_err()?,
|
origin: Origin::from_str(&t.raw_get::<mlua::String>(1)?.to_str()?).into_lua_err()?,
|
||||||
offset: Offset {
|
offset: Offset {
|
||||||
x: t.raw_get("x").unwrap_or_default(),
|
x: t.raw_get("x").unwrap_or_default(),
|
||||||
y: t.raw_get("y").unwrap_or_default(),
|
y: t.raw_get("y").unwrap_or_default(),
|
||||||
width: t.raw_get("w").unwrap_or_default(),
|
width: t.raw_get("w").unwrap_or_default(),
|
||||||
height: t.raw_get("h").unwrap_or_default(),
|
height: t.raw_get("h").unwrap_or_default(),
|
||||||
},
|
},
|
||||||
|
padding: Default::default(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromLua for Pos {
|
impl FromLua for Position {
|
||||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::Table(tbl) => Self::try_from(tbl),
|
Value::Table(tbl) => Self::try_from(tbl),
|
||||||
|
|
@ -63,23 +42,18 @@ impl FromLua for Pos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pos {
|
impl Position {
|
||||||
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
|
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
|
||||||
let new = lua.create_function(|_, (_, t): (Table, Table)| Self::try_from(t))?;
|
let new = lua.create_function(|_, (_, t): (Table, Table)| Self::try_from(t))?;
|
||||||
|
|
||||||
let position = lua.create_table()?;
|
let pos = lua.create_table()?;
|
||||||
position.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?))?;
|
pos.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?))?;
|
||||||
|
|
||||||
position.into_lua(lua)
|
pos.into_lua(lua)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_height(mut self, height: u16) -> Self {
|
|
||||||
self.inner.height = height;
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserData for Pos {
|
impl UserData for Position {
|
||||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||||
// TODO: cache
|
// TODO: cache
|
||||||
fields.add_field_method_get("1", |_, me| Ok(me.origin.into_str()));
|
fields.add_field_method_get("1", |_, me| Ok(me.origin.into_str()));
|
||||||
|
|
@ -91,7 +65,7 @@ impl UserData for Pos {
|
||||||
|
|
||||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||||
methods.add_function("pad", |_, (ud, pad): (AnyUserData, Pad)| {
|
methods.add_function("pad", |_, (ud, pad): (AnyUserData, Pad)| {
|
||||||
ud.borrow_mut::<Self>()?.pad = pad;
|
ud.borrow_mut::<Self>()?.padding = pad.into();
|
||||||
Ok(ud)
|
Ok(ud)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1 +1 @@
|
||||||
yazi_macro::mod_flat!(offset origin position);
|
yazi_macro::mod_flat!(lua offset origin position);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,17 @@ pub struct Offset {
|
||||||
pub height: u16,
|
pub height: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ratatui_core::layout::Rect> for Offset {
|
||||||
|
fn from(value: ratatui_core::layout::Rect) -> Self {
|
||||||
|
Self {
|
||||||
|
x: value.x as i16,
|
||||||
|
y: value.y as i16,
|
||||||
|
width: value.width,
|
||||||
|
height: value.height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<[i16; 4]> for Offset {
|
impl TryFrom<[i16; 4]> for Offset {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
|
@ -32,8 +43,3 @@ impl TryFrom<[i16; 4]> for Offset {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Offset {
|
|
||||||
#[inline]
|
|
||||||
pub fn line() -> Self { Self { x: 0, y: 0, width: u16::MAX, height: 1 } }
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,15 @@ use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use ratatui_core::layout::Rect;
|
use ratatui_core::layout::Rect;
|
||||||
use ratatui_widgets::block::Padding;
|
use ratatui_widgets::block::Padding;
|
||||||
|
use yazi_shim::ratatui::Padable;
|
||||||
|
|
||||||
use super::{Offset, Origin};
|
use super::{Offset, Origin};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub origin: Origin,
|
pub origin: Origin,
|
||||||
pub offset: Offset,
|
pub offset: Offset,
|
||||||
|
pub padding: Padding,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Position {
|
impl Deref for Position {
|
||||||
|
|
@ -21,8 +23,23 @@ impl DerefMut for Position {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.offset }
|
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.offset }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Rect> for Position {
|
||||||
|
fn from(value: Rect) -> Self { Self::new(Origin::TopLeft, value.into()) }
|
||||||
|
}
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
pub const fn new(origin: Origin, offset: Offset) -> Self { Self { origin, offset } }
|
pub const fn new(origin: Origin, offset: Offset) -> Self {
|
||||||
|
Self { origin, offset, padding: Padding::ZERO }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn hovered(offset: Offset) -> Self {
|
||||||
|
Self { origin: Origin::Hovered, offset, padding: Padding::ZERO }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_height(mut self, height: u16) -> Self {
|
||||||
|
self.height = height;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rect(&self, (cols, rows): (u16, u16)) -> Rect {
|
pub fn rect(&self, (cols, rows): (u16, u16)) -> Rect {
|
||||||
use Origin::*;
|
use Origin::*;
|
||||||
|
|
@ -52,10 +69,11 @@ impl Position {
|
||||||
width: width.min(cols.saturating_sub(new_x)),
|
width: width.min(cols.saturating_sub(new_x)),
|
||||||
height: height.min(rows.saturating_sub(new_y)),
|
height: height.min(rows.saturating_sub(new_y)),
|
||||||
}
|
}
|
||||||
|
.padding(self.padding)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sticky((cols, rows): (u16, u16), base: Rect, offset: Offset) -> Rect {
|
pub fn sticky(self, base: Rect, (cols, rows): (u16, u16)) -> Rect {
|
||||||
let Offset { x, y, width, height } = offset;
|
let Offset { x, y, width, height } = self.offset;
|
||||||
|
|
||||||
let above =
|
let above =
|
||||||
base.y.saturating_add(base.height).saturating_add(height).saturating_add_signed(y) > rows;
|
base.y.saturating_add(base.height).saturating_add(height).saturating_add_signed(y) > rows;
|
||||||
|
|
@ -73,31 +91,15 @@ impl Position {
|
||||||
width: width.min(cols.saturating_sub(new_x)),
|
width: width.min(cols.saturating_sub(new_x)),
|
||||||
height: height.min(rows.saturating_sub(new_y)),
|
height: height.min(rows.saturating_sub(new_y)),
|
||||||
}
|
}
|
||||||
|
.padding(self.padding)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn padding(mut self, padding: Padding) -> Self {
|
pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
|
||||||
use Origin::*;
|
let p = padding.into();
|
||||||
let h_reduction = padding.left + padding.right;
|
self.padding.left = self.padding.left.saturating_add(p.left);
|
||||||
let v_reduction = padding.top + padding.bottom;
|
self.padding.right = self.padding.right.saturating_add(p.right);
|
||||||
|
self.padding.top = self.padding.top.saturating_add(p.top);
|
||||||
self.x = self.x.saturating_add_unsigned(padding.left);
|
self.padding.bottom = self.padding.bottom.saturating_add(p.bottom);
|
||||||
self.y = self.y.saturating_add_unsigned(padding.top);
|
|
||||||
|
|
||||||
self.width = self.width.saturating_sub(h_reduction);
|
|
||||||
self.height = self.height.saturating_sub(v_reduction);
|
|
||||||
|
|
||||||
self.x = self.x.saturating_sub_unsigned(match self.origin {
|
|
||||||
TopCenter | BottomCenter | Center => h_reduction / 2,
|
|
||||||
TopRight | BottomRight => h_reduction,
|
|
||||||
_ => 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.y = self.y.saturating_sub_unsigned(match self.origin {
|
|
||||||
BottomLeft | BottomCenter | BottomRight => v_reduction,
|
|
||||||
Center => v_reduction / 2,
|
|
||||||
_ => 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ impl Core {
|
||||||
pub fn cursor(&self) -> Option<(Position, SetCursorStyle)> {
|
pub fn cursor(&self) -> Option<(Position, SetCursorStyle)> {
|
||||||
if let Some(guard) = self.input.lock() {
|
if let Some(guard) = self.input.lock() {
|
||||||
let Rect { x, y, .. } = match &guard {
|
let Rect { x, y, .. } = match &guard {
|
||||||
InputGuard::Main(_) => self.mgr.area(self.input.main_position).inner(Margin::new(1, 1)),
|
InputGuard::Main(_) => self.mgr.area(self.input.position()?).inner(Margin::new(1, 1)),
|
||||||
InputGuard::Alt(alt) => self.mgr.area(alt.pos),
|
InputGuard::Alt(_) => self.mgr.area(self.input.position()?),
|
||||||
};
|
};
|
||||||
return Some((Position { x: x + guard.cursor(), y }, guard.cursor_shape()));
|
return Some((Position { x: x + guard.cursor(), y }, guard.cursor_shape()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,83 @@
|
||||||
use std::sync::Arc;
|
use std::{ops::{Deref, DerefMut}, sync::Arc};
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use yazi_binding::position::Position;
|
use yazi_binding::{elements::Spatial, position::Position};
|
||||||
|
|
||||||
use crate::input::{InputGuard, InputMutGuard};
|
use crate::input::{InputGuard, InputMutGuard};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
pub main: yazi_widgets::input::Input,
|
pub main: InputMain,
|
||||||
pub alt: Option<Arc<Mutex<yazi_widgets::input::Input>>>,
|
pub alt: Option<InputAlt>,
|
||||||
|
|
||||||
pub main_visible: bool,
|
|
||||||
pub main_title: String,
|
|
||||||
pub main_position: Position,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
pub fn focus(&self) -> bool { self.main_visible || self.alt.is_some() }
|
pub fn focus(&self) -> bool { self.main.visible || self.alt.is_some() }
|
||||||
|
|
||||||
|
pub fn position(&self) -> Option<Position> {
|
||||||
|
if self.main.visible {
|
||||||
|
Some(self.main.position)
|
||||||
|
} else if let Some(alt) = &self.alt {
|
||||||
|
Some(alt.position)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lock(&self) -> Option<InputGuard<'_>> {
|
pub fn lock(&self) -> Option<InputGuard<'_>> {
|
||||||
if self.main_visible {
|
if self.main.visible {
|
||||||
Some(InputGuard::Main(&self.main))
|
Some(InputGuard::Main(&self.main.inner))
|
||||||
} else if let Some(alt) = &self.alt {
|
} else if let Some(alt) = &self.alt {
|
||||||
Some(InputGuard::Alt(alt.lock()))
|
Some(InputGuard::Alt(alt.inner.lock()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lock_mut(&mut self) -> Option<InputMutGuard<'_>> {
|
pub fn lock_mut(&mut self) -> Option<InputMutGuard<'_>> {
|
||||||
if self.main_visible {
|
if self.main.visible {
|
||||||
Some(InputMutGuard::Main(&mut self.main))
|
Some(InputMutGuard::Main(&mut self.main.inner))
|
||||||
} else if let Some(alt) = &self.alt {
|
} else if let Some(alt) = &self.alt {
|
||||||
Some(InputMutGuard::Alt(alt.lock()))
|
Some(InputMutGuard::Alt(alt.inner.lock()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- InputMain
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct InputMain {
|
||||||
|
inner: yazi_widgets::input::Input,
|
||||||
|
pub visible: bool,
|
||||||
|
pub title: String,
|
||||||
|
pub position: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for InputMain {
|
||||||
|
type Target = yazi_widgets::input::Input;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target { &self.inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for InputMain {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- InputAlt
|
||||||
|
pub struct InputAlt {
|
||||||
|
inner: Arc<Mutex<yazi_widgets::input::Input>>,
|
||||||
|
position: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for InputAlt {
|
||||||
|
type Target = Arc<Mutex<yazi_widgets::input::Input>>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target { &self.inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&yazi_widgets::input::InputArc> for InputAlt {
|
||||||
|
fn from(value: &yazi_widgets::input::InputArc) -> Self {
|
||||||
|
Self { inner: value.deref().clone(), position: value.area().into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ impl Tab {
|
||||||
pub fn hovered_rect_based(&self, pos: Position) -> Rect {
|
pub fn hovered_rect_based(&self, pos: Position) -> Rect {
|
||||||
let area = TERM.dimension().area();
|
let area = TERM.dimension().area();
|
||||||
if let Some(r) = self.hovered_rect() {
|
if let Some(r) = self.hovered_rect() {
|
||||||
Position::sticky(area, r, pos.offset)
|
pos.sticky(r, area)
|
||||||
} else {
|
} else {
|
||||||
Position::new(Origin::TopCenter, pos.offset).rect(area)
|
Position::new(Origin::TopCenter, pos.offset).rect(area)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,14 @@ impl Widget for Cmp<'_> {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let input_area = self.core.mgr.area(self.core.input.main_position);
|
let input_area = self.core.mgr.area(self.core.input.main.position);
|
||||||
let mut area = Position::sticky(TERM.dimension().area(), input_area, Offset {
|
let mut area = Position::hovered(Offset {
|
||||||
x: 1,
|
x: 1,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: input_area.width.saturating_sub(2),
|
width: input_area.width.saturating_sub(2),
|
||||||
height: items.len() as u16 + 2,
|
height: items.len() as u16 + 2,
|
||||||
});
|
})
|
||||||
|
.sticky(input_area, TERM.dimension().area());
|
||||||
|
|
||||||
if area.y > input_area.y {
|
if area.y > input_area.y {
|
||||||
area.y = area.y.saturating_sub(1);
|
area.y = area.y.saturating_sub(1);
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,13 @@ impl Widget for Input<'_> {
|
||||||
fn render(self, _: Rect, buf: &mut Buffer) {
|
fn render(self, _: Rect, buf: &mut Buffer) {
|
||||||
let input = &self.core.input;
|
let input = &self.core.input;
|
||||||
|
|
||||||
let outer = self.core.mgr.area(input.main_position);
|
let outer = self.core.mgr.area(input.main.position);
|
||||||
yazi_widgets::clear::Clear::default().render(outer, buf);
|
yazi_widgets::clear::Clear::default().render(outer, buf);
|
||||||
|
|
||||||
Block::bordered()
|
Block::bordered()
|
||||||
.border_type(BorderType::Rounded)
|
.border_type(BorderType::Rounded)
|
||||||
.border_style(THEME.input.border.get())
|
.border_style(THEME.input.border.get())
|
||||||
.title(Line::styled(&input.main_title, THEME.input.title.get()))
|
.title(Line::styled(&input.main.title, THEME.input.title.get()))
|
||||||
.render(outer, buf);
|
.render(outer, buf);
|
||||||
|
|
||||||
input.main.render(outer.inner(Margin::new(1, 1)), buf);
|
input.main.render(outer.inner(Margin::new(1, 1)), buf);
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ impl Widget for Root<'_> {
|
||||||
pick::Pick::new(self.core).render(area, buf);
|
pick::Pick::new(self.core).render(area, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.core.input.main_visible {
|
if self.core.input.main.visible {
|
||||||
input::Input::new(self.core).render(area, buf);
|
input::Input::new(self.core).render(area, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use mlua::{IntoLua, Lua, Value};
|
use mlua::{IntoLua, Lua, Value};
|
||||||
use yazi_binding::{Composer, ComposerGet, ComposerSet, elements::{Align, Bar, Border, Color, Constraint, Edge, Fill, Gauge, Layout, Line, List, Pad, Pos, Rect, Row, Span, Table, Text, Wrap}, style::Style};
|
use yazi_binding::{Composer, ComposerGet, ComposerSet, elements::{Align, Bar, Border, Color, Constraint, Edge, Fill, Gauge, Layout, Line, List, Pad, Rect, Row, Span, Table, Text, Wrap}, position::Position, style::Style};
|
||||||
use yazi_config::THEME;
|
use yazi_config::THEME;
|
||||||
use yazi_widgets::{clear::Clear, input::InputArc};
|
use yazi_widgets::{clear::Clear, input::InputArc};
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ pub fn compose() -> Composer<ComposerGet, ComposerSet> {
|
||||||
b"Line" => Line::compose(lua)?,
|
b"Line" => Line::compose(lua)?,
|
||||||
b"List" => List::compose(lua)?,
|
b"List" => List::compose(lua)?,
|
||||||
b"Pad" => Pad::compose(lua)?,
|
b"Pad" => Pad::compose(lua)?,
|
||||||
b"Pos" => Pos::compose(lua)?,
|
b"Pos" => Position::compose(lua)?,
|
||||||
b"Rect" => Rect::compose(lua)?,
|
b"Rect" => Rect::compose(lua)?,
|
||||||
b"Row" => Row::compose(lua)?,
|
b"Row" => Row::compose(lua)?,
|
||||||
b"Span" => Span::compose(lua)?,
|
b"Span" => Span::compose(lua)?,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{str::FromStr, time::Duration};
|
||||||
|
|
||||||
use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value};
|
use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value};
|
||||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
use yazi_binding::{elements::{Line, Pos, Text}, runtime};
|
use yazi_binding::{elements::{Line, Text}, runtime};
|
||||||
use yazi_config::{Platform, keymap::{Chord, ChordArc}, popup::ConfirmCfg};
|
use yazi_config::{Platform, keymap::{Chord, ChordArc}, popup::ConfirmCfg};
|
||||||
use yazi_core::notify::MessageOpt;
|
use yazi_core::notify::MessageOpt;
|
||||||
use yazi_macro::relay;
|
use yazi_macro::relay;
|
||||||
|
|
@ -79,7 +79,7 @@ impl Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = ConfirmProxy::show(ConfirmCfg {
|
let result = ConfirmProxy::show(ConfirmCfg {
|
||||||
position: t.raw_get::<Pos>("pos")?.into(),
|
position: t.raw_get("pos")?,
|
||||||
title: t.raw_get::<Line>("title")?.into(),
|
title: t.raw_get::<Line>("title")?.into(),
|
||||||
body: t.raw_get::<Option<Text>>("body")?.unwrap_or_default().into(),
|
body: t.raw_get::<Option<Text>>("body")?.unwrap_or_default().into(),
|
||||||
list: Default::default(), // TODO
|
list: Default::default(), // TODO
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ impl Utils {
|
||||||
let mut table = yazi_binding::elements::Table::try_from(&table)?;
|
let mut table = yazi_binding::elements::Table::try_from(&table)?;
|
||||||
|
|
||||||
let area = table.area();
|
let area = table.area();
|
||||||
table.set_area(area.inner(ratatui_widgets::block::Padding::uniform(1)));
|
table.set_area(area.padding(ratatui_widgets::block::Padding::uniform(1)));
|
||||||
|
|
||||||
lock.data = vec![
|
lock.data = vec![
|
||||||
Renderable::Clear(Default::default()).with_area(area),
|
Renderable::Clear(Default::default()).with_area(area),
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
yazi_macro::mod_flat!(line span wrapper);
|
yazi_macro::mod_flat!(line padding span wrapper);
|
||||||
|
|
|
||||||
20
yazi-shim/src/ratatui/padding.rs
Normal file
20
yazi-shim/src/ratatui/padding.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use ratatui_widgets::block::Padding;
|
||||||
|
|
||||||
|
pub trait Padable {
|
||||||
|
fn padding(self, pad: impl Into<Padding>) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Padable for ratatui_core::layout::Rect {
|
||||||
|
fn padding(self, padding: impl Into<Padding>) -> Self {
|
||||||
|
let p = padding.into();
|
||||||
|
let horizontal = p.left.saturating_add(p.right);
|
||||||
|
let vertical = p.top.saturating_add(p.bottom);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
x: self.x.saturating_add(p.left),
|
||||||
|
y: self.y.saturating_add(p.top),
|
||||||
|
width: self.width.saturating_sub(horizontal),
|
||||||
|
height: self.height.saturating_sub(vertical),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,11 @@ impl Tty {
|
||||||
let mut w = self.writer();
|
let mut w = self.writer();
|
||||||
|
|
||||||
let result = match kind {
|
let result = match kind {
|
||||||
|
b"Print" => {
|
||||||
|
write!(w, "{}", t.raw_get::<ByteString>(1)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DnD
|
||||||
b"AgreeDrag" => {
|
b"AgreeDrag" => {
|
||||||
let it = t.raw_get::<Table>("mimes")?.sequence_iter::<ByteString>(lua).flatten();
|
let it = t.raw_get::<Table>("mimes")?.sequence_iter::<ByteString>(lua).flatten();
|
||||||
write!(w, "{}", match &*t.raw_get::<BorrowedBytes>("type")? {
|
write!(w, "{}", match &*t.raw_get::<BorrowedBytes>("type")? {
|
||||||
|
|
@ -48,6 +53,7 @@ impl Tty {
|
||||||
b"move" => write!(w, "{}", FinishDrop::Move),
|
b"move" => write!(w, "{}", FinishDrop::Move),
|
||||||
_ => return Err("invalid FinishDrop type".into_lua_err()),
|
_ => return Err("invalid FinishDrop type".into_lua_err()),
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => return Err("invalid sequence kind".into_lua_err()),
|
_ => return Err("invalid sequence kind".into_lua_err()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ impl Input {
|
||||||
snap.value.replace_range(start..end, &casefied);
|
snap.value.replace_range(start..end, &casefied);
|
||||||
snap.op = InputOp::None;
|
snap.op = InputOp::None;
|
||||||
snap.cursor = range.start;
|
snap.cursor = range.start;
|
||||||
self.snaps.tag(self.pos.width as usize).then(|| self.flush_type());
|
self.snaps.tag(self.size.width as usize).then(|| self.flush_type());
|
||||||
|
|
||||||
act!(r#move, self)?;
|
act!(r#move, self)?;
|
||||||
succ!(render!());
|
succ!(render!());
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ impl Input {
|
||||||
snap.mode = InputMode::Normal;
|
snap.mode = InputMode::Normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.snaps.tag(self.pos.width as usize);
|
self.snaps.tag(self.size.width as usize);
|
||||||
succ!();
|
succ!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ impl Input {
|
||||||
render!(self.handle_op(opt.step.add(&snap.value, snap.cursor), false));
|
render!(self.handle_op(opt.step.add(&snap.value, snap.cursor), false));
|
||||||
let n_cur = self.snap().cursor;
|
let n_cur = self.snap().cursor;
|
||||||
|
|
||||||
let (limit, snap) = (self.pos.width as usize, self.snap_mut());
|
let (limit, snap) = (self.size.width as usize, self.snap_mut());
|
||||||
if snap.value.is_empty() {
|
if snap.value.is_empty() {
|
||||||
succ!(snap.offset = 0);
|
succ!(snap.offset = 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ impl Input {
|
||||||
(Some(_), Some((len, _))) => snap.value.replace_range(start..start + len, &s),
|
(Some(_), Some((len, _))) => snap.value.replace_range(start..start + len, &s),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.snaps.tag(self.pos.width as usize).then(|| self.flush_type());
|
self.snaps.tag(self.size.width as usize).then(|| self.flush_type());
|
||||||
succ!(render!());
|
succ!(render!());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{borrow::Cow, ops::Range};
|
use std::{borrow::Cow, ops::Range};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use yazi_binding::position::Position;
|
use ratatui_core::layout::{Rect, Size};
|
||||||
use yazi_macro::act;
|
use yazi_macro::act;
|
||||||
use yazi_shared::id::Ids;
|
use yazi_shared::id::Ids;
|
||||||
use yazi_shim::path::CROSS_SEPARATOR;
|
use yazi_shim::path::CROSS_SEPARATOR;
|
||||||
|
|
@ -12,7 +12,7 @@ use crate::{CLIPBOARD, input::{InputCallback, InputEvent, InputOpt, InputStyles}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
pub pos: Position,
|
pub size: Size,
|
||||||
pub snaps: InputSnaps,
|
pub snaps: InputSnaps,
|
||||||
pub styles: InputStyles,
|
pub styles: InputStyles,
|
||||||
pub obscure: bool,
|
pub obscure: bool,
|
||||||
|
|
@ -26,10 +26,8 @@ pub struct Input {
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
pub fn new(opt: InputOpt) -> Result<Self> {
|
pub fn new(opt: InputOpt) -> Result<Self> {
|
||||||
let limit = opt.position.width as usize;
|
|
||||||
let mut input = Self {
|
let mut input = Self {
|
||||||
pos: opt.position,
|
snaps: InputSnaps::new(opt.value, opt.obscure),
|
||||||
snaps: InputSnaps::new(opt.value, opt.obscure, limit),
|
|
||||||
styles: opt.styles,
|
styles: opt.styles,
|
||||||
obscure: opt.obscure,
|
obscure: opt.obscure,
|
||||||
blinking: opt.blinking,
|
blinking: opt.blinking,
|
||||||
|
|
@ -48,9 +46,13 @@ impl Input {
|
||||||
Ok(input)
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repos(&mut self, pos: Position) {
|
pub fn repos(&mut self, area: Rect) {
|
||||||
self.pos = pos;
|
let size = area.into();
|
||||||
self.snap_mut().resize(pos.width as usize);
|
|
||||||
|
if self.size != size {
|
||||||
|
self.size = size;
|
||||||
|
self.snap_mut().resize(size.width as usize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn handle_op(&mut self, cursor: usize, include: bool) -> bool {
|
pub(super) fn handle_op(&mut self, cursor: usize, include: bool) -> bool {
|
||||||
|
|
@ -89,7 +91,7 @@ impl Input {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if !matches!(old.op, InputOp::None | InputOp::Select(_)) {
|
if !matches!(old.op, InputOp::None | InputOp::Select(_)) {
|
||||||
self.snaps.tag(self.pos.width as usize).then(|| self.flush_type());
|
self.snaps.tag(self.size.width as usize).then(|| self.flush_type());
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
@ -118,9 +120,9 @@ impl Input {
|
||||||
|
|
||||||
pub fn display(&self) -> Cow<'_, str> {
|
pub fn display(&self) -> Cow<'_, str> {
|
||||||
if self.obscure {
|
if self.obscure {
|
||||||
"•".repeat(self.snap().window(self.pos.width as usize).len()).into()
|
"•".repeat(self.snap().window(self.size.width as usize).len()).into()
|
||||||
} else {
|
} else {
|
||||||
self.snap().slice(self.snap().window(self.pos.width as usize)).into()
|
self.snap().slice(self.snap().window(self.size.width as usize)).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,7 +151,7 @@ impl Input {
|
||||||
let (start, end) =
|
let (start, end) =
|
||||||
if start < snap.cursor { (start, snap.cursor) } else { (snap.cursor + 1, start + 1) };
|
if start < snap.cursor { (start, snap.cursor) } else { (snap.cursor + 1, start + 1) };
|
||||||
|
|
||||||
let win = snap.window(self.pos.width as usize);
|
let win = snap.window(self.size.width as usize);
|
||||||
let Range { start, end } = start.max(win.start)..end.min(win.end);
|
let Range { start, end } = start.max(win.start)..end.min(win.end);
|
||||||
|
|
||||||
let s = snap.width(snap.offset..start);
|
let s = snap.width(snap.offset..start);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,24 @@
|
||||||
use std::sync::Arc;
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
|
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use ratatui_core::widgets::Widget;
|
use ratatui_core::widgets::Widget;
|
||||||
use yazi_binding::{elements::{Area, Spatial}, impl_area_method, position::{Offset, Origin, Position}};
|
use yazi_binding::{elements::{Area, Spatial}, impl_area_method};
|
||||||
|
|
||||||
use crate::input::{Input, InputOpt, InputStyles};
|
use crate::input::{Input, InputOpt, InputStyles};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct InputArc {
|
pub struct InputArc {
|
||||||
pub focus: bool,
|
area: Area,
|
||||||
|
|
||||||
inner: Arc<Mutex<Input>>,
|
inner: Arc<Mutex<Input>>,
|
||||||
|
|
||||||
|
pub focus: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for InputArc {
|
||||||
|
type Target = Arc<Mutex<Input>>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target { &self.inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputArc {
|
impl InputArc {
|
||||||
|
|
@ -47,22 +54,9 @@ impl TryFrom<&AnyUserData> for InputArc {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spatial for InputArc {
|
impl Spatial for InputArc {
|
||||||
fn area(&self) -> Area { self.inner.lock().pos.into() }
|
fn area(&self) -> Area { self.area }
|
||||||
|
|
||||||
fn set_area(&mut self, area: Area) {
|
fn set_area(&mut self, area: Area) { self.area = area; }
|
||||||
self.inner.lock().repos(match area {
|
|
||||||
Area::Rect(rect) => Position {
|
|
||||||
origin: Origin::TopLeft,
|
|
||||||
offset: Offset {
|
|
||||||
x: rect.x as i16,
|
|
||||||
y: rect.y as i16,
|
|
||||||
width: rect.width,
|
|
||||||
height: rect.height,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Area::Pos(pos) => pos.into(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for &InputArc {
|
impl Widget for &InputArc {
|
||||||
|
|
@ -70,7 +64,9 @@ impl Widget for &InputArc {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.inner.lock().render(rect, buf)
|
let mut guard = self.inner.lock();
|
||||||
|
guard.repos(rect);
|
||||||
|
guard.render(rect, buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use mlua::{ExternalError, FromLua, Lua, Table, Value};
|
use mlua::{ExternalError, FromLua, Lua, Table, Value};
|
||||||
use yazi_binding::{elements::Pos, position::Position};
|
use yazi_binding::position::Position;
|
||||||
use yazi_macro::impl_data_any;
|
use yazi_macro::impl_data_any;
|
||||||
|
|
||||||
use crate::input::{InputCallback, InputStyles};
|
use crate::input::{InputCallback, InputStyles};
|
||||||
|
|
@ -48,7 +48,7 @@ impl TryFrom<&Table> for InputOpt {
|
||||||
cursor: None,
|
cursor: None,
|
||||||
obscure: t.raw_get("obscure")?,
|
obscure: t.raw_get("obscure")?,
|
||||||
blinking: false,
|
blinking: false,
|
||||||
position: t.raw_get::<Pos>("pos")?.with_height(3).into(),
|
position: t.raw_get::<Position>("pos").unwrap_or_default().with_height(3),
|
||||||
realtime: t.raw_get("realtime")?,
|
realtime: t.raw_get("realtime")?,
|
||||||
completion: false,
|
completion: false,
|
||||||
cb: None,
|
cb: None,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ pub struct InputSnap {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputSnap {
|
impl InputSnap {
|
||||||
pub(super) fn new(value: String, obscure: bool, limit: usize) -> Self {
|
pub(super) fn new(value: String, obscure: bool) -> Self {
|
||||||
let mut snap = Self {
|
let mut snap = Self {
|
||||||
value,
|
value,
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@ impl InputSnap {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
cursor: usize::MAX,
|
cursor: usize::MAX,
|
||||||
};
|
};
|
||||||
snap.resize(limit);
|
snap.resize(0);
|
||||||
snap
|
snap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,15 @@ impl Default for InputSnaps {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
idx: 0,
|
idx: 0,
|
||||||
versions: vec![InputSnap::new(String::new(), false, 0)],
|
versions: vec![InputSnap::new(String::new(), false)],
|
||||||
current: InputSnap::new(String::new(), false, 0),
|
current: InputSnap::new(String::new(), false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputSnaps {
|
impl InputSnaps {
|
||||||
pub fn new(value: String, obscure: bool, limit: usize) -> Self {
|
pub fn new(value: String, obscure: bool) -> Self {
|
||||||
let current = InputSnap::new(value, obscure, limit);
|
let current = InputSnap::new(value, obscure);
|
||||||
Self { idx: 0, versions: vec![current.clone()], current }
|
Self { idx: 0, versions: vec![current.clone()], current }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue