mirror of
https://github.com/sxyazi/yazi.git
synced 2024-12-25 01:31:36 +03:00
feat: support mouse event (#1038)
This commit is contained in:
parent
e4d67121f8
commit
162218c345
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2751,6 +2751,7 @@ version = "0.2.5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"bitflags 2.5.0",
|
||||
"crossterm",
|
||||
"globset",
|
||||
"indexmap",
|
||||
|
@ -53,6 +53,7 @@ impl Chafa {
|
||||
height: lines.len() as u16,
|
||||
};
|
||||
|
||||
Adaptor::Chafa.image_hide()?;
|
||||
Adaptor::shown_store(area);
|
||||
Emulator::move_lock((max.x, max.y), |stderr| {
|
||||
for (i, line) in lines.into_iter().enumerate() {
|
||||
|
@ -14,6 +14,7 @@ yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||
# External dependencies
|
||||
anyhow = "1.0.86"
|
||||
arc-swap = "1.7.1"
|
||||
bitflags = "2.5.0"
|
||||
crossterm = "0.27.0"
|
||||
globset = "0.4.14"
|
||||
indexmap = "2.2.6"
|
||||
|
@ -13,6 +13,7 @@ linemode = "none"
|
||||
show_hidden = false
|
||||
show_symlink = true
|
||||
scrolloff = 5
|
||||
mouse_events = [ "click", "scroll" ]
|
||||
|
||||
[preview]
|
||||
tab_size = 2
|
||||
@ -86,10 +87,8 @@ fetchers = [
|
||||
]
|
||||
preloaders = [
|
||||
# Image
|
||||
{ mime = "image/svg+xml", run = "magick" },
|
||||
{ mime = "image/heic", run = "magick" },
|
||||
{ mime = "image/jxl", run = "magick" },
|
||||
{ mime = "image/*", run = "image" },
|
||||
{ mime = "image/{heic,jxl,svg+xml}", run = "magick" },
|
||||
{ mime = "image/*", run = "image" },
|
||||
# Video
|
||||
{ mime = "video/*", run = "video" },
|
||||
# PDF
|
||||
@ -106,10 +105,8 @@ previewers = [
|
||||
# JSON
|
||||
{ mime = "application/json", run = "json" },
|
||||
# Image
|
||||
{ mime = "image/svg+xml", run = "magick" },
|
||||
{ mime = "image/heic", run = "magick" },
|
||||
{ mime = "image/jxl", run = "magick" },
|
||||
{ mime = "image/*", run = "image" },
|
||||
{ mime = "image/{heic,jxl,svg+xml}", run = "magick" },
|
||||
{ mime = "image/*", run = "image" },
|
||||
# Video
|
||||
{ mime = "video/*", run = "video" },
|
||||
# PDF
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
use super::{ManagerRatio, SortBy};
|
||||
use super::{ManagerRatio, MouseEvents, SortBy};
|
||||
use crate::{validation::check_validation, MERGED_YAZI};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Validate)]
|
||||
@ -21,6 +21,7 @@ pub struct Manager {
|
||||
pub show_hidden: bool,
|
||||
pub show_symlink: bool,
|
||||
pub scrolloff: u8,
|
||||
pub mouse_events: MouseEvents,
|
||||
}
|
||||
|
||||
impl Default for Manager {
|
||||
|
@ -1,7 +1,9 @@
|
||||
mod manager;
|
||||
mod mouse;
|
||||
mod ratio;
|
||||
mod sorting;
|
||||
|
||||
pub use manager::*;
|
||||
pub use mouse::*;
|
||||
pub use ratio::*;
|
||||
pub use sorting::*;
|
||||
|
63
yazi-config/src/manager/mouse.rs
Normal file
63
yazi-config/src/manager/mouse.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use anyhow::{bail, Result};
|
||||
use bitflags::bitflags;
|
||||
use crossterm::event::MouseEventKind;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[serde(try_from = "Vec<String>", into = "Vec<String>")]
|
||||
pub struct MouseEvents: u8 {
|
||||
const CLICK = 0b00001;
|
||||
const SCROLL = 0b00010;
|
||||
const TOUCH = 0b00100;
|
||||
const MOVE = 0b01000;
|
||||
const DRAG = 0b10000;
|
||||
}
|
||||
}
|
||||
|
||||
impl MouseEvents {
|
||||
#[inline]
|
||||
pub const fn draggable(self) -> bool { self.contains(Self::DRAG) }
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<String>> for MouseEvents {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: Vec<String>) -> Result<Self, Self::Error> {
|
||||
value.into_iter().try_fold(Self::empty(), |aac, s| {
|
||||
Ok(match s.as_str() {
|
||||
"click" => aac | Self::CLICK,
|
||||
"scroll" => aac | Self::SCROLL,
|
||||
"touch" => aac | Self::TOUCH,
|
||||
"move" => aac | Self::MOVE,
|
||||
"drag" => aac | Self::DRAG,
|
||||
_ => bail!("Invalid mouse event: {s}"),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MouseEvents> for Vec<String> {
|
||||
fn from(value: MouseEvents) -> Self {
|
||||
let events = [
|
||||
(MouseEvents::CLICK, "click"),
|
||||
(MouseEvents::SCROLL, "scroll"),
|
||||
(MouseEvents::TOUCH, "touch"),
|
||||
(MouseEvents::MOVE, "move"),
|
||||
(MouseEvents::DRAG, "drag"),
|
||||
];
|
||||
events.into_iter().filter(|v| value.contains(v.0)).map(|v| v.1.to_owned()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crossterm::event::MouseEventKind> for MouseEvents {
|
||||
fn from(value: crossterm::event::MouseEventKind) -> Self {
|
||||
match value {
|
||||
MouseEventKind::Down(_) | MouseEventKind::Up(_) => Self::CLICK,
|
||||
MouseEventKind::ScrollDown | MouseEventKind::ScrollUp => Self::SCROLL,
|
||||
MouseEventKind::ScrollLeft | MouseEventKind::ScrollRight => Self::TOUCH,
|
||||
MouseEventKind::Moved => Self::MOVE,
|
||||
MouseEventKind::Drag(_) => Self::DRAG,
|
||||
}
|
||||
}
|
||||
}
|
@ -111,9 +111,10 @@ impl Manager {
|
||||
|(p, pp)| matches!(*op, FilesOp::Deleting(ref parent, ref urls) if *parent == pp && urls.contains(p)),
|
||||
);
|
||||
|
||||
if let Some(f) = tab.history.get_mut(op.url()) {
|
||||
let hovered = f.hovered().filter(|_| f.tracing).map(|h| h.url());
|
||||
_ = f.update(op.into_owned()) && f.repos(hovered);
|
||||
let folder = tab.history.entry(op.url().clone()).or_insert_with(|| Folder::from(op.url()));
|
||||
let hovered = folder.hovered().filter(|_| folder.tracing).map(|h| h.url());
|
||||
if folder.update(op.into_owned()) {
|
||||
folder.repos(hovered);
|
||||
}
|
||||
|
||||
if leave {
|
||||
|
@ -56,6 +56,7 @@ impl App {
|
||||
Event::Seq(cmds, layer) => self.dispatch_seq(cmds, layer),
|
||||
Event::Render => self.dispatch_render(),
|
||||
Event::Key(key) => self.dispatch_key(key),
|
||||
Event::Mouse(mouse) => self.mouse(mouse),
|
||||
Event::Resize => self.resize(()),
|
||||
Event::Paste(str) => self.dispatch_paste(str),
|
||||
Event::Quit(opt) => self.quit(opt),
|
||||
|
@ -1,4 +1,5 @@
|
||||
mod accept_payload;
|
||||
mod mouse;
|
||||
mod notify;
|
||||
mod plugin;
|
||||
mod quit;
|
||||
|
65
yazi-fm/src/app/commands/mouse.rs
Normal file
65
yazi-fm/src/app/commands/mouse.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use crossterm::event::{MouseEvent, MouseEventKind};
|
||||
use mlua::Table;
|
||||
use ratatui::layout::{Position, Rect};
|
||||
use tracing::error;
|
||||
use yazi_config::{LAYOUT, MANAGER};
|
||||
use yazi_plugin::{bindings::Cast, LUA};
|
||||
|
||||
use crate::{app::App, components, lives::Lives};
|
||||
|
||||
pub struct Opt {
|
||||
event: MouseEvent,
|
||||
}
|
||||
|
||||
impl From<MouseEvent> for Opt {
|
||||
fn from(event: MouseEvent) -> Self { Self { event } }
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub(crate) fn mouse(&mut self, opt: impl Into<Opt>) {
|
||||
let event = (opt.into() as Opt).event;
|
||||
|
||||
let layout = LAYOUT.load();
|
||||
let position = Position { x: event.column, y: event.row };
|
||||
|
||||
if matches!(event.kind, MouseEventKind::Moved | MouseEventKind::Drag(_)) {
|
||||
self.mouse_do(crate::Root::mouse, event, None);
|
||||
return;
|
||||
}
|
||||
|
||||
if layout.current.contains(position) {
|
||||
self.mouse_do(components::Current::mouse, event, Some(layout.current));
|
||||
} else if layout.preview.contains(position) {
|
||||
self.mouse_do(components::Preview::mouse, event, Some(layout.preview));
|
||||
} else if layout.parent.contains(position) {
|
||||
self.mouse_do(components::Parent::mouse, event, Some(layout.parent));
|
||||
} else if layout.header.contains(position) {
|
||||
self.mouse_do(components::Header::mouse, event, Some(layout.header));
|
||||
} else if layout.status.contains(position) {
|
||||
self.mouse_do(components::Status::mouse, event, Some(layout.status));
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse_do(
|
||||
&self,
|
||||
f: impl FnOnce(MouseEvent) -> mlua::Result<()>,
|
||||
mut event: MouseEvent,
|
||||
rect: Option<Rect>,
|
||||
) {
|
||||
if matches!(event.kind, MouseEventKind::Down(_) if MANAGER.mouse_events.draggable()) {
|
||||
let evt = yazi_plugin::bindings::MouseEvent::cast(&LUA, event);
|
||||
if let (Ok(evt), Ok(root)) = (evt, LUA.globals().raw_get::<_, Table>("Root")) {
|
||||
root.raw_set("drag_start", evt).ok();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(rect) = rect {
|
||||
event.row -= rect.y;
|
||||
event.column -= rect.x;
|
||||
}
|
||||
|
||||
if let Err(e) = Lives::scope(&self.cx, move |_| f(event)) {
|
||||
error!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
23
yazi-fm/src/components/current.rs
Normal file
23
yazi-fm/src/components/current.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use crossterm::event::MouseEventKind;
|
||||
use mlua::{Table, TableExt};
|
||||
use yazi_plugin::{bindings::{Cast, MouseEvent}, LUA};
|
||||
|
||||
pub(crate) struct Current;
|
||||
|
||||
impl Current {
|
||||
pub fn mouse(event: crossterm::event::MouseEvent) -> mlua::Result<()> {
|
||||
let evt = MouseEvent::cast(&LUA, event)?;
|
||||
let comp: Table = LUA.globals().raw_get("Current")?;
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => comp.call_method("click", (evt, false))?,
|
||||
MouseEventKind::Up(_) => comp.call_method("click", (evt, true))?,
|
||||
MouseEventKind::ScrollDown => comp.call_method("scroll", (evt, 1))?,
|
||||
MouseEventKind::ScrollUp => comp.call_method("scroll", (evt, -1))?,
|
||||
MouseEventKind::ScrollRight => comp.call_method("touch", (evt, 1))?,
|
||||
MouseEventKind::ScrollLeft => comp.call_method("touch", (evt, -1))?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
use crossterm::event::MouseEventKind;
|
||||
use mlua::{Table, TableExt};
|
||||
use ratatui::{buffer::Buffer, widgets::Widget};
|
||||
use tracing::error;
|
||||
use yazi_plugin::{bindings::Cast, elements::{render_widgets, Rect}, LUA};
|
||||
use yazi_plugin::{bindings::{Cast, MouseEvent}, elements::{render_widgets, Rect}, LUA};
|
||||
|
||||
pub(crate) struct Header;
|
||||
|
||||
@ -18,3 +19,21 @@ impl Widget for Header {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Header {
|
||||
pub fn mouse(event: crossterm::event::MouseEvent) -> mlua::Result<()> {
|
||||
let evt = MouseEvent::cast(&LUA, event)?;
|
||||
let comp: Table = LUA.globals().raw_get("Header")?;
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => comp.call_method("click", (evt, false))?,
|
||||
MouseEventKind::Up(_) => comp.call_method("click", (evt, true))?,
|
||||
MouseEventKind::ScrollDown => comp.call_method("scroll", (evt, 1))?,
|
||||
MouseEventKind::ScrollUp => comp.call_method("scroll", (evt, -1))?,
|
||||
MouseEventKind::ScrollRight => comp.call_method("touch", (evt, 1))?,
|
||||
MouseEventKind::ScrollLeft => comp.call_method("touch", (evt, -1))?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
mod current;
|
||||
mod header;
|
||||
mod manager;
|
||||
mod parent;
|
||||
mod preview;
|
||||
mod progress;
|
||||
mod status;
|
||||
|
||||
pub(super) use current::*;
|
||||
pub(super) use header::*;
|
||||
pub(super) use manager::*;
|
||||
pub(super) use parent::*;
|
||||
pub(super) use preview::*;
|
||||
pub(super) use progress::*;
|
||||
pub(super) use status::*;
|
||||
|
23
yazi-fm/src/components/parent.rs
Normal file
23
yazi-fm/src/components/parent.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use crossterm::event::MouseEventKind;
|
||||
use mlua::{Table, TableExt};
|
||||
use yazi_plugin::{bindings::{Cast, MouseEvent}, LUA};
|
||||
|
||||
pub(crate) struct Parent;
|
||||
|
||||
impl Parent {
|
||||
pub fn mouse(event: crossterm::event::MouseEvent) -> mlua::Result<()> {
|
||||
let evt = MouseEvent::cast(&LUA, event)?;
|
||||
let comp: Table = LUA.globals().raw_get("Parent")?;
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => comp.call_method("click", (evt, false))?,
|
||||
MouseEventKind::Up(_) => comp.call_method("click", (evt, true))?,
|
||||
MouseEventKind::ScrollDown => comp.call_method("scroll", (evt, 1))?,
|
||||
MouseEventKind::ScrollUp => comp.call_method("scroll", (evt, -1))?,
|
||||
MouseEventKind::ScrollRight => comp.call_method("touch", (evt, 1))?,
|
||||
MouseEventKind::ScrollLeft => comp.call_method("touch", (evt, -1))?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
use crossterm::event::MouseEventKind;
|
||||
use mlua::{Table, TableExt};
|
||||
use ratatui::{buffer::Buffer, widgets::Widget};
|
||||
use yazi_plugin::{bindings::{Cast, MouseEvent}, LUA};
|
||||
|
||||
use crate::Ctx;
|
||||
|
||||
@ -9,6 +12,22 @@ pub(crate) struct Preview<'a> {
|
||||
impl<'a> Preview<'a> {
|
||||
#[inline]
|
||||
pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } }
|
||||
|
||||
pub fn mouse(event: crossterm::event::MouseEvent) -> mlua::Result<()> {
|
||||
let evt = MouseEvent::cast(&LUA, event)?;
|
||||
let comp: Table = LUA.globals().raw_get("Preview")?;
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => comp.call_method("click", (evt, false))?,
|
||||
MouseEventKind::Up(_) => comp.call_method("click", (evt, true))?,
|
||||
MouseEventKind::ScrollDown => comp.call_method("scroll", (evt, 1))?,
|
||||
MouseEventKind::ScrollUp => comp.call_method("scroll", (evt, -1))?,
|
||||
MouseEventKind::ScrollRight => comp.call_method("touch", (evt, 1))?,
|
||||
MouseEventKind::ScrollLeft => comp.call_method("touch", (evt, -1))?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Preview<'_> {
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crossterm::event::MouseEventKind;
|
||||
use mlua::{Table, TableExt};
|
||||
use ratatui::widgets::Widget;
|
||||
use tracing::error;
|
||||
use yazi_plugin::{bindings::Cast, elements::{render_widgets, Rect}, LUA};
|
||||
use yazi_plugin::{bindings::{Cast, MouseEvent}, elements::{render_widgets, Rect}, LUA};
|
||||
|
||||
pub(crate) struct Status;
|
||||
|
||||
@ -18,3 +19,21 @@ impl Widget for Status {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Status {
|
||||
pub fn mouse(event: crossterm::event::MouseEvent) -> mlua::Result<()> {
|
||||
let evt = MouseEvent::cast(&LUA, event)?;
|
||||
let comp: Table = LUA.globals().raw_get("Status")?;
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => comp.call_method("click", (evt, false))?,
|
||||
MouseEventKind::Up(_) => comp.call_method("click", (evt, true))?,
|
||||
MouseEventKind::ScrollDown => comp.call_method("scroll", (evt, 1))?,
|
||||
MouseEventKind::ScrollUp => comp.call_method("scroll", (evt, -1))?,
|
||||
MouseEventKind::ScrollRight => comp.call_method("touch", (evt, 1))?,
|
||||
MouseEventKind::ScrollLeft => comp.call_method("touch", (evt, -1))?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
use crossterm::event::MouseEventKind;
|
||||
use mlua::{Table, TableExt};
|
||||
use ratatui::{buffer::Buffer, layout::{Constraint, Layout, Rect}, widgets::Widget};
|
||||
use yazi_plugin::{bindings::{Cast, MouseEvent}, LUA};
|
||||
|
||||
use super::{completion, input, select, tasks, which};
|
||||
use crate::{components, help, Ctx};
|
||||
@ -47,3 +50,17 @@ impl<'a> Widget for Root<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Root<'_> {
|
||||
pub(super) fn mouse(event: crossterm::event::MouseEvent) -> mlua::Result<()> {
|
||||
let evt = MouseEvent::cast(&LUA, event)?;
|
||||
let comp: Table = LUA.globals().raw_get("Root")?;
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Moved => comp.call_method("move", evt)?,
|
||||
MouseEventKind::Drag(_) => comp.call_method("drag", evt)?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use crossterm::event::{Event as CrosstermEvent, EventStream, KeyEvent, KeyEventK
|
||||
use futures::StreamExt;
|
||||
use tokio::{select, task::JoinHandle};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use yazi_config::MANAGER;
|
||||
use yazi_shared::event::Event;
|
||||
|
||||
pub(super) struct Signals {
|
||||
@ -71,6 +72,11 @@ impl Signals {
|
||||
Some(Ok(event)) = reader.next() => {
|
||||
match event {
|
||||
CrosstermEvent::Key(key @ KeyEvent { kind: KeyEventKind::Press, .. }) => Event::Key(key).emit(),
|
||||
CrosstermEvent::Mouse(mouse) => {
|
||||
if MANAGER.mouse_events.contains(mouse.kind.into()) {
|
||||
Event::Mouse(mouse).emit();
|
||||
}
|
||||
},
|
||||
CrosstermEvent::Paste(str) => Event::Paste(str).emit(),
|
||||
CrosstermEvent::Resize(..) => Event::Resize.emit(),
|
||||
_ => {},
|
||||
|
@ -42,3 +42,18 @@ function Current:render(area)
|
||||
Folder:markers(area, markers),
|
||||
}
|
||||
end
|
||||
|
||||
function Current:click(event, up)
|
||||
if up or not event.is_left then
|
||||
return
|
||||
end
|
||||
|
||||
local f = Folder:by_kind(Folder.CURRENT)
|
||||
if event.y <= #f.window and f.hovered then
|
||||
ya.manager_emit("arrow", { event.y + f.offset - f.hovered.idx })
|
||||
end
|
||||
end
|
||||
|
||||
function Current:scroll(event, step) ya.manager_emit("arrow", { step }) end
|
||||
|
||||
function Current:touch(event, step) end
|
||||
|
@ -82,3 +82,8 @@ function Folder:by_kind(kind)
|
||||
return cx.active.preview.folder
|
||||
end
|
||||
end
|
||||
|
||||
function Folder:window(kind)
|
||||
local folder = self:by_kind(kind)
|
||||
return folder and folder.window
|
||||
end
|
||||
|
@ -66,3 +66,9 @@ function Header:render(area)
|
||||
ui.Paragraph(area, { right }):align(ui.Paragraph.RIGHT),
|
||||
}
|
||||
end
|
||||
|
||||
function Header:click(event, up) end
|
||||
|
||||
function Header:scroll(event, step) end
|
||||
|
||||
function Header:touch(event, step) end
|
||||
|
@ -26,3 +26,20 @@ function Parent:render(area)
|
||||
Folder:markers(area, markers),
|
||||
}
|
||||
end
|
||||
|
||||
function Parent:click(event, up)
|
||||
if up or not event.is_left then
|
||||
return
|
||||
end
|
||||
|
||||
local window = Folder:window(Folder.PARENT) or {}
|
||||
if window[event.y] then
|
||||
ya.manager_emit("reveal", { window[event.y].url })
|
||||
else
|
||||
ya.manager_emit("leave", {})
|
||||
end
|
||||
end
|
||||
|
||||
function Parent:scroll(event, step) end
|
||||
|
||||
function Parent:touch(event, step) end
|
||||
|
@ -6,3 +6,20 @@ function Preview:render(area)
|
||||
self.area = area
|
||||
return {}
|
||||
end
|
||||
|
||||
function Preview:click(event, up)
|
||||
if up or not event.is_left then
|
||||
return
|
||||
end
|
||||
|
||||
local window = Folder:window(Folder.PREVIEW) or {}
|
||||
if window[event.y] then
|
||||
ya.manager_emit("reveal", { window[event.y].url })
|
||||
else
|
||||
ya.manager_emit("enter", {})
|
||||
end
|
||||
end
|
||||
|
||||
function Preview:scroll(event, step) ya.manager_emit("seek", { step }) end
|
||||
|
||||
function Preview:touch(event, step) end
|
||||
|
7
yazi-plugin/preset/components/root.lua
Normal file
7
yazi-plugin/preset/components/root.lua
Normal file
@ -0,0 +1,7 @@
|
||||
Root = {
|
||||
drag_start = ui.Rect.default,
|
||||
}
|
||||
|
||||
function Root:move(event) end
|
||||
|
||||
function Root:drag(event) end
|
@ -121,3 +121,9 @@ function Status:render(area)
|
||||
table.unpack(Progress:render(area, right:width())),
|
||||
}
|
||||
end
|
||||
|
||||
function Status:click(event, up) end
|
||||
|
||||
function Status:scroll(event, step) end
|
||||
|
||||
function Status:touch(event, step) end
|
||||
|
@ -5,6 +5,7 @@ mod cha;
|
||||
mod file;
|
||||
mod icon;
|
||||
mod input;
|
||||
mod mouse;
|
||||
mod permit;
|
||||
mod position;
|
||||
mod range;
|
||||
@ -15,6 +16,7 @@ pub use cha::*;
|
||||
pub use file::*;
|
||||
pub use icon::*;
|
||||
pub use input::*;
|
||||
pub use mouse::*;
|
||||
pub use permit::*;
|
||||
pub use position::*;
|
||||
pub use range::*;
|
||||
|
35
yazi-plugin/src/bindings/mouse.rs
Normal file
35
yazi-plugin/src/bindings/mouse.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use crossterm::event::MouseButton;
|
||||
use mlua::{AnyUserData, Lua, UserDataFields};
|
||||
|
||||
use super::Cast;
|
||||
|
||||
pub struct MouseEvent;
|
||||
|
||||
impl MouseEvent {
|
||||
pub fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.register_userdata_type::<crossterm::event::MouseEvent>(|reg| {
|
||||
reg.add_field_method_get("x", |_, me| Ok(me.column as u32 + 1));
|
||||
reg.add_field_method_get("y", |_, me| Ok(me.row as u32 + 1));
|
||||
reg.add_field_method_get("is_left", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Left))
|
||||
});
|
||||
reg.add_field_method_get("is_right", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Right))
|
||||
});
|
||||
reg.add_field_method_get("is_middle", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Middle))
|
||||
});
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Cast<crossterm::event::MouseEvent> for MouseEvent {
|
||||
fn cast(lua: &Lua, data: crossterm::event::MouseEvent) -> mlua::Result<AnyUserData> {
|
||||
lua.create_any_userdata(data)
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ fn stage_1(lua: &'static Lua) -> Result<()> {
|
||||
crate::bindings::Cha::register(lua)?;
|
||||
crate::bindings::File::register(lua)?;
|
||||
crate::bindings::Icon::register(lua)?;
|
||||
crate::bindings::MouseEvent::register(lua)?;
|
||||
crate::elements::pour(lua)?;
|
||||
crate::loader::install(lua)?;
|
||||
crate::pubsub::install(lua)?;
|
||||
@ -38,6 +39,7 @@ fn stage_1(lua: &'static Lua) -> Result<()> {
|
||||
lua.load(include_str!("../preset/components/parent.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/components/preview.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/components/progress.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/components/root.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/components/status.lua")).exec()?;
|
||||
|
||||
Ok(())
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{collections::VecDeque, ffi::OsString};
|
||||
|
||||
use crossterm::event::KeyEvent;
|
||||
use crossterm::event::{KeyEvent, MouseEvent};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use super::Cmd;
|
||||
@ -15,6 +15,7 @@ pub enum Event {
|
||||
Seq(VecDeque<Cmd>, Layer),
|
||||
Render,
|
||||
Key(KeyEvent),
|
||||
Mouse(MouseEvent),
|
||||
Resize,
|
||||
Paste(String),
|
||||
Quit(EventQuit),
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{io::{self, stderr, BufWriter, Stderr, Write}, mem, ops::{Deref, DerefMut}, sync::atomic::{AtomicBool, Ordering}};
|
||||
|
||||
use anyhow::Result;
|
||||
use crossterm::{cursor::{RestorePosition, SavePosition}, event::{DisableBracketedPaste, DisableFocusChange, EnableBracketedPaste, EnableFocusChange, 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, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture, KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}, execute, queue, style::Print, terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen, SetTitle, WindowSize}};
|
||||
use ratatui::{backend::CrosstermBackend, buffer::Buffer, layout::Rect, CompletedFrame, Frame, Terminal};
|
||||
|
||||
static CSI_U: AtomicBool = AtomicBool::new(false);
|
||||
@ -25,7 +25,7 @@ impl Term {
|
||||
BufWriter::new(stderr()),
|
||||
EnterAlternateScreen,
|
||||
EnableBracketedPaste,
|
||||
EnableFocusChange,
|
||||
EnableMouseCapture,
|
||||
SavePosition,
|
||||
Print("\x1b[?u\x1b[c"),
|
||||
RestorePosition
|
||||
@ -56,7 +56,7 @@ impl Term {
|
||||
|
||||
execute!(
|
||||
stderr(),
|
||||
DisableFocusChange,
|
||||
DisableMouseCapture,
|
||||
DisableBracketedPaste,
|
||||
LeaveAlternateScreen,
|
||||
crossterm::cursor::SetCursorStyle::DefaultUserShape
|
||||
@ -74,7 +74,7 @@ impl Term {
|
||||
execute!(
|
||||
stderr(),
|
||||
SetTitle(""),
|
||||
DisableFocusChange,
|
||||
DisableMouseCapture,
|
||||
DisableBracketedPaste,
|
||||
LeaveAlternateScreen,
|
||||
crossterm::cursor::SetCursorStyle::DefaultUserShape,
|
||||
|
Loading…
Reference in New Issue
Block a user