feat: new fs.expand_url API (#2476)

This commit is contained in:
三咲雅 · Misaki Masa 2025-03-12 14:17:07 +08:00 committed by GitHub
parent faee35fc44
commit abfbd1cd9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 58 additions and 21 deletions

1
Cargo.lock generated
View file

@ -3624,6 +3624,7 @@ dependencies = [
"ratatui",
"serde",
"tokio",
"tracing",
"uzers",
"windows-sys 0.59.0",
"yazi-macro",

View file

@ -31,8 +31,11 @@ impl<'a> Runtime<'a> {
fn args(lua: &Lua) -> mlua::Result<Value> {
Composer::make(lua, 5, |lua, key| {
match key {
b"chooser_file" => ARGS.chooser_file.as_ref().map(Url::from).into_lua(lua)?,
b"entries" => {
lua.create_sequence_from(ARGS.entries.iter().map(Url::from))?.into_lua(lua)?
}
b"cwd_file" => ARGS.cwd_file.as_ref().map(Url::from).into_lua(lua)?,
b"chooser_file" => ARGS.chooser_file.as_ref().map(Url::from).into_lua(lua)?,
_ => return Ok(Value::Nil),
}
.into_lua(lua)

View file

@ -15,6 +15,7 @@ pub fn compose(lua: &Lua) -> mlua::Result<Value> {
b"create" => create(lua)?,
b"remove" => remove(lua)?,
b"read_dir" => read_dir(lua)?,
b"expand_url" => expand_url(lua)?,
b"unique_name" => unique_name(lua)?,
b"partitions" => partitions(lua)?,
_ => return Ok(Value::Nil),
@ -150,6 +151,17 @@ fn read_dir(lua: &Lua) -> mlua::Result<Function> {
})
}
fn expand_url(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|_, value: Value| {
use yazi_fs::expand_path;
Ok(Url::from(match value {
Value::String(s) => expand_path(s.to_str()?.as_ref()),
Value::UserData(ud) => expand_path(&*ud.borrow::<yazi_shared::url::Url>()?),
_ => Err("must be a string or a Url".into_lua_err())?,
}))
})
}
fn unique_name(lua: &Lua) -> mlua::Result<Function> {
lua.create_async_function(|lua, url: UrlRef| async move {
match yazi_fs::unique_name(url.clone(), async { false }).await {

View file

@ -22,6 +22,7 @@ percent-encoding = "2.3.1"
ratatui = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
[target."cfg(unix)".dependencies]
libc = { workspace = true }

View file

@ -1,5 +1,7 @@
use std::{io::{Error, ErrorKind, Read, Write}, time::Duration};
use tracing::error;
pub struct Handle {
#[cfg(unix)]
inner: std::os::fd::RawFd,
@ -32,7 +34,7 @@ impl Read for Handle {
use std::os::{fd::IntoRawFd, unix::io::FromRawFd};
let mut f = unsafe { std::fs::File::from_raw_fd(self.inner) };
let result = f.read(buf);
self.inner = f.into_raw_fd();
_ = f.into_raw_fd();
result
}
#[cfg(windows)]
@ -40,7 +42,7 @@ impl Read for Handle {
use std::os::windows::io::{FromRawHandle, IntoRawHandle};
let mut f = unsafe { std::fs::File::from_raw_handle(self.inner) };
let result = f.read(buf);
self.inner = f.into_raw_handle();
_ = f.into_raw_handle();
result
}
}
@ -75,18 +77,23 @@ impl Write for Handle {
#[cfg(unix)]
impl Handle {
pub(super) fn new(out: bool) -> std::io::Result<Self> {
pub(super) fn new(out: bool) -> Self {
use std::{fs::OpenOptions, os::fd::IntoRawFd};
let fileno = if out { libc::STDOUT_FILENO } else { libc::STDIN_FILENO };
Ok(if unsafe { libc::isatty(fileno) } == 1 {
Self { inner: fileno, close: false }
} else {
Self {
inner: OpenOptions::new().read(!out).write(out).open("/dev/tty")?.into_raw_fd(),
close: true,
use libc::{STDIN_FILENO, STDOUT_FILENO};
let resort = Self { inner: if out { STDOUT_FILENO } else { STDIN_FILENO }, close: false };
if unsafe { libc::isatty(resort.inner) } == 1 {
return resort;
}
match OpenOptions::new().read(!out).write(out).open("/dev/tty") {
Ok(f) => Self { inner: f.into_raw_fd(), close: true },
Err(err) => {
error!("Failed to open /dev/tty, falling back to stdin/stdout: {err}");
resort
}
})
}
}
pub(super) fn poll(&mut self, timeout: Duration) -> std::io::Result<bool> {
@ -121,7 +128,9 @@ impl Handle {
#[cfg(windows)]
impl Handle {
pub(super) fn new(out: bool) -> std::io::Result<Self> {
pub(super) fn new(out: bool) -> Self {
use std::{io::{Error, stdin, stdout}, os::windows::io::AsRawHandle};
use windows_sys::Win32::{Foundation::{GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE}, Globalization::CP_UTF8, Storage::FileSystem::{CreateFileW, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING}, System::Console::GetConsoleOutputCP};
let name: Vec<u16> = if out { "CONOUT$\0" } else { "CONIN$\0" }.encode_utf16().collect();
@ -137,15 +146,25 @@ impl Handle {
)
};
if result == INVALID_HANDLE_VALUE {
Err(std::io::Error::last_os_error())
} else {
Ok(Self {
if result != INVALID_HANDLE_VALUE {
return Self {
inner: result,
close: true,
out_utf8: unsafe { GetConsoleOutputCP() } == CP_UTF8,
incomplete_utf8: Default::default(),
})
};
}
error!(
"Failed to open {}, falling back to stdin/stdout: {}",
if out { "CONOUT$" } else { "CONIN$" },
Error::last_os_error()
);
Self {
inner: if out { stdout().as_raw_handle() } else { stdin().as_raw_handle() },
close: false,
out_utf8: unsafe { GetConsoleOutputCP() } == CP_UTF8,
incomplete_utf8: Default::default(),
}
}

View file

@ -11,9 +11,10 @@ pub struct Tty {
impl Default for Tty {
fn default() -> Self {
let stdin = Handle::new(false).expect("failed to open stdin");
let stdout = Handle::new(true).expect("failed to open stdout");
Self { stdin: Mutex::new(stdin), stdout: Mutex::new(BufWriter::new(stdout)) }
Self {
stdin: Mutex::new(Handle::new(false)),
stdout: Mutex::new(BufWriter::new(Handle::new(true))),
}
}
}