fix: make file counter more distinguishable in dark mode (#3311)

This commit is contained in:
三咲雅 misaki masa 2025-11-05 01:20:56 +08:00 committed by GitHub
parent 604b86612a
commit 97c63e2708
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 378 additions and 322 deletions

21
Cargo.lock generated
View file

@ -459,9 +459,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.43"
version = "1.2.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2"
checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3"
dependencies = [
"find-msvc-tools",
"jobserver",
@ -568,9 +568,9 @@ dependencies = [
[[package]]
name = "clap_complete_nushell"
version = "4.5.9"
version = "4.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "811159f339691baacdf7d534df2946b9d217014081099e23d31d887d99521e70"
checksum = "685bc86fd34b7467e0532a4f8435ab107960d69a243785ef0275e571b35b641a"
dependencies = [
"clap",
"clap_complete",
@ -2233,11 +2233,10 @@ dependencies = [
[[package]]
name = "num-bigint-dig"
version = "0.8.4"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b"
dependencies = [
"byteorder",
"lazy_static",
"libm",
"num-integer",
@ -3774,9 +3773,9 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.16"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
dependencies = [
"bytes",
"futures-core",
@ -4112,9 +4111,9 @@ dependencies = [
[[package]]
name = "version-compare"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e"
[[package]]
name = "version_check"

View file

@ -50,9 +50,15 @@ serde_json = "1.0.145"
syntect = { version = "5.3.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
tokio = { version = "1.48.0", features = [ "full" ] }
tokio-stream = "0.1.17"
tokio-util = "0.7.16"
tokio-util = "0.7.17"
toml = { version = "0.9.8" }
tracing = { version = "0.1.41", features = [ "max_level_debug", "release_max_level_debug" ] }
twox-hash = { version = "2.1.2", default-features = false, features = [ "std", "random", "xxhash3_128" ] }
unicode-width = { version = "0.2.0", default-features = false }
uzers = "0.12.1"
[workspace.lints.clippy]
format_push_string = "warn"
implicit_clone = "warn"
module_inception = "allow"
use_self = "warn"

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(core file files filter finder folder lives mode preference preview ptr selected tab tabs task tasks yanked);

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(align area bar border cell clear constraint edge elements gauge layout line list pad pos rect renderable row span table text wrap);

View file

@ -30,5 +30,5 @@ yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
clap = { workspace = true }
clap_complete = "4.5.60"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.9"
clap_complete_nushell = "4.5.10"
vergen-gitcl = { version = "1.0.8", features = [ "build", "rustc" ] }

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(actions clear_cache debug rustc triple version);

View file

@ -43,7 +43,7 @@ anyhow = { workspace = true }
clap = { workspace = true }
clap_complete = "4.5.60"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.9"
clap_complete_nushell = "4.5.10"
serde_json = { workspace = true }
vergen-gitcl = { version = "1.0.8", features = [ "build" ] }

View file

@ -1,5 +1,3 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(add delete dependency deploy git hash install package upgrade);
use anyhow::Context;

View file

@ -41,7 +41,7 @@ marker_selected = { fg = "lightyellow", bg = "lightyellow" }
# Count
count_copied = { fg = "white", bg = "green" }
count_cut = { fg = "white", bg = "red" }
count_selected = { fg = "white", bg = "yellow" }
count_selected = { fg = "black", bg = "yellow" }
# Border
border_symbol = "│"

View file

@ -1,5 +1,3 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_pub!(keymap mgr open opener plugin popup preview tasks theme which vfs);
yazi_macro::mod_flat!(color icon layout pattern platform preset priority style yazi);

View file

@ -1,7 +1,6 @@
#![allow(
clippy::if_same_then_else,
clippy::len_without_is_empty,
clippy::module_inception,
clippy::option_map_unit_fn,
clippy::unit_arg
)]

View file

@ -1,5 +1,3 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(
bulk bye cd custom delete ember hey hi hover load mount r#move rename tab trash yank
);

View file

@ -1,4 +1,4 @@
#![allow(clippy::if_same_then_else, clippy::module_inception, clippy::unit_arg)]
#![allow(clippy::if_same_then_else, clippy::unit_arg)]
#[cfg(all(not(target_os = "macos"), not(target_os = "windows")))]
#[global_allocator]

View file

@ -10,7 +10,8 @@ pub fn clean_url<'a>(url: impl Into<UrlCow<'a>>) -> UrlBuf {
cow.loc().trail().components().count(),
);
let loc = LocBuf::with(path, uri, urn).expect("Failed to create Loc from cleaned path");
let loc =
LocBuf::<PathBuf>::with(path, uri, urn).expect("Failed to create Loc from cleaned path");
UrlBuf { loc, scheme: cow.into_scheme().into() }
}

View file

@ -22,7 +22,7 @@ fn expand_url_impl<'a>(url: Url<'a>) -> UrlCow<'a> {
let uri_count = url.uri().components().count() as isize;
let urn_count = url.urn().components().count() as isize;
let loc = LocBuf::with(
let loc = LocBuf::<PathBuf>::with(
PathBuf::from_iter([n_base, n_rest, n_urn]),
(uri_count + rest_diff + urn_diff) as usize,
(urn_count + urn_diff) as usize,
@ -69,7 +69,7 @@ pub fn absolute_url<'a>(url: Url<'a>) -> UrlCow<'a> {
let b = url.loc.as_os_str().as_encoded_bytes();
if cfg!(windows) && b.len() == 2 && b[1] == b':' && b[0].is_ascii_alphabetic() {
let loc = LocBuf::with(
let loc = LocBuf::<PathBuf>::with(
format!(r"{}:\", b[0].to_ascii_uppercase() as char).into(),
if url.has_base() { 0 } else { 2 },
if url.has_trail() { 0 } else { 2 },
@ -81,7 +81,7 @@ pub fn absolute_url<'a>(url: Url<'a>) -> UrlCow<'a> {
&& home.is_absolute()
{
let add = home.components().count() - 1; // Home root ("~") has offset by the absolute root ("/")
let loc = LocBuf::with(
let loc = LocBuf::<PathBuf>::with(
home.join(rest),
url.uri().components().count() + if url.has_base() { 0 } else { add },
url.urn().components().count() + if url.has_trail() { 0 } else { add },
@ -90,7 +90,7 @@ pub fn absolute_url<'a>(url: Url<'a>) -> UrlCow<'a> {
UrlBuf { loc, scheme: url.scheme.into() }.into()
} else if !url.is_absolute() {
let cwd = CWD.path();
let loc = LocBuf::with(
let loc = LocBuf::<PathBuf>::with(
cwd.join(url.loc),
url.uri().components().count(),
url.urn().components().count(),

View file

@ -25,7 +25,7 @@ pub(super) fn url_relative_to<'a>(from: UrlCow<'_>, to: UrlCow<'a>) -> Result<Ur
}
if from.covariant(&to) {
return Ok(UrlBuf { loc: LocBuf::zeroed("."), scheme: to.scheme().into() }.into());
return Ok(UrlBuf { loc: LocBuf::<PathBuf>::zeroed("."), scheme: to.scheme().into() }.into());
}
let (mut f_it, mut t_it) = (from.components(), to.components());
@ -47,5 +47,5 @@ pub(super) fn url_relative_to<'a>(from: UrlCow<'_>, to: UrlCow<'a>) -> Result<Ur
let rest = t_head.into_iter().chain(t_it);
let buf: PathBuf = dots.chain(rest).collect();
Ok(UrlBuf { loc: LocBuf::zeroed(buf), scheme: to.scheme().into() }.into())
Ok(UrlBuf { loc: LocBuf::<PathBuf>::zeroed(buf), scheme: to.scheme().into() }.into())
}

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(calculator chan image input layer mouse range);

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(fs op);

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(entry fetch isolate peek preload seek spot);

View file

@ -1,5 +1,3 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(chunk loader require);
pub(super) fn init() { LOADER.with(<_>::default); }

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(child command output process status);

View file

@ -1,5 +1,3 @@
#![allow(clippy::module_inception)]
use mlua::{IntoLua, Lua, Value};
use yazi_binding::{Composer, ComposerGet, ComposerSet};

View file

@ -1,5 +1,3 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(
app cache call image json layer log preview process spot sync target text time user utils
);

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(file out progress r#in);

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(out plugin progress r#in);

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(out prework progress r#in);

View file

@ -1,3 +1 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(out process progress r#in shell);

View file

@ -1,5 +1,3 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(cmd cow event);
pub static NEED_RENDER: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);

View file

@ -1,8 +1,8 @@
use std::{cmp, ffi::OsStr, fmt::{self, Debug, Formatter}, hash::{Hash, Hasher}, ops::Deref, path::PathBuf};
use std::{cmp, ffi::OsStr, fmt::{self, Debug, Formatter}, hash::{Hash, Hasher}, marker::PhantomData, ops::Deref, path::PathBuf};
use anyhow::Result;
use crate::{loc::Loc, path::{PathBufLike, PathLike}};
use crate::{loc::Loc, path::{AsInnerView, AsPathView, PathBufLike, PathLike}};
#[derive(Clone, Default, Eq)]
pub struct LocBuf<P: PathBufLike = PathBuf> {
@ -20,11 +20,9 @@ where
fn deref(&self) -> &Self::Target { &self.inner }
}
impl<P> AsRef<P::Borrowed> for LocBuf<P>
where
P: PathBufLike,
{
fn as_ref(&self) -> &P::Borrowed { self.inner.as_ref() }
// FIXME: remove
impl AsRef<std::path::Path> for LocBuf<PathBuf> {
fn as_ref(&self) -> &std::path::Path { self.inner.as_ref() }
}
impl<P> PartialEq for LocBuf<P>
@ -54,7 +52,7 @@ where
impl<P> Hash for LocBuf<P>
where
P: PathBufLike,
P::Borrowed: Hash,
for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>,
{
fn hash<H: Hasher>(&self, state: &mut H) { self.as_loc().hash(state) }
}
@ -62,7 +60,7 @@ where
impl<P> Debug for LocBuf<P>
where
P: PathBufLike + Debug,
P::Borrowed: Debug,
for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("LocBuf")
@ -76,9 +74,10 @@ where
impl<P> From<P> for LocBuf<P>
where
P: PathBufLike,
for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>,
{
fn from(path: P) -> Self {
let Loc { inner, uri, urn } = Loc::from(&path);
let Loc { inner, uri, urn, _phantom } = Loc::bare(&path);
let len = inner.len();
let mut bytes = path.into_encoded_bytes();
@ -94,13 +93,14 @@ impl<T: ?Sized + AsRef<OsStr>> From<&T> for LocBuf<PathBuf> {
impl<P> LocBuf<P>
where
P: PathBufLike,
for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>,
{
pub fn new<T>(path: P, base: &T, trail: &T) -> Self
pub fn new<'a, T>(path: P, base: T, trail: T) -> Self
where
T: AsRef<P::Borrowed> + ?Sized,
T: for<'b> AsPathView<'a, <P::Borrowed<'b> as PathLike<'b>>::View<'a>>,
{
let loc = Self::from(path);
let Loc { inner, uri, urn } = Loc::new(&loc.inner, base, trail);
let Loc { inner, uri, urn, _phantom } = Loc::new(&loc.inner, base, trail);
debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes());
Self { inner: loc.inner, uri, urn }
@ -108,10 +108,10 @@ where
pub fn with(path: P, uri: usize, urn: usize) -> Result<Self>
where
P::Borrowed: PathLike,
for<'a> P::Borrowed<'a>: PathLike<'a>,
{
let loc = Self::from(path);
let Loc { inner, uri, urn } = Loc::with(&loc.inner, uri, urn)?;
let Loc { inner, uri, urn, _phantom } = Loc::with(&loc.inner, uri, urn)?;
debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes());
Ok(Self { inner: loc.inner, uri, urn })
@ -126,27 +126,31 @@ where
T: Into<P>,
{
let loc = Self::from(path.into());
let Loc { inner, uri, urn } = Loc::zeroed(&loc.inner);
let Loc { inner, uri, urn, _phantom } = Loc::zeroed(&loc.inner);
debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes());
Self { inner: loc.inner, uri, urn }
}
pub fn floated<T, U>(path: T, base: &U) -> Self
pub fn floated<'a, T>(path: P, base: T) -> Self
where
T: Into<P>,
U: AsRef<P::Borrowed> + ?Sized,
T: for<'b> AsPathView<'a, <P::Borrowed<'b> as PathLike<'b>>::View<'a>>,
{
let loc = Self::from(path.into());
let Loc { inner, uri, urn } = Loc::floated(&loc.inner, base);
let loc = Self::from(path);
let Loc { inner, uri, urn, _phantom } = Loc::floated(&loc.inner, base);
debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes());
Self { inner: loc.inner, uri, urn }
}
#[inline]
pub fn as_loc<'a>(&'a self) -> Loc<'a, P::Borrowed> {
Loc { inner: self.inner.as_ref(), uri: self.uri, urn: self.urn }
pub fn as_loc<'a>(&'a self) -> Loc<'a, P::Borrowed<'a>> {
Loc {
inner: self.inner.as_path_view(),
uri: self.uri,
urn: self.urn,
_phantom: PhantomData,
}
}
#[inline]
@ -162,7 +166,7 @@ where
pub fn set_name<T>(&mut self, name: T)
where
T: AsRef<P::InnerRef>,
T: for<'a> AsInnerView<'a, P::InnerRef<'a>>,
{
let old = self.inner.len();
self.mutate(|path| path.set_file_name(name));
@ -189,9 +193,10 @@ where
}
#[inline]
pub fn rebase(&self, base: &P::Borrowed) -> Self
pub fn rebase<'a, 'b>(&'a self, base: P::Borrowed<'b>) -> Self
where
<P::Borrowed as PathLike>::Owned: Into<Self>,
'a: 'b,
for<'c> <P::Borrowed<'c> as PathLike<'c>>::Owned: Into<Self>,
{
let mut loc: Self = base.join(self.uri()).into();
(loc.uri, loc.urn) = (self.uri, self.urn);
@ -213,33 +218,34 @@ where
impl<P> LocBuf<P>
where
P: PathBufLike,
for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>,
{
#[inline]
pub fn uri(&self) -> &P::Borrowed { self.as_loc().uri() }
pub fn uri(&self) -> P::Borrowed<'_> { self.as_loc().uri() }
#[inline]
pub fn urn(&self) -> &P::Borrowed { self.as_loc().urn() }
pub fn urn(&self) -> P::Borrowed<'_> { self.as_loc().urn() }
#[inline]
pub fn base(&self) -> &P::Borrowed { self.as_loc().base() }
pub fn base(&self) -> P::Borrowed<'_> { self.as_loc().base() }
#[inline]
pub fn has_base(&self) -> bool { self.as_loc().has_base() }
#[inline]
pub fn trail(&self) -> &P::Borrowed { self.as_loc().trail() }
pub fn trail(&self) -> P::Borrowed<'_> { self.as_loc().trail() }
#[inline]
pub fn has_trail(&self) -> bool { self.as_loc().has_trail() }
#[inline]
pub fn name(&self) -> Option<&<P::Borrowed as PathLike>::Inner> { self.as_loc().name() }
pub fn name(&self) -> Option<<P::Borrowed<'_> as PathLike<'_>>::Inner> { self.as_loc().name() }
#[inline]
pub fn stem(&self) -> Option<&<P::Borrowed as PathLike>::Inner> { self.as_loc().stem() }
pub fn stem(&self) -> Option<<P::Borrowed<'_> as PathLike<'_>>::Inner> { self.as_loc().stem() }
#[inline]
pub fn ext(&self) -> Option<&<P::Borrowed as PathLike>::Inner> { self.as_loc().ext() }
pub fn ext(&self) -> Option<<P::Borrowed<'_> as PathLike<'_>>::Inner> { self.as_loc().ext() }
}
#[cfg(test)]

View file

@ -1,125 +1,90 @@
use std::{hash::{Hash, Hasher}, ops::Deref, path::Path};
use std::{hash::{Hash, Hasher}, marker::PhantomData, ops::Deref, path::Path};
use anyhow::{Result, bail};
use crate::{loc::LocBuf, path::{PathInner, PathLike}};
use crate::{loc::LocBuf, path::{AsPathView, PathBufLike, PathInner, PathLike, ToPathOwned}};
#[derive(Debug)]
pub struct Loc<'a, P: ?Sized + PathLike = Path> {
pub(super) inner: &'a P,
pub(super) uri: usize,
pub(super) urn: usize,
#[derive(Clone, Copy, Debug)]
pub struct Loc<'p, P = &'p Path> {
pub(super) inner: P,
pub(super) uri: usize,
pub(super) urn: usize,
pub(super) _phantom: PhantomData<&'p ()>,
}
impl<'a, P> Copy for Loc<'a, P> where P: ?Sized + PathLike {}
impl<'a, P> Clone for Loc<'a, P>
impl<'p, P> Default for Loc<'p, P>
where
P: ?Sized + PathLike,
P: PathLike<'p>,
{
fn clone(&self) -> Self { *self }
fn default() -> Self { Self { inner: P::default(), uri: 0, urn: 0, _phantom: PhantomData } }
}
impl<P> Default for Loc<'static, P>
impl<'p, P> Deref for Loc<'p, P>
where
P: ?Sized + PathLike,
{
fn default() -> Self { Self { inner: P::default(), uri: 0, urn: 0 } }
}
impl<P> Deref for Loc<'_, P>
where
P: ?Sized + PathLike,
P: PathLike<'p>,
{
type Target = P;
fn deref(&self) -> &Self::Target { self.inner }
fn deref(&self) -> &Self::Target { &self.inner }
}
impl<P> AsRef<P> for Loc<'_, P>
where
P: ?Sized + PathLike,
{
fn as_ref(&self) -> &P { self.inner }
// FIXME: remove
impl AsRef<std::path::Path> for Loc<'_, &std::path::Path> {
fn as_ref(&self) -> &std::path::Path { self.inner }
}
// --- Hash
impl<P> Hash for Loc<'_, P>
impl<'p, P> Hash for Loc<'p, P>
where
P: ?Sized + PathLike + Hash,
P: PathLike<'p> + Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) { self.inner.hash(state) }
}
impl<'a, P, T> From<&'a T> for Loc<'a, P>
impl<'p, P> From<Loc<'p, P>> for LocBuf<<P as PathLike<'p>>::Owned>
where
P: ?Sized + PathLike,
T: ?Sized + AsRef<P>,
P: PathLike<'p> + ToPathOwned<<P as PathLike<'p>>::Owned>,
<P as PathLike<'p>>::Owned: PathBufLike,
{
fn from(value: &'a T) -> Self {
let path = value.as_ref();
let Some(name) = path.file_name() else {
let uri = path.len();
return Self { inner: path, uri, urn: 0 };
};
let name_len = name.len();
let prefix_len =
unsafe { name.encoded_bytes().as_ptr().offset_from_unsigned(path.encoded_bytes().as_ptr()) };
let bytes = path.encoded_bytes();
Self {
inner: unsafe { P::from_encoded_bytes(&bytes[..prefix_len + name_len]) },
uri: name_len,
urn: name_len,
}
}
}
impl<P> From<Loc<'_, P>> for LocBuf<<P as PathLike>::Owned>
where
P: ?Sized + PathLike + ToOwned<Owned = <P as PathLike>::Owned>,
{
fn from(value: Loc<'_, P>) -> Self {
Self { inner: value.inner.to_owned(), uri: value.uri, urn: value.urn }
fn from(value: Loc<'p, P>) -> Self {
Self { inner: value.inner.to_path_owned(), uri: value.uri, urn: value.urn }
}
}
// --- Eq
impl<P> PartialEq for Loc<'_, P>
impl<'p, P> PartialEq for Loc<'p, P>
where
P: ?Sized + PathLike + PartialEq,
P: PathLike<'p> + PartialEq,
{
fn eq(&self, other: &Self) -> bool { self.inner == other.inner }
}
impl<P> Eq for Loc<'_, P> where P: ?Sized + PathLike + Eq {}
impl<'p, P> Eq for Loc<'p, P> where P: PathLike<'p> + Eq {}
impl<'a, P> Loc<'a, P>
impl<'p, P> Loc<'p, P>
where
P: ?Sized + PathLike,
P: PathLike<'p>,
{
pub fn new<T, U>(path: &'a T, base: &U, trail: &U) -> Self
pub fn new<'a, T, U>(path: T, base: U, trail: U) -> Self
where
T: AsRef<P> + ?Sized,
U: AsRef<P> + ?Sized,
T: AsPathView<'p, P>,
U: AsPathView<'a, P::View<'a>>,
{
let mut loc = Self::from(path);
let mut loc = Self::bare(path);
loc.uri = loc.inner.strip_prefix(base).expect("Loc must start with the given base").len();
loc.urn = loc.inner.strip_prefix(trail).expect("Loc must start with the given trail").len();
loc
}
pub fn with<T>(path: &'a T, uri: usize, urn: usize) -> Result<Self>
pub fn with<T>(path: T, uri: usize, urn: usize) -> Result<Self>
where
T: ?Sized + AsRef<P>,
<P as PathLike>::Components<'a>: AsRef<P> + Clone + DoubleEndedIterator,
T: AsPathView<'p, P>,
{
if urn > uri {
bail!("URN cannot be longer than URI");
}
let mut loc = Self::from(path);
let mut loc = Self::bare(path);
if uri == 0 {
(loc.uri, loc.urn) = (0, 0);
return Ok(loc);
@ -143,21 +108,44 @@ where
Ok(loc)
}
pub fn zeroed<T>(path: &'a T) -> Self
pub fn bare<T>(path: T) -> Self
where
T: AsRef<P> + ?Sized,
T: AsPathView<'p, P>,
{
let mut loc = Self::from(path);
let path = path.as_path_view();
let Some(name) = path.file_name() else {
let uri = path.len();
return Self { inner: path, uri, urn: 0, _phantom: PhantomData };
};
let name_len = name.len();
let prefix_len =
unsafe { name.encoded_bytes().as_ptr().offset_from_unsigned(path.encoded_bytes().as_ptr()) };
let bytes = path.encoded_bytes();
Self {
inner: unsafe { P::from_encoded_bytes(&bytes[..prefix_len + name_len]) },
uri: name_len,
urn: name_len,
_phantom: PhantomData,
}
}
pub fn zeroed<T>(path: T) -> Self
where
T: AsPathView<'p, P>,
{
let mut loc = Self::bare(path);
(loc.uri, loc.urn) = (0, 0);
loc
}
pub fn floated<T, U>(path: &'a T, base: &U) -> Self
pub fn floated<'a, T, U>(path: T, base: U) -> Self
where
T: AsRef<P> + ?Sized,
U: AsRef<P> + ?Sized,
T: AsPathView<'p, P>,
U: AsPathView<'a, P::View<'a>>,
{
let mut loc = Self::from(path);
let mut loc = Self::bare(path);
loc.uri = loc.inner.strip_prefix(base).expect("Loc must start with the given base").len();
loc
}
@ -166,24 +154,24 @@ where
pub fn as_loc(self) -> Self { self }
#[inline]
pub fn as_path(self) -> &'a P { self.inner }
pub fn as_path(self) -> P { self.inner }
#[inline]
pub fn uri(self) -> &'a P {
pub fn uri(self) -> P {
unsafe {
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(self.inner.len() - self.uri..))
}
}
#[inline]
pub fn urn(self) -> &'a P {
pub fn urn(self) -> P {
unsafe {
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(self.inner.len() - self.urn..))
}
}
#[inline]
pub fn base(self) -> &'a P {
pub fn base(self) -> P {
unsafe {
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(..self.inner.len() - self.uri))
}
@ -193,7 +181,7 @@ where
pub fn has_base(self) -> bool { self.inner.len() != self.uri }
#[inline]
pub fn trail(self) -> &'a P {
pub fn trail(self) -> P {
unsafe {
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(..self.inner.len() - self.urn))
}
@ -203,19 +191,19 @@ where
pub fn has_trail(self) -> bool { self.inner.len() != self.urn }
#[inline]
pub fn name(self) -> Option<&'a P::Inner> { self.inner.file_name() }
pub fn name(self) -> Option<P::Inner> { self.inner.file_name() }
#[inline]
pub fn stem(self) -> Option<&'a P::Inner> { self.inner.file_stem() }
pub fn stem(self) -> Option<P::Inner> { self.inner.file_stem() }
#[inline]
pub fn ext(self) -> Option<&'a P::Inner> { self.inner.extension() }
pub fn ext(self) -> Option<P::Inner> { self.inner.extension() }
#[inline]
pub fn parent(self) -> Option<&'a P> { self.inner.parent() }
pub fn parent(self) -> Option<P> { self.inner.parent() }
#[inline]
pub fn triple(self) -> (&'a P, &'a P, &'a P) {
pub fn triple(self) -> (P, P, P) {
let len = self.inner.len();
let base = ..len - self.uri;
@ -232,9 +220,9 @@ where
}
#[inline]
pub fn strip_prefix<T>(self, base: T) -> Option<&'a P>
pub fn strip_prefix<'a, T>(self, base: T) -> Option<P>
where
T: AsRef<P>,
T: AsPathView<'a, P::View<'a>>,
{
self.inner.strip_prefix(base)
}

View file

@ -0,0 +1,45 @@
use std::{fmt::Debug, hash::Hash};
use crate::path::{AsInnerView, AsPathView, PathInner, PathLike};
pub trait PathBufLike
where
Self: Default + 'static,
{
type Inner: for<'a> AsInnerView<'a, Self::InnerRef<'a>>;
type InnerRef<'a>: PathInner<'a>;
type Borrowed<'a>: PathLike<'a> + AsPathView<'a, Self::Borrowed<'a>> + Debug + Hash;
fn encoded_bytes(&self) -> &[u8];
unsafe fn from_encoded_bytes(bytes: Vec<u8>) -> Self;
fn into_encoded_bytes(self) -> Vec<u8>;
fn len(&self) -> usize { self.encoded_bytes().len() }
fn set_file_name<T>(&mut self, name: T)
where
T: for<'a> AsInnerView<'a, Self::InnerRef<'a>>;
}
impl PathBufLike for std::path::PathBuf {
type Borrowed<'a> = &'a std::path::Path;
type Inner = std::ffi::OsString;
type InnerRef<'a> = &'a std::ffi::OsStr;
fn encoded_bytes(&self) -> &[u8] { self.as_os_str().as_encoded_bytes() }
unsafe fn from_encoded_bytes(bytes: Vec<u8>) -> Self {
Self::from(unsafe { Self::Inner::from_encoded_bytes_unchecked(bytes) })
}
fn into_encoded_bytes(self) -> Vec<u8> { self.into_os_string().into_encoded_bytes() }
fn set_file_name<T>(&mut self, name: T)
where
T: for<'a> AsInnerView<'a, Self::InnerRef<'a>>,
{
self.set_file_name(name.as_inner_view());
}
}

View file

View file

View file

@ -0,0 +1,9 @@
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum PathDyn<'p> {
Os(&'p std::path::Path),
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum PathBufDyn {
Os(std::path::PathBuf),
}

View file

@ -0,0 +1,13 @@
pub trait PathInner<'a>: Copy {
fn len(self) -> usize { self.encoded_bytes().len() }
fn encoded_bytes(self) -> &'a [u8];
}
impl<'a> PathInner<'a> for &'a std::ffi::OsStr {
fn encoded_bytes(self) -> &'a [u8] { self.as_encoded_bytes() }
}
impl<'a> PathInner<'a> for &'a [u8] {
fn encoded_bytes(self) -> &'a [u8] { self }
}

View file

@ -1 +1 @@
yazi_macro::mod_flat!(traits);
yazi_macro::mod_flat!(buf component components inner path r#dyn traits);

View file

@ -0,0 +1,81 @@
use crate::path::{AsPathView, PathBufLike, PathInner};
pub trait PathLike<'p>
where
Self: Copy + AsPathView<'p, Self::View<'p>>,
{
type Inner: PathInner<'p>;
type Owned: PathBufLike + Into<Self::Owned>;
type View<'a>;
type Components<'a>: AsPathView<'a, Self::View<'a>> + Clone + DoubleEndedIterator;
fn components(self) -> Self::Components<'p>;
fn default() -> Self;
fn encoded_bytes(self) -> &'p [u8];
fn extension(self) -> Option<Self::Inner>;
fn file_name(self) -> Option<Self::Inner>;
fn file_stem(self) -> Option<Self::Inner>;
unsafe fn from_encoded_bytes(bytes: &'p [u8]) -> Self;
#[cfg(unix)]
fn is_hidden(self) -> bool {
self.file_name().map_or(false, |n| n.encoded_bytes().get(0) == Some(&b'.'))
}
fn join<'a, T>(self, base: T) -> Self::Owned
where
T: AsPathView<'a, Self::View<'a>>;
fn len(self) -> usize { self.encoded_bytes().len() }
fn parent(self) -> Option<Self>;
fn strip_prefix<'a, T>(self, base: T) -> Option<Self>
where
T: AsPathView<'a, Self::View<'a>>;
}
impl<'p> PathLike<'p> for &'p std::path::Path {
type Components<'a> = std::path::Components<'a>;
type Inner = &'p std::ffi::OsStr;
type Owned = std::path::PathBuf;
type View<'a> = &'a std::path::Path;
fn components(self) -> Self::Components<'p> { self.components() }
fn default() -> Self { std::path::Path::new("") }
fn encoded_bytes(self) -> &'p [u8] { self.as_os_str().as_encoded_bytes() }
fn extension(self) -> Option<Self::Inner> { self.extension() }
fn file_name(self) -> Option<Self::Inner> { self.file_name() }
fn file_stem(self) -> Option<Self::Inner> { self.file_stem() }
unsafe fn from_encoded_bytes(bytes: &'p [u8]) -> Self {
std::path::Path::new(unsafe { std::ffi::OsStr::from_encoded_bytes_unchecked(bytes) })
}
fn join<'a, T>(self, base: T) -> Self::Owned
where
T: AsPathView<'a, Self::View<'a>>,
{
self.join(base.as_path_view())
}
fn parent(self) -> Option<Self> { self.parent() }
fn strip_prefix<'a, T>(self, base: T) -> Option<Self>
where
T: AsPathView<'a, Self::View<'a>>,
{
self.strip_prefix(base.as_path_view()).ok()
}
}

View file

@ -1,147 +1,90 @@
use std::{ffi::{OsStr, OsString}, path::{Path, PathBuf}};
use crate::path::PathLike;
pub trait AsPath {
fn as_path(&self) -> &(impl ?Sized + PathLike);
fn as_path(&self) -> impl PathLike<'_>;
}
pub trait PathLike: AsRef<Self> {
type Inner: ?Sized + PathInner;
type Owned: PathBufLike + Into<Self::Owned>;
type Components<'a>: AsRef<Self> + Clone + DoubleEndedIterator
where
Self: 'a;
fn components(&self) -> Self::Components<'_>;
fn default() -> &'static Self;
fn encoded_bytes(&self) -> &[u8];
fn extension(&self) -> Option<&Self::Inner>;
fn file_name(&self) -> Option<&Self::Inner>;
fn file_stem(&self) -> Option<&Self::Inner>;
unsafe fn from_encoded_bytes(bytes: &[u8]) -> &Self;
#[cfg(unix)]
fn is_hidden(&self) -> bool {
self.file_name().map_or(false, |n| n.encoded_bytes().get(0) == Some(&b'.'))
}
fn join<T>(&self, base: T) -> Self::Owned
where
T: AsRef<Self>;
fn len(&self) -> usize { self.encoded_bytes().len() }
fn parent(&self) -> Option<&Self>;
fn strip_prefix<T>(&self, base: T) -> Option<&Self>
where
T: AsRef<Self>;
impl AsPath for &std::ffi::OsStr {
fn as_path(&self) -> impl PathLike<'_> { std::path::Path::new(self) }
}
pub trait PathBufLike: AsRef<Self::Borrowed> + Default + 'static {
type Inner: AsRef<Self::InnerRef>;
type InnerRef: ?Sized + PathInner;
type Borrowed: ?Sized + PathLike + AsRef<Self::Borrowed>;
fn encoded_bytes(&self) -> &[u8];
unsafe fn from_encoded_bytes(bytes: Vec<u8>) -> Self;
fn into_encoded_bytes(self) -> Vec<u8>;
fn len(&self) -> usize { self.encoded_bytes().len() }
fn set_file_name<T>(&mut self, name: T)
where
T: AsRef<Self::InnerRef>;
impl AsPath for &std::path::Path {
fn as_path(&self) -> impl PathLike<'_> { *self }
}
pub trait PathInner {
fn len(&self) -> usize { self.encoded_bytes().len() }
fn encoded_bytes(&self) -> &[u8];
impl AsPath for std::path::PathBuf {
fn as_path(&self) -> impl PathLike<'_> { self.as_path() }
}
impl AsPath for &OsStr {
fn as_path(&self) -> &(impl ?Sized + PathLike) { Path::new(self) }
impl AsPath for &std::path::PathBuf {
fn as_path(&self) -> impl PathLike<'_> { (*self).as_path() }
}
impl AsPath for &Path {
fn as_path(&self) -> &(impl ?Sized + PathLike) { *self }
// --- AsPathView
pub trait AsPathView<'a, T> {
fn as_path_view(self) -> T;
}
impl AsPath for PathBuf {
fn as_path(&self) -> &(impl ?Sized + PathLike) { self.as_path() }
impl<'a> AsPathView<'a, &'a std::path::Path> for &'a str {
fn as_path_view(self) -> &'a std::path::Path { std::path::Path::new(self) }
}
impl AsPath for &PathBuf {
fn as_path(&self) -> &(impl ?Sized + PathLike) { (*self).as_path() }
impl<'a> AsPathView<'a, &'a std::path::Path> for &'a std::path::Path {
fn as_path_view(self) -> &'a std::path::Path { self }
}
impl PathLike for Path {
type Components<'a> = std::path::Components<'a>;
type Inner = OsStr;
type Owned = PathBuf;
impl<'a> AsPathView<'a, &'a std::path::Path> for &'a std::path::PathBuf {
fn as_path_view(self) -> &'a std::path::Path { self }
}
fn components(&self) -> Self::Components<'_> { self.components() }
impl<'a> AsPathView<'a, &'a std::path::Path> for std::path::Components<'a> {
fn as_path_view(self) -> &'a std::path::Path { self.as_path() }
}
fn default() -> &'static Self { Path::new("") }
fn encoded_bytes(&self) -> &[u8] { self.as_os_str().as_encoded_bytes() }
fn extension(&self) -> Option<&Self::Inner> { self.extension() }
fn file_name(&self) -> Option<&Self::Inner> { self.file_name() }
fn file_stem(&self) -> Option<&Self::Inner> { self.file_stem() }
unsafe fn from_encoded_bytes(bytes: &[u8]) -> &Self {
Self::new(unsafe { Self::Inner::from_encoded_bytes_unchecked(bytes) })
}
fn join<T>(&self, base: T) -> Self::Owned
where
T: AsRef<Self>,
{
self.join(base)
}
fn parent(&self) -> Option<&Self> { self.parent() }
fn strip_prefix<T>(&self, base: T) -> Option<&Self>
where
T: AsRef<Self>,
{
self.strip_prefix(base).ok()
impl<'a> AsPathView<'a, super::PathDyn<'a>> for &'a super::PathBufDyn {
fn as_path_view(self) -> super::PathDyn<'a> {
match self {
super::PathBufDyn::Os(p) => super::PathDyn::Os(p.as_path()),
}
}
}
impl PathBufLike for PathBuf {
type Borrowed = Path;
type Inner = OsString;
type InnerRef = OsStr;
fn encoded_bytes(&self) -> &[u8] { self.as_os_str().as_encoded_bytes() }
unsafe fn from_encoded_bytes(bytes: Vec<u8>) -> Self {
Self::from(unsafe { Self::Inner::from_encoded_bytes_unchecked(bytes) })
}
fn into_encoded_bytes(self) -> Vec<u8> { self.into_os_string().into_encoded_bytes() }
fn set_file_name<T>(&mut self, name: T)
where
T: AsRef<Self::InnerRef>,
{
self.set_file_name(name);
}
impl<'a> AsPathView<'a, &'a std::path::Path> for crate::loc::Loc<'a, &'a std::path::Path> {
fn as_path_view(self) -> &'a std::path::Path { *self }
}
impl PathInner for OsStr {
fn encoded_bytes(&self) -> &[u8] { self.as_encoded_bytes() }
// --- ToPathOwned
pub trait ToPathOwned<T> {
fn to_path_owned(&self) -> T;
}
impl ToPathOwned<std::path::PathBuf> for std::path::Path {
fn to_path_owned(&self) -> std::path::PathBuf { self.to_owned() }
}
impl<T, U> ToPathOwned<U> for &T
where
T: ?Sized + ToPathOwned<U>,
{
fn to_path_owned(&self) -> U { (*self).to_path_owned() }
}
// --- AsInnerView
pub trait AsInnerView<'a, T> {
fn as_inner_view(&'a self) -> T;
}
impl<'a> AsInnerView<'a, &'a std::ffi::OsStr> for std::ffi::OsStr {
fn as_inner_view(&'a self) -> &'a std::ffi::OsStr { self }
}
impl<'a> AsInnerView<'a, &'a std::ffi::OsStr> for std::ffi::OsString {
fn as_inner_view(&'a self) -> &'a std::ffi::OsStr { self }
}
impl<'a, T, U> AsInnerView<'a, U> for &T
where
T: ?Sized + AsInnerView<'a, U>,
{
fn as_inner_view(&'a self) -> U { (*self).as_inner_view() }
}

View file

@ -95,7 +95,7 @@ impl UrlBuf {
}
#[inline]
pub fn set_name(&mut self, name: impl AsRef<OsStr>) { self.loc.set_name(name); }
pub fn set_name(&mut self, name: impl AsRef<OsStr>) { self.loc.set_name(name.as_ref()); }
#[inline]
pub fn rebase(&self, base: &Path) -> Self {
@ -125,14 +125,14 @@ impl UrlBuf {
#[inline]
pub fn to_search(&self, domain: impl AsRef<str>) -> Self {
Self {
loc: LocBuf::zeroed(self.loc.to_path()),
loc: LocBuf::<PathBuf>::zeroed(self.loc.to_path()),
scheme: Scheme::Search(Pool::<str>::intern(domain)),
}
}
#[inline]
pub fn into_search(mut self, domain: impl AsRef<str>) -> Self {
self.loc = LocBuf::zeroed(self.loc.into_path());
self.loc = LocBuf::<PathBuf>::zeroed(self.loc.into_path());
self.scheme = Scheme::Search(Pool::<str>::intern(domain));
self
}

View file

@ -49,12 +49,14 @@ impl<'a> TryFrom<&'a [u8]> for UrlCow<'a> {
let (scheme, path, port) = Self::parse(value)?;
Ok(match (path, port) {
(Cow::Borrowed(p), None) => Self::Borrowed { loc: Loc::from(p), scheme },
(Cow::Borrowed(p), None) => Self::Borrowed { loc: Loc::bare(p), scheme },
(Cow::Borrowed(p), Some((uri, urn))) => {
Self::Borrowed { loc: Loc::with(p, uri, urn)?, scheme }
}
(Cow::Owned(p), None) => Self::Owned { loc: LocBuf::from(p), scheme },
(Cow::Owned(p), Some((uri, urn))) => Self::Owned { loc: LocBuf::with(p, uri, urn)?, scheme },
(Cow::Owned(p), Some((uri, urn))) => {
Self::Owned { loc: LocBuf::<PathBuf>::with(p, uri, urn)?, scheme }
}
})
}
}

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, ffi::OsStr, path::{Path, PathBuf}};
use crate::{scheme::{AsScheme, SchemeRef}, url::{Components, Display, Url, UrlBuf, UrlCow}};
use crate::{loc::Loc, scheme::{AsScheme, SchemeRef}, url::{Components, Display, Url, UrlBuf, UrlCow}};
// --- AsUrl
pub trait AsUrl {
@ -9,7 +9,7 @@ pub trait AsUrl {
impl AsUrl for Path {
#[inline]
fn as_url(&self) -> Url<'_> { Url { loc: self.into(), scheme: SchemeRef::Regular } }
fn as_url(&self) -> Url<'_> { Url { loc: Loc::bare(self), scheme: SchemeRef::Regular } }
}
impl AsUrl for &Path {

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::Path};
use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::{Path, PathBuf}};
use hashbrown::Equivalent;
@ -34,7 +34,7 @@ impl Debug for Url<'_> {
impl<'a> Url<'a> {
#[inline]
pub fn regular<T: AsRef<Path> + ?Sized>(path: &'a T) -> Self {
Self { loc: path.as_ref().into(), scheme: SchemeRef::Regular }
Self { loc: Loc::bare(path.as_ref()), scheme: SchemeRef::Regular }
}
#[inline]
@ -42,7 +42,7 @@ impl<'a> Url<'a> {
#[inline]
pub fn into_regular(self) -> Self {
Self { loc: self.loc.as_path().into(), scheme: SchemeRef::Regular }
Self { loc: Loc::bare(self.loc.as_path()), scheme: SchemeRef::Regular }
}
#[inline]
@ -71,8 +71,8 @@ impl<'a> Url<'a> {
let loc = match self.scheme {
S::Regular => join.into(),
S::Search(_) => LocBuf::new(join, self.loc.base(), self.loc.base()),
S::Archive(_) => LocBuf::floated(join, self.loc.base()),
S::Search(_) => LocBuf::<PathBuf>::new(join, self.loc.base(), self.loc.base()),
S::Archive(_) => LocBuf::<PathBuf>::floated(join, self.loc.base()),
S::Sftp(_) => join.into(),
};
@ -134,7 +134,7 @@ impl<'a> Url<'a> {
return None;
}
let loc: Loc = self.loc.base().into();
let loc = Loc::bare(self.loc.base());
Some(match self.scheme {
S::Regular => Self { loc, scheme: S::Regular },
S::Search(_) => Self { loc, scheme: self.scheme },
@ -151,11 +151,11 @@ impl<'a> Url<'a> {
Some(match self.scheme {
// Regular
S::Regular => Self { loc: parent.into(), scheme: S::Regular },
S::Regular => Self { loc: Loc::bare(parent), scheme: S::Regular },
// Search
S::Search(_) if uri.as_os_str().is_empty() => {
Self { loc: parent.into(), scheme: S::Regular }
Self { loc: Loc::bare(parent), scheme: S::Regular }
}
S::Search(_) => {
Self { loc: Loc::new(parent, self.loc.base(), self.loc.base()), scheme: self.scheme }
@ -163,7 +163,7 @@ impl<'a> Url<'a> {
// Archive
S::Archive(_) if uri.as_os_str().is_empty() => {
Self { loc: parent.into(), scheme: S::Regular }
Self { loc: Loc::bare(parent), scheme: S::Regular }
}
S::Archive(_) if uri.components().nth(1).is_none() => {
Self { loc: Loc::zeroed(parent), scheme: self.scheme }
@ -171,7 +171,7 @@ impl<'a> Url<'a> {
S::Archive(_) => Self { loc: Loc::floated(parent, self.loc.base()), scheme: self.scheme },
// SFTP
S::Sftp(_) => Self { loc: parent.into(), scheme: self.scheme },
S::Sftp(_) => Self { loc: Loc::bare(parent), scheme: self.scheme },
})
}