mirror of
https://github.com/sxyazi/yazi.git
synced 2026-05-13 08:16:40 +00:00
refactor: pull filesystem calls out into a designated yazi_fs crate (#3013)
This commit is contained in:
parent
1f596a01fc
commit
c2883f1e05
38 changed files with 354 additions and 145 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -3530,6 +3530,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"tracing",
|
||||
"yazi-config",
|
||||
"yazi-fs",
|
||||
"yazi-macro",
|
||||
"yazi-shared",
|
||||
"yazi-term",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use std::{ffi::OsString, mem, path::{MAIN_SEPARATOR_STR, Path, PathBuf}};
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::fs;
|
||||
use yazi_fs::{CWD, expand_path};
|
||||
use yazi_fs::{CWD, expand_path, services::Local};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::cmp::{CmpItem, ShowOpt, TriggerOpt};
|
||||
use yazi_proxy::CmpProxy;
|
||||
|
|
@ -37,7 +36,8 @@ impl Actor for Trigger {
|
|||
|
||||
let ticket = cmp.ticket;
|
||||
tokio::spawn(async move {
|
||||
let mut dir = fs::read_dir(&parent).await?;
|
||||
// TODO: support VFS
|
||||
let mut dir = Local::read_dir(&parent).await?;
|
||||
let mut cache = vec![];
|
||||
|
||||
// "/" is both a directory separator and the root directory per se
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ impl Actor for BulkRename {
|
|||
|
||||
const NAME: &str = "bulk_rename";
|
||||
|
||||
// FIXME: VFS
|
||||
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
||||
let Some(opener) = YAZI.opener.block(YAZI.open.all("bulk-rename.txt", "text/plain")) else {
|
||||
succ!(AppProxy::notify_warn("Bulk rename", "No text opener found"));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use tokio::fs;
|
||||
use yazi_config::popup::{ConfirmCfg, InputCfg};
|
||||
use yazi_fs::{File, FilesOp, maybe_exists, ok_or_not_found, realname};
|
||||
use yazi_fs::{File, FilesOp, maybe_exists, ok_or_not_found, realname, services};
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::mgr::CreateOpt;
|
||||
use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy, WATCHER};
|
||||
|
|
@ -46,15 +45,15 @@ impl Create {
|
|||
let _permit = WATCHER.acquire().await.unwrap();
|
||||
|
||||
if dir {
|
||||
fs::create_dir_all(&new).await?;
|
||||
services::create_dir_all(&new).await?;
|
||||
} else if let Some(real) = realname(&new).await {
|
||||
ok_or_not_found(fs::remove_file(&new).await)?;
|
||||
ok_or_not_found(services::remove_file(&new).await)?;
|
||||
FilesOp::Deleting(parent.clone(), [UrnBuf::from(real)].into()).emit();
|
||||
fs::File::create(&new).await?;
|
||||
services::create(&new).await?;
|
||||
} else {
|
||||
fs::create_dir_all(&parent).await.ok();
|
||||
ok_or_not_found(fs::remove_file(&new).await)?;
|
||||
fs::File::create(&new).await?;
|
||||
services::create_dir_all(&parent).await.ok();
|
||||
ok_or_not_found(services::remove_file(&new).await)?;
|
||||
services::create(&new).await?;
|
||||
}
|
||||
|
||||
if let Ok(f) = File::new(new.clone()).await {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use anyhow::Result;
|
||||
use tokio::fs;
|
||||
use yazi_config::popup::{ConfirmCfg, InputCfg};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp, maybe_exists, ok_or_not_found, paths_to_same_file, realname};
|
||||
use yazi_fs::{File, FilesOp, maybe_exists, ok_or_not_found, paths_to_same_file, realname, services};
|
||||
use yazi_macro::{act, err, succ};
|
||||
use yazi_parser::mgr::RenameOpt;
|
||||
use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy, WATCHER};
|
||||
|
|
@ -66,10 +65,10 @@ impl Rename {
|
|||
let _permit = WATCHER.acquire().await.unwrap();
|
||||
|
||||
let overwritten = realname(&new).await;
|
||||
fs::rename(&old, &new).await?;
|
||||
services::rename(&old, &new).await?;
|
||||
|
||||
if let Some(o) = overwritten {
|
||||
ok_or_not_found(fs::rename(p_new.join(&o), &new).await)?;
|
||||
ok_or_not_found(services::rename(p_new.join(&o), &new).await)?;
|
||||
FilesOp::Deleting(p_new.clone(), [UrnBuf::from(o)].into()).emit();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ repository = "https://github.com/sxyazi/yazi"
|
|||
|
||||
[dependencies]
|
||||
yazi-config = { path = "../yazi-config", version = "25.6.11" }
|
||||
yazi-fs = { path = "../yazi-fs", version = "25.6.11" }
|
||||
yazi-macro = { path = "../yazi-macro", version = "25.6.11" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.6.11" }
|
||||
yazi-term = { path = "../yazi-term", version = "25.6.11" }
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::{env, fmt::Display, path::Path};
|
||||
use std::{env, fmt::Display};
|
||||
|
||||
use anyhow::Result;
|
||||
use ratatui::layout::Rect;
|
||||
use tracing::warn;
|
||||
use yazi_shared::env_exists;
|
||||
use yazi_shared::{env_exists, url::Url};
|
||||
|
||||
use crate::{Emulator, SHOWN, TMUX, drivers};
|
||||
|
||||
|
|
@ -35,18 +35,18 @@ impl Display for Adapter {
|
|||
}
|
||||
|
||||
impl Adapter {
|
||||
pub async fn image_show(self, path: &Path, max: Rect) -> Result<Rect> {
|
||||
pub async fn image_show(self, url: &Url, max: Rect) -> Result<Rect> {
|
||||
if max.is_empty() {
|
||||
return Ok(Rect::default());
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::Kgp => drivers::Kgp::image_show(path, max).await,
|
||||
Self::KgpOld => drivers::KgpOld::image_show(path, max).await,
|
||||
Self::Iip => drivers::Iip::image_show(path, max).await,
|
||||
Self::Sixel => drivers::Sixel::image_show(path, max).await,
|
||||
Self::X11 | Self::Wayland => drivers::Ueberzug::image_show(path, max).await,
|
||||
Self::Chafa => drivers::Chafa::image_show(path, max).await,
|
||||
Self::Kgp => drivers::Kgp::image_show(url, max).await,
|
||||
Self::KgpOld => drivers::KgpOld::image_show(url, max).await,
|
||||
Self::Iip => drivers::Iip::image_show(url, max).await,
|
||||
Self::Sixel => drivers::Sixel::image_show(url, max).await,
|
||||
Self::X11 | Self::Wayland => drivers::Ueberzug::image_show(url, max).await,
|
||||
Self::Chafa => drivers::Chafa::image_show(url, max).await,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{fmt::Write, io::Write as ioWrite, path::Path};
|
||||
use std::{fmt::Write, io::Write as ioWrite};
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{Engine, engine::{Config, general_purpose::STANDARD}};
|
||||
|
|
@ -6,14 +6,15 @@ use crossterm::{cursor::MoveTo, queue};
|
|||
use image::{DynamicImage, ExtendedColorType, ImageEncoder, codecs::{jpeg::JpegEncoder, png::PngEncoder}};
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use crate::{CLOSE, Emulator, Image, START, adapter::Adapter};
|
||||
|
||||
pub(crate) struct Iip;
|
||||
|
||||
impl Iip {
|
||||
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
pub(crate) async fn image_show(url: &Url, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(url, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use core::str;
|
||||
use std::{io::Write, path::Path};
|
||||
use std::io::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{Engine, engine::general_purpose};
|
||||
use crossterm::{cursor::MoveTo, queue};
|
||||
use image::DynamicImage;
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter, image::Image};
|
||||
|
||||
|
|
@ -312,8 +313,8 @@ static DIACRITICS: [char; 297] = [
|
|||
pub(crate) struct Kgp;
|
||||
|
||||
impl Kgp {
|
||||
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
pub(crate) async fn image_show(url: &Url, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(url, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
|
||||
let b1 = Self::encode(img).await?;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use core::str;
|
||||
use std::{io::Write, path::Path};
|
||||
use std::io::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{Engine, engine::general_purpose};
|
||||
use image::DynamicImage;
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_shared::url::Url;
|
||||
use yazi_term::tty::TTY;
|
||||
|
||||
use crate::{CLOSE, ESCAPE, Emulator, Image, START, adapter::Adapter};
|
||||
|
|
@ -12,8 +13,8 @@ use crate::{CLOSE, ESCAPE, Emulator, Image, START, adapter::Adapter};
|
|||
pub(crate) struct KgpOld;
|
||||
|
||||
impl KgpOld {
|
||||
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
pub(crate) async fn image_show(url: &Url, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(url, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{io::Write, path::Path};
|
||||
use std::io::Write;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use crossterm::{cursor::MoveTo, queue};
|
||||
|
|
@ -6,14 +6,15 @@ use image::{DynamicImage, GenericImageView, RgbImage};
|
|||
use palette::{Srgb, cast::ComponentsAs};
|
||||
use quantette::{ColorSlice, PaletteSize, QuantizeOutput, wu::UIntBinner};
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use crate::{CLOSE, ESCAPE, Emulator, Image, START, adapter::Adapter};
|
||||
|
||||
pub(crate) struct Sixel;
|
||||
|
||||
impl Sixel {
|
||||
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
pub(crate) async fn image_show(url: &Url, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(url, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
use std::path::Path;
|
||||
use std::io::BufReader;
|
||||
|
||||
use anyhow::Result;
|
||||
use image::{DynamicImage, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageReader, ImageResult, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, imageops::FilterType, metadata::Orientation};
|
||||
use image::{DynamicImage, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageFormat, ImageReader, ImageResult, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, imageops::FilterType, metadata::Orientation};
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_fs::services;
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use crate::Dimension;
|
||||
|
||||
pub struct Image;
|
||||
|
||||
impl Image {
|
||||
pub async fn precache(path: &Path, cache: &Path) -> Result<()> {
|
||||
let (mut img, orientation, icc) = Self::decode_from(path).await?;
|
||||
pub async fn precache(src: &Url, cache: &Url) -> Result<()> {
|
||||
let (mut img, orientation, icc) = Self::decode_from(src).await?;
|
||||
let (w, h) = Self::flip_size(orientation, (YAZI.preview.max_width, YAZI.preview.max_height));
|
||||
|
||||
let buf = tokio::task::spawn_blocking(move || {
|
||||
|
|
@ -38,11 +40,11 @@ impl Image {
|
|||
})
|
||||
.await??;
|
||||
|
||||
Ok(tokio::fs::write(cache, buf).await?)
|
||||
Ok(services::write(cache, buf).await?)
|
||||
}
|
||||
|
||||
pub(super) async fn downscale(path: &Path, rect: Rect) -> Result<DynamicImage> {
|
||||
let (mut img, orientation, _) = Self::decode_from(path).await?;
|
||||
pub(super) async fn downscale(url: &Url, rect: Rect) -> Result<DynamicImage> {
|
||||
let (mut img, orientation, _) = Self::decode_from(url).await?;
|
||||
let (w, h) = Self::flip_size(orientation, Self::max_pixel(rect));
|
||||
|
||||
// Fast path.
|
||||
|
|
@ -96,7 +98,7 @@ impl Image {
|
|||
}
|
||||
}
|
||||
|
||||
async fn decode_from(path: &Path) -> ImageResult<(DynamicImage, Orientation, Option<Vec<u8>>)> {
|
||||
async fn decode_from(url: &Url) -> ImageResult<(DynamicImage, Orientation, Option<Vec<u8>>)> {
|
||||
let mut limits = Limits::no_limits();
|
||||
if YAZI.tasks.image_alloc > 0 {
|
||||
limits.max_alloc = Some(YAZI.tasks.image_alloc as u64);
|
||||
|
|
@ -108,11 +110,13 @@ impl Image {
|
|||
limits.max_image_height = Some(YAZI.tasks.image_bound[1] as u32);
|
||||
}
|
||||
|
||||
let path = path.to_owned();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut reader = ImageReader::open(path)?;
|
||||
reader.limits(limits);
|
||||
let mut reader = ImageReader::new(BufReader::new(services::open(&url).await?.into_std().await));
|
||||
if let Ok(format) = ImageFormat::from_path(url) {
|
||||
reader.set_format(format);
|
||||
}
|
||||
|
||||
reader.limits(limits);
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut decoder = reader.with_guessed_format()?.into_decoder()?;
|
||||
let orientation = decoder.orientation().unwrap_or(Orientation::NoTransforms);
|
||||
let icc = decoder.icc_profile().unwrap_or_default();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ impl Deref for Url {
|
|||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl AsRef<yazi_shared::url::Url> for Url {
|
||||
fn as_ref(&self) -> &yazi_shared::url::Url { &self.inner }
|
||||
}
|
||||
|
||||
// FIXME: remove
|
||||
impl AsRef<Path> for Url {
|
||||
fn as_ref(&self) -> &Path { self.inner.as_path() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use anyhow::{Context, Result};
|
||||
use tokio::fs;
|
||||
use yazi_fs::{maybe_exists, ok_or_not_found, remove_dir_clean, remove_sealed};
|
||||
use yazi_fs::{maybe_exists, ok_or_not_found, remove_dir_clean, remove_sealed, services::Local};
|
||||
use yazi_macro::outln;
|
||||
|
||||
use super::Dependency;
|
||||
|
|
@ -23,7 +22,7 @@ impl Dependency {
|
|||
|
||||
pub(super) async fn delete_assets(&self) -> Result<()> {
|
||||
let assets = self.target().join("assets");
|
||||
match fs::read_dir(&assets).await {
|
||||
match Local::read_dir(&assets).await {
|
||||
Ok(mut it) => {
|
||||
while let Some(entry) = it.next_entry().await? {
|
||||
remove_sealed(&entry.path())
|
||||
|
|
@ -52,7 +51,7 @@ impl Dependency {
|
|||
.with_context(|| format!("failed to delete `{}`", p.display()))?;
|
||||
}
|
||||
|
||||
if ok_or_not_found(fs::remove_dir(&dir).await).is_ok() {
|
||||
if ok_or_not_found(Local::remove_dir(&dir).await).is_ok() {
|
||||
outln!("Done!")?;
|
||||
} else {
|
||||
outln!(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use tokio::fs;
|
||||
use yazi_fs::{copy_and_seal, maybe_exists, remove_dir_clean};
|
||||
use yazi_fs::{copy_and_seal, maybe_exists, remove_dir_clean, services::Local};
|
||||
use yazi_macro::outln;
|
||||
|
||||
use super::Dependency;
|
||||
|
|
@ -20,7 +19,7 @@ impl Dependency {
|
|||
self.hash_check().await?;
|
||||
}
|
||||
|
||||
fs::create_dir_all(&to).await?;
|
||||
Local::create_dir_all(&to).await?;
|
||||
self.delete_assets().await?;
|
||||
|
||||
let res1 = Self::deploy_assets(from.join("assets"), to.join("assets")).await;
|
||||
|
|
@ -40,9 +39,9 @@ impl Dependency {
|
|||
}
|
||||
|
||||
async fn deploy_assets(from: PathBuf, to: PathBuf) -> Result<()> {
|
||||
match fs::read_dir(&from).await {
|
||||
match Local::read_dir(&from).await {
|
||||
Ok(mut it) => {
|
||||
fs::create_dir_all(&to).await?;
|
||||
Local::create_dir_all(&to).await?;
|
||||
while let Some(entry) = it.next_entry().await? {
|
||||
let (src, dist) = (entry.path(), to.join(entry.file_name()));
|
||||
copy_and_seal(&src, &dist).await.with_context(|| {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use anyhow::{Context, Result, bail};
|
||||
use tokio::fs;
|
||||
use twox_hash::XxHash3_128;
|
||||
use yazi_fs::ok_or_not_found;
|
||||
use yazi_fs::{ok_or_not_found, services::Local};
|
||||
|
||||
use super::Dependency;
|
||||
|
||||
|
|
@ -26,17 +25,17 @@ impl Dependency {
|
|||
for &file in files {
|
||||
h.write(file.as_bytes());
|
||||
h.write(b"VpvFw9Atb7cWGOdqhZCra634CcJJRlsRl72RbZeV0vpG1\0");
|
||||
h.write(&ok_or_not_found(fs::read(dir.join(file)).await)?);
|
||||
h.write(&ok_or_not_found(Local::read(dir.join(file)).await)?);
|
||||
}
|
||||
|
||||
let mut assets = vec![];
|
||||
match fs::read_dir(dir.join("assets")).await {
|
||||
match Local::read_dir(dir.join("assets")).await {
|
||||
Ok(mut it) => {
|
||||
while let Some(entry) = it.next_entry().await? {
|
||||
let Ok(name) = entry.file_name().into_string() else {
|
||||
bail!("asset path is not valid UTF-8: {}", entry.path().display());
|
||||
};
|
||||
assets.push((name, fs::read(entry.path()).await?));
|
||||
assets.push((name, Local::read(entry.path()).await?));
|
||||
}
|
||||
}
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ use std::{path::PathBuf, str::FromStr};
|
|||
|
||||
use anyhow::{Context, Result, bail};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use tokio::fs;
|
||||
use yazi_fs::Xdg;
|
||||
use yazi_fs::{Xdg, services::Local};
|
||||
use yazi_macro::outln;
|
||||
|
||||
use super::Dependency;
|
||||
|
|
@ -16,7 +15,7 @@ pub(crate) struct Package {
|
|||
|
||||
impl Package {
|
||||
pub(crate) async fn load() -> Result<Self> {
|
||||
Ok(match fs::read_to_string(Self::toml()).await {
|
||||
Ok(match Local::read_to_string(Self::toml()).await {
|
||||
Ok(s) => toml::from_str(&s)?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Self::default(),
|
||||
Err(e) => Err(e)?,
|
||||
|
|
@ -136,7 +135,7 @@ impl Package {
|
|||
|
||||
async fn save(&self) -> Result<()> {
|
||||
let s = toml::to_string_pretty(self)?;
|
||||
fs::write(Self::toml(), s).await.context("Failed to write package.toml")
|
||||
Local::write(Self::toml(), s).await.context("Failed to write package.toml")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ use std::{collections::{HashMap, HashSet}, time::Duration};
|
|||
use anyhow::Result;
|
||||
use notify::{PollWatcher, RecommendedWatcher, RecursiveMode, Watcher as _Watcher};
|
||||
use parking_lot::RwLock;
|
||||
use tokio::{fs, pin, sync::{mpsc::{self, UnboundedReceiver}, watch}};
|
||||
use tokio::{pin, sync::{mpsc::{self, UnboundedReceiver}, watch}};
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use tracing::error;
|
||||
use yazi_fs::{File, Files, FilesOp, cha::Cha, realname_unchecked};
|
||||
use yazi_fs::{File, Files, FilesOp, cha::Cha, realname_unchecked, services};
|
||||
use yazi_proxy::WATCHER;
|
||||
use yazi_shared::{RoCell, url::Url};
|
||||
|
||||
|
|
@ -21,6 +21,7 @@ pub struct Watcher {
|
|||
out_tx: mpsc::UnboundedSender<Url>,
|
||||
}
|
||||
|
||||
// FIXME: VFS
|
||||
impl Watcher {
|
||||
pub(super) fn serve() -> Self {
|
||||
let (in_tx, in_rx) = watch::channel(Default::default());
|
||||
|
|
@ -138,7 +139,7 @@ impl Watcher {
|
|||
};
|
||||
|
||||
let u = &file.url;
|
||||
let eq = (!file.is_link() && fs::canonicalize(u).await.is_ok_and(|p| p == ***u))
|
||||
let eq = (!file.is_link() && services::canonicalize(u).await.is_ok_and(|c| c == *u))
|
||||
|| realname_unchecked(u, &mut cached).await.is_ok_and(|s| urn.as_urn() == s);
|
||||
|
||||
if !eq {
|
||||
|
|
@ -193,10 +194,10 @@ impl Watcher {
|
|||
|
||||
async fn go(todo: HashSet<Url>) {
|
||||
for from in todo {
|
||||
let Ok(to) = fs::canonicalize(&from).await else { continue };
|
||||
let Ok(to) = services::canonicalize(&from).await else { continue };
|
||||
|
||||
if to != **from && WATCHED.read().contains(&from) {
|
||||
LINKED.write().insert(from, Url::from(to));
|
||||
if to != from && WATCHED.read().contains(&from) {
|
||||
LINKED.write().insert(from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ use std::{collections::HashMap, mem, ops::Deref, sync::atomic::{AtomicU64, Order
|
|||
|
||||
use anyhow::Result;
|
||||
use parking_lot::RwLock;
|
||||
use tokio::{fs::{self, File, OpenOptions}, io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter}};
|
||||
use tokio::{fs::OpenOptions, io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter}};
|
||||
use yazi_boot::BOOT;
|
||||
use yazi_fs::services::Local;
|
||||
use yazi_shared::{RoCell, timestamp_us};
|
||||
|
||||
use crate::CLIENTS;
|
||||
|
|
@ -56,8 +57,9 @@ impl State {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
fs::create_dir_all(&BOOT.state_dir).await?;
|
||||
Local::create_dir_all(&BOOT.state_dir).await?;
|
||||
let mut buf = BufWriter::new(
|
||||
// TODO: VFS
|
||||
OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
|
|
@ -77,7 +79,7 @@ impl State {
|
|||
}
|
||||
|
||||
async fn load(&self) -> Result<()> {
|
||||
let mut file = BufReader::new(File::open(BOOT.state_dir.join(".dds")).await?);
|
||||
let mut file = BufReader::new(Local::open(BOOT.state_dir.join(".dds")).await?);
|
||||
let mut buf = String::new();
|
||||
|
||||
let mut inner = HashMap::new();
|
||||
|
|
@ -101,7 +103,7 @@ impl State {
|
|||
}
|
||||
|
||||
async fn skip(&self) -> Result<bool> {
|
||||
let meta = fs::symlink_metadata(BOOT.state_dir.join(".dds")).await?;
|
||||
let meta = Local::symlink_metadata(BOOT.state_dir.join(".dds")).await?;
|
||||
let modified = meta.modified()?.duration_since(UNIX_EPOCH)?.as_micros();
|
||||
Ok(modified >= self.last.load(Ordering::Relaxed) as u128)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl Stream {
|
|||
pub(super) async fn bind() -> std::io::Result<ServerListener> {
|
||||
let p = Self::socket_file();
|
||||
|
||||
tokio::fs::remove_file(&p).await.ok();
|
||||
yazi_fs::services::Local::remove_file(&p).await.ok();
|
||||
tokio::net::UnixListener::bind(p)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::ffi::OsString;
|
||||
|
||||
use tokio::fs;
|
||||
use yazi_boot::ARGS;
|
||||
use yazi_fs::services::Local;
|
||||
use yazi_shared::event::EventQuit;
|
||||
|
||||
use crate::{Term, app::App};
|
||||
|
|
@ -26,13 +26,13 @@ impl App {
|
|||
async fn cwd_to_file(&self, no: bool) {
|
||||
if let Some(p) = ARGS.cwd_file.as_ref().filter(|_| !no) {
|
||||
let cwd = self.core.mgr.cwd().as_os_str();
|
||||
fs::write(p, cwd.as_encoded_bytes()).await.ok();
|
||||
Local::write(p, cwd.as_encoded_bytes()).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
async fn selected_to_file(&self, selected: Option<OsString>) {
|
||||
if let (Some(s), Some(p)) = (selected, &ARGS.chooser_file) {
|
||||
fs::write(p, s.as_encoded_bytes()).await.ok();
|
||||
Local::write(p, s.as_encoded_bytes()).await.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::{fs::{FileType, Metadata}, path::Path, time::SystemTime};
|
||||
use std::{fs::{FileType, Metadata}, time::SystemTime};
|
||||
|
||||
use tokio::fs;
|
||||
use yazi_macro::{unix_either, win_either};
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use super::ChaKind;
|
||||
use crate::services;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Cha {
|
||||
|
|
@ -53,20 +53,20 @@ impl Default for Cha {
|
|||
|
||||
impl Cha {
|
||||
#[inline]
|
||||
pub fn new(path: &Path, meta: Metadata) -> Self {
|
||||
Self::from_just_meta(&meta).attach(ChaKind::hidden(path, &meta))
|
||||
pub fn new(url: &Url, meta: Metadata) -> Self {
|
||||
Self::from_just_meta(&meta).attach(ChaKind::hidden(url, &meta))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn from_url(url: &Url) -> std::io::Result<Self> {
|
||||
Ok(Self::from_follow(url, fs::symlink_metadata(url).await?).await)
|
||||
Ok(Self::from_follow(url, services::symlink_metadata(url).await?).await)
|
||||
}
|
||||
|
||||
pub async fn from_follow(path: &Path, mut meta: Metadata) -> Self {
|
||||
let mut attached = ChaKind::hidden(path, &meta);
|
||||
pub async fn from_follow(url: &Url, mut meta: Metadata) -> Self {
|
||||
let mut attached = ChaKind::hidden(url, &meta);
|
||||
if meta.is_symlink() {
|
||||
attached |= ChaKind::LINK;
|
||||
meta = fs::metadata(path).await.unwrap_or(meta);
|
||||
meta = services::metadata(url).await.unwrap_or(meta);
|
||||
}
|
||||
if meta.is_symlink() {
|
||||
attached |= ChaKind::ORPHAN;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::{fs::Metadata, path::Path};
|
||||
use std::fs::Metadata;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
|
|
@ -19,11 +20,11 @@ bitflags! {
|
|||
|
||||
impl ChaKind {
|
||||
#[inline]
|
||||
pub(super) fn hidden(_path: &Path, _meta: &Metadata) -> Self {
|
||||
pub(super) fn hidden(_url: &Url, _meta: &Metadata) -> Self {
|
||||
let mut me = Self::empty();
|
||||
|
||||
#[cfg(unix)]
|
||||
if yazi_shared::url::Urn::new(_path).is_hidden() {
|
||||
if _url.urn().is_hidden() {
|
||||
me |= Self::HIDDEN;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use std::{ffi::OsStr, fs::{FileType, Metadata}, hash::{BuildHasher, Hash, Hasher}, ops::Deref};
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::fs;
|
||||
use yazi_shared::url::{Url, Urn, UrnBuf};
|
||||
|
||||
use crate::cha::Cha;
|
||||
use crate::{cha::Cha, services};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct File {
|
||||
|
|
@ -23,14 +22,13 @@ impl Deref for File {
|
|||
impl File {
|
||||
#[inline]
|
||||
pub async fn new(url: Url) -> Result<Self> {
|
||||
let meta = fs::symlink_metadata(&url).await?;
|
||||
let meta = services::symlink_metadata(&url).await?;
|
||||
Ok(Self::from_follow(url, meta).await)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn from_follow(url: Url, meta: Metadata) -> Self {
|
||||
let link_to =
|
||||
if meta.is_symlink() { fs::read_link(&url).await.map(Url::from).ok() } else { None };
|
||||
let link_to = if meta.is_symlink() { services::read_link(&url).await.ok() } else { None };
|
||||
|
||||
let cha = Cha::from_follow(&url, meta).await;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::{collections::{HashMap, HashSet}, mem, ops::{Deref, Not}};
|
||||
|
||||
use tokio::{fs::{self, DirEntry}, select, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use tokio::{select, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_shared::{Id, url::{Url, Urn, UrnBuf}};
|
||||
|
||||
use super::{FilesSorter, Filter};
|
||||
use crate::{FILES_TICKET, File, FilesOp, SortBy, cha::Cha, mounts::PARTITIONS};
|
||||
use crate::{FILES_TICKET, File, FilesOp, SortBy, cha::Cha, mounts::PARTITIONS, services};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Files {
|
||||
|
|
@ -31,7 +31,7 @@ impl Files {
|
|||
pub fn new(show_hidden: bool) -> Self { Self { show_hidden, ..Default::default() } }
|
||||
|
||||
pub async fn from_dir(dir: &Url) -> std::io::Result<UnboundedReceiver<File>> {
|
||||
let mut it = fs::read_dir(dir).await?;
|
||||
let mut it = services::read_dir(dir).await?;
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
|
@ -52,7 +52,7 @@ impl Files {
|
|||
}
|
||||
|
||||
pub async fn from_dir_bulk(dir: &Url) -> std::io::Result<Vec<File>> {
|
||||
let mut it = fs::read_dir(dir).await?;
|
||||
let mut it = services::read_dir(dir).await?;
|
||||
let mut entries = Vec::with_capacity(5000);
|
||||
while let Ok(Some(entry)) = it.next_entry().await {
|
||||
entries.push(entry);
|
||||
|
|
@ -60,7 +60,7 @@ impl Files {
|
|||
|
||||
let (first, rest) = entries.split_at(entries.len() / 3);
|
||||
let (second, third) = rest.split_at(entries.len() / 3);
|
||||
async fn go(entries: &[DirEntry]) -> Vec<File> {
|
||||
async fn go(entries: &[tokio::fs::DirEntry]) -> Vec<File> {
|
||||
let mut files = Vec::with_capacity(entries.len());
|
||||
for entry in entries {
|
||||
let url = Url::from(entry.path());
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// FIXME: VFS
|
||||
|
||||
use std::{borrow::Cow, collections::{HashMap, HashSet}, ffi::{OsStr, OsString}, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::if_same_then_else, clippy::option_map_unit_fn)]
|
||||
|
||||
yazi_macro::mod_pub!(cha mounts);
|
||||
yazi_macro::mod_pub!(cha mounts services);
|
||||
|
||||
yazi_macro::mod_flat!(calculator cwd file files filter fns op path sorter sorting stage xdg);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use std::{borrow::Cow, env, ffi::{OsStr, OsString}, future::Future, io, path::{Component, Path, PathBuf}};
|
||||
|
||||
use tokio::fs;
|
||||
use yazi_shared::url::{Loc, Url};
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use crate::CWD;
|
||||
use crate::{CWD, services};
|
||||
|
||||
#[inline]
|
||||
pub fn clean_url(url: &Url) -> Url { Url::from(clean_path(url)) }
|
||||
|
|
@ -83,19 +82,19 @@ pub async fn unique_name<F>(u: Url, append: F) -> io::Result<Url>
|
|||
where
|
||||
F: Future<Output = bool>,
|
||||
{
|
||||
match fs::symlink_metadata(&u).await {
|
||||
match services::symlink_metadata(&u).await {
|
||||
Ok(_) => _unique_name(u, append.await).await,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(u),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
async fn _unique_name(mut u: Url, append: bool) -> io::Result<Url> {
|
||||
let Some(stem) = u.file_stem().map(|s| s.to_owned()) else {
|
||||
async fn _unique_name(mut url: Url, append: bool) -> io::Result<Url> {
|
||||
let Some(stem) = url.file_stem().map(|s| s.to_owned()) else {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "empty file stem"));
|
||||
};
|
||||
|
||||
let dot_ext = u.extension().map_or_else(OsString::new, |e| {
|
||||
let dot_ext = url.extension().map_or_else(OsString::new, |e| {
|
||||
let mut s = OsString::with_capacity(e.len() + 1);
|
||||
s.push(".");
|
||||
s.push(e);
|
||||
|
|
@ -103,9 +102,9 @@ async fn _unique_name(mut u: Url, append: bool) -> io::Result<Url> {
|
|||
});
|
||||
|
||||
let mut i = 1u64;
|
||||
let mut p = u.to_path();
|
||||
let mut name = OsString::with_capacity(stem.len() + dot_ext.len() + 5);
|
||||
loop {
|
||||
let mut name = OsString::with_capacity(stem.len() + dot_ext.len() + 5);
|
||||
name.clear();
|
||||
name.push(&stem);
|
||||
|
||||
if append {
|
||||
|
|
@ -118,16 +117,15 @@ async fn _unique_name(mut u: Url, append: bool) -> io::Result<Url> {
|
|||
name.push(&dot_ext);
|
||||
}
|
||||
|
||||
p.set_file_name(name);
|
||||
match fs::symlink_metadata(&p).await {
|
||||
url.set_name(&name);
|
||||
match services::symlink_metadata(&url).await {
|
||||
Ok(_) => i += 1,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => break,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
u.set_loc(Loc::from(u.base(), p));
|
||||
Ok(u)
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
// Parameters
|
||||
|
|
|
|||
83
yazi-fs/src/services/local.rs
Normal file
83
yazi-fs/src/services/local.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
use std::{io, path::{Path, PathBuf}};
|
||||
|
||||
pub struct Local;
|
||||
|
||||
impl Local {
|
||||
#[inline]
|
||||
pub async fn canonicalize(path: impl AsRef<Path>) -> io::Result<PathBuf> {
|
||||
tokio::fs::canonicalize(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create(path: impl AsRef<Path>) -> io::Result<tokio::fs::File> {
|
||||
tokio::fs::File::create(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create_dir(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
tokio::fs::create_dir(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
tokio::fs::create_dir_all(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn metadata(url: impl AsRef<Path>) -> io::Result<std::fs::Metadata> {
|
||||
tokio::fs::metadata(url).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn open(path: impl AsRef<Path>) -> io::Result<tokio::fs::File> {
|
||||
tokio::fs::File::open(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read(path: impl AsRef<Path>) -> io::Result<Vec<u8>> { tokio::fs::read(path).await }
|
||||
|
||||
#[inline]
|
||||
pub async fn read_dir(path: impl AsRef<Path>) -> io::Result<tokio::fs::ReadDir> {
|
||||
tokio::fs::read_dir(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_link(url: impl AsRef<Path>) -> io::Result<PathBuf> {
|
||||
tokio::fs::read_link(url).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_to_string(path: impl AsRef<Path>) -> io::Result<String> {
|
||||
tokio::fs::read_to_string(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_dir(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
tokio::fs::remove_dir(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
tokio::fs::remove_dir_all(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_file(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
tokio::fs::remove_file(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
|
||||
tokio::fs::rename(from, to).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_metadata(path: impl AsRef<Path>) -> io::Result<std::fs::Metadata> {
|
||||
tokio::fs::symlink_metadata(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
|
||||
tokio::fs::write(path, contents).await
|
||||
}
|
||||
}
|
||||
1
yazi-fs/src/services/mod.rs
Normal file
1
yazi-fs/src/services/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(local services);
|
||||
75
yazi-fs/src/services/services.rs
Normal file
75
yazi-fs/src/services/services.rs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
use std::io;
|
||||
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use crate::services::Local;
|
||||
|
||||
#[inline]
|
||||
pub async fn canonicalize(url: impl AsRef<Url>) -> io::Result<Url> {
|
||||
Local::canonicalize(url.as_ref()).await.map(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create(url: impl AsRef<Url>) -> io::Result<tokio::fs::File> {
|
||||
Local::create(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create_dir(url: impl AsRef<Url>) -> io::Result<()> {
|
||||
Local::create_dir(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create_dir_all(url: impl AsRef<Url>) -> io::Result<()> {
|
||||
Local::create_dir_all(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn metadata(url: impl AsRef<Url>) -> io::Result<std::fs::Metadata> {
|
||||
Local::metadata(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn open(url: impl AsRef<Url>) -> io::Result<tokio::fs::File> {
|
||||
Local::open(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_dir(url: impl AsRef<Url>) -> io::Result<tokio::fs::ReadDir> {
|
||||
Local::read_dir(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_link(url: impl AsRef<Url>) -> io::Result<Url> {
|
||||
Local::read_link(url.as_ref()).await.map(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_dir(url: impl AsRef<Url>) -> io::Result<()> {
|
||||
Local::remove_dir(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_dir_all(url: impl AsRef<Url>) -> io::Result<()> {
|
||||
Local::remove_dir_all(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_file(url: impl AsRef<Url>) -> io::Result<()> {
|
||||
Local::remove_file(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn rename(from: impl AsRef<Url>, to: impl AsRef<Url>) -> io::Result<()> {
|
||||
Local::rename(from.as_ref(), to.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_metadata(url: impl AsRef<Url>) -> io::Result<std::fs::Metadata> {
|
||||
Local::symlink_metadata(url.as_ref()).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn write(url: impl AsRef<Url>, contents: impl AsRef<[u8]>) -> io::Result<()> {
|
||||
Local::write(url.as_ref(), contents).await
|
||||
}
|
||||
7
yazi-plugin/src/external/highlighter.rs
vendored
7
yazi-plugin/src/external/highlighter.rs
vendored
|
|
@ -3,8 +3,9 @@ use std::{borrow::Cow, io::Cursor, mem, path::{Path, PathBuf}, sync::OnceLock};
|
|||
use anyhow::{Result, anyhow};
|
||||
use ratatui::{layout::Size, text::{Line, Span, Text}};
|
||||
use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}};
|
||||
use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}};
|
||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
use yazi_config::{THEME, YAZI, preview::PreviewWrap};
|
||||
use yazi_fs::services::Local;
|
||||
use yazi_shared::{Ids, errors::PeekError, replace_to_printable};
|
||||
|
||||
static INCR: Ids = Ids::new();
|
||||
|
|
@ -38,7 +39,7 @@ impl Highlighter {
|
|||
pub fn abort() { INCR.next(); }
|
||||
|
||||
pub async fn highlight(&self, skip: usize, size: Size) -> Result<Text<'static>, PeekError> {
|
||||
let mut reader = BufReader::new(File::open(&self.path).await?);
|
||||
let mut reader = BufReader::new(Local::open(&self.path).await?);
|
||||
|
||||
let syntax = Self::find_syntax(&self.path).await;
|
||||
let mut plain = syntax.is_err();
|
||||
|
|
@ -142,7 +143,7 @@ impl Highlighter {
|
|||
}
|
||||
|
||||
let mut line = String::new();
|
||||
let mut reader = BufReader::new(File::open(&path).await?);
|
||||
let mut reader = BufReader::new(Local::open(&path).await?);
|
||||
reader.read_line(&mut line).await?;
|
||||
syntaxes.find_syntax_by_first_line(&line).ok_or_else(|| anyhow!("No syntax found"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use globset::GlobBuilder;
|
||||
use mlua::{ExternalError, ExternalResult, Function, IntoLua, IntoLuaMulti, Lua, Table, Value};
|
||||
use tokio::fs;
|
||||
use yazi_binding::{Cha, Composer, ComposerGet, ComposerSet, Error, File, Url, UrlRef};
|
||||
use yazi_fs::{mounts::PARTITIONS, remove_dir_clean};
|
||||
use yazi_fs::{mounts::PARTITIONS, remove_dir_clean, services};
|
||||
|
||||
use crate::bindings::SizeCalculator;
|
||||
|
||||
|
|
@ -49,9 +48,9 @@ fn cwd(lua: &Lua) -> mlua::Result<Function> {
|
|||
fn cha(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (url, follow): (UrlRef, Option<bool>)| async move {
|
||||
let meta = if follow.unwrap_or(false) {
|
||||
fs::metadata(&*url).await
|
||||
services::metadata(&*url).await
|
||||
} else {
|
||||
fs::symlink_metadata(&*url).await
|
||||
services::symlink_metadata(&*url).await
|
||||
};
|
||||
|
||||
match meta {
|
||||
|
|
@ -63,7 +62,7 @@ fn cha(lua: &Lua) -> mlua::Result<Function> {
|
|||
|
||||
fn write(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (url, data): (UrlRef, mlua::String)| async move {
|
||||
match fs::write(&*url, data.as_bytes()).await {
|
||||
match services::write(&*url, data.as_bytes()).await {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
|
|
@ -73,8 +72,8 @@ fn write(lua: &Lua) -> mlua::Result<Function> {
|
|||
fn create(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (r#type, url): (mlua::String, UrlRef)| async move {
|
||||
let result = match r#type.as_bytes().as_ref() {
|
||||
b"dir" => fs::create_dir(&*url).await,
|
||||
b"dir_all" => fs::create_dir_all(&*url).await,
|
||||
b"dir" => services::create_dir(&*url).await,
|
||||
b"dir_all" => services::create_dir_all(&*url).await,
|
||||
_ => Err("Creation type must be 'dir' or 'dir_all'".into_lua_err())?,
|
||||
};
|
||||
|
||||
|
|
@ -88,9 +87,9 @@ fn create(lua: &Lua) -> mlua::Result<Function> {
|
|||
fn remove(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (r#type, url): (mlua::String, UrlRef)| async move {
|
||||
let result = match r#type.as_bytes().as_ref() {
|
||||
b"file" => fs::remove_file(&*url).await,
|
||||
b"dir" => fs::remove_dir(&*url).await,
|
||||
b"dir_all" => fs::remove_dir_all(&*url).await,
|
||||
b"file" => services::remove_file(&*url).await,
|
||||
b"dir" => services::remove_dir(&*url).await,
|
||||
b"dir_all" => services::remove_dir_all(&*url).await,
|
||||
b"dir_clean" => Ok(remove_dir_clean(&url).await),
|
||||
_ => Err("Removal type must be 'file', 'dir', 'dir_all', or 'dir_clean'".into_lua_err())?,
|
||||
};
|
||||
|
|
@ -122,7 +121,7 @@ fn read_dir(lua: &Lua) -> mlua::Result<Function> {
|
|||
let limit = options.raw_get("limit").unwrap_or(usize::MAX);
|
||||
let resolve = options.raw_get("resolve").unwrap_or(false);
|
||||
|
||||
let mut it = match fs::read_dir(&*dir).await {
|
||||
let mut it = match services::read_dir(&*dir).await {
|
||||
Ok(it) => it,
|
||||
Err(e) => return (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ use std::{borrow::Cow, collections::HashMap, ops::Deref};
|
|||
use anyhow::{Context, Result, bail};
|
||||
use mlua::{ChunkMode, ExternalError, Lua, Table};
|
||||
use parking_lot::RwLock;
|
||||
use tokio::fs;
|
||||
use yazi_boot::BOOT;
|
||||
use yazi_fs::services::Local;
|
||||
use yazi_macro::plugin_preset as preset;
|
||||
use yazi_shared::{LOG_LEVEL, RoCell};
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ impl Loader {
|
|||
|
||||
let p = BOOT.plugin_dir.join(format!("{name}.yazi/main.lua"));
|
||||
let chunk =
|
||||
fs::read(&p).await.with_context(|| format!("Failed to load plugin from {p:?}"))?.into();
|
||||
Local::read(&p).await.with_context(|| format!("Failed to load plugin from {p:?}"))?.into();
|
||||
|
||||
let result = Self::compatible_or_error(name, &chunk);
|
||||
let inspect = f(&chunk);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use std::{borrow::Cow, collections::VecDeque, path::Path};
|
||||
// FIXME: VFS, depends on yazi_fs::fns
|
||||
use std::{borrow::Cow, collections::VecDeque};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use tokio::{fs::{self, DirEntry}, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
||||
use tracing::warn;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_fs::{SizeCalculator, cha::Cha, copy_with_progress, maybe_exists, ok_or_not_found, path_relative_to, skip_path};
|
||||
use yazi_fs::{SizeCalculator, cha::Cha, copy_with_progress, maybe_exists, ok_or_not_found, path_relative_to, services, skip_path};
|
||||
use yazi_shared::{Id, url::Url};
|
||||
|
||||
use super::{FileIn, FileInDelete, FileInHardlink, FileInLink, FileInPaste, FileInTrash};
|
||||
|
|
@ -327,17 +328,17 @@ impl File {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
async fn cha(path: &Path, follow: bool) -> io::Result<Cha> {
|
||||
let meta = fs::symlink_metadata(path).await?;
|
||||
Ok(if follow { Cha::from_follow(path, meta).await } else { Cha::new(path, meta) })
|
||||
async fn cha(url: &Url, follow: bool) -> io::Result<Cha> {
|
||||
let meta = services::symlink_metadata(url).await?;
|
||||
Ok(if follow { Cha::from_follow(url, meta).await } else { Cha::new(url, meta) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn cha_from(entry: DirEntry, path: &Path, follow: bool) -> io::Result<Cha> {
|
||||
async fn cha_from(entry: DirEntry, url: &Url, follow: bool) -> io::Result<Cha> {
|
||||
Ok(if follow {
|
||||
Cha::from_follow(path, entry.metadata().await?).await
|
||||
Cha::from_follow(url, entry.metadata().await?).await
|
||||
} else {
|
||||
Cha::new(path, entry.metadata().await?)
|
||||
Cha::new(url, entry.metadata().await?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ use std::{ffi::OsString, future::Future, sync::Arc, time::Duration};
|
|||
use anyhow::Result;
|
||||
use futures::{FutureExt, future::BoxFuture};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::{fs, select, sync::mpsc::{self, UnboundedReceiver}, task::JoinHandle};
|
||||
use tokio::{select, sync::mpsc::{self, UnboundedReceiver}, task::JoinHandle};
|
||||
use yazi_config::{YAZI, plugin::{Fetcher, Preloader}};
|
||||
use yazi_dds::Pump;
|
||||
use yazi_fs::{must_be_dir, remove_dir_clean, unique_name};
|
||||
use yazi_fs::{must_be_dir, remove_dir_clean, services, unique_name};
|
||||
use yazi_parser::{app::PluginOpt, tasks::ProcessExecOpt};
|
||||
use yazi_proxy::MgrProxy;
|
||||
use yazi_shared::{Id, Throttle, url::Url};
|
||||
|
|
@ -166,7 +166,7 @@ impl Scheduler {
|
|||
move |canceled: bool| {
|
||||
async move {
|
||||
if !canceled {
|
||||
fs::remove_dir_all(&target).await.ok();
|
||||
services::remove_dir_all(&target).await.ok();
|
||||
MgrProxy::update_tasks(&target);
|
||||
Pump::push_delete(target);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,22 @@ impl Loc {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: impl AsRef<OsStr>) {
|
||||
let name = name.as_ref();
|
||||
if name == self.name() {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.name > name.len() {
|
||||
self.urn -= self.name - name.len();
|
||||
} else {
|
||||
self.urn += name.len() - self.name;
|
||||
}
|
||||
|
||||
self.name = name.len();
|
||||
self.path.set_file_name(name);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn base(&self) -> &Path {
|
||||
Path::new(unsafe {
|
||||
|
|
@ -122,6 +138,8 @@ impl Loc {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::MAIN_SEPARATOR;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
|
@ -159,4 +177,22 @@ mod tests {
|
|||
assert_eq!(loc.name(), OsStr::new("foo"));
|
||||
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_name() {
|
||||
let mut loc = Loc::from(Path::new("/root"), "/root/code/foo/".into());
|
||||
assert_eq!(loc.urn().as_os_str(), OsStr::new("code/foo"));
|
||||
assert_eq!(loc.name(), OsStr::new("foo"));
|
||||
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/"));
|
||||
|
||||
loc.set_name("bar.txt");
|
||||
assert_eq!(loc.urn().as_os_str(), OsString::from(format!("code{MAIN_SEPARATOR}bar.txt")));
|
||||
assert_eq!(loc.name(), OsStr::new("bar.txt"));
|
||||
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/"));
|
||||
|
||||
loc.set_name("baz");
|
||||
assert_eq!(loc.urn().as_os_str(), OsString::from(format!("code{MAIN_SEPARATOR}baz")));
|
||||
assert_eq!(loc.name(), OsStr::new("baz"));
|
||||
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,6 +167,9 @@ impl Url {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_name(&mut self, name: impl AsRef<OsStr>) { self.loc.set_name(name); }
|
||||
|
||||
#[inline]
|
||||
pub fn pair(&self) -> Option<(Self, UrnBuf)> { Some((self.parent_url()?, self.loc.urn_owned())) }
|
||||
|
||||
|
|
@ -240,9 +243,7 @@ impl Url {
|
|||
#[inline]
|
||||
pub fn set_loc(&mut self, loc: Loc) { self.loc = loc; }
|
||||
|
||||
#[inline]
|
||||
pub fn to_path(&self) -> PathBuf { self.loc.to_path_buf() }
|
||||
|
||||
// FIXME: remove
|
||||
#[inline]
|
||||
pub fn into_path(self) -> PathBuf { self.loc.into_path() }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue