mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
perf: zero-copy UrlBuf to Url conversion (#3117)
This commit is contained in:
parent
dd7afaa64a
commit
8a0265ad64
30 changed files with 442 additions and 299 deletions
68
Cargo.lock
generated
68
Cargo.lock
generated
|
|
@ -243,9 +243,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.2"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
|
|
@ -382,9 +382,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.45"
|
||||
version = "4.5.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
|
||||
checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -392,9 +392,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.44"
|
||||
version = "4.5.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
|
||||
checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -895,6 +895,12 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
|
|
@ -1047,8 +1053,8 @@ dependencies = [
|
|||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-automata 0.4.10",
|
||||
"regex-syntax 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1069,7 +1075,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
|||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
"foldhash 0.1.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
@ -1132,9 +1138,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "image-webp"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b"
|
||||
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error",
|
||||
|
|
@ -1259,9 +1265,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.33"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"libc",
|
||||
|
|
@ -1967,9 +1973,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
|||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.38.2"
|
||||
version = "0.38.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d200a41a7797e6461bd04e4e95c3347053a731c32c87f066f2f0dda22dbdbba8"
|
||||
checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
@ -2158,14 +2164,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-automata 0.4.10",
|
||||
"regex-syntax 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2179,13 +2185,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-syntax 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2196,9 +2202,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
|
|
@ -2267,9 +2273,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
|||
|
||||
[[package]]
|
||||
name = "safe_arch"
|
||||
version = "0.7.4"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
|
||||
checksum = "3fb5032219cc30e5bb98749b19a18ceb2cf15e24ba8d517a7e64dff4f1f1eca5"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
|
@ -2519,7 +2525,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"onig",
|
||||
"plist",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-syntax 0.8.6",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
|
|
@ -3127,9 +3133,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wide"
|
||||
version = "0.7.33"
|
||||
version = "0.7.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03"
|
||||
checksum = "5a0ab08c041f0cbb00a12fd091b2877dcec2311f90f87a88391d4b0961ffb4fe"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"safe_arch",
|
||||
|
|
@ -3727,7 +3733,7 @@ dependencies = [
|
|||
"bitflags 2.9.3",
|
||||
"core-foundation-sys",
|
||||
"dirs",
|
||||
"foldhash",
|
||||
"foldhash 0.2.0",
|
||||
"futures",
|
||||
"hashbrown",
|
||||
"libc",
|
||||
|
|
@ -3859,7 +3865,7 @@ version = "25.6.11"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"crossterm 0.29.0",
|
||||
"foldhash",
|
||||
"foldhash 0.2.0",
|
||||
"futures",
|
||||
"hashbrown",
|
||||
"libc",
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ ansi-to-tui = "7.0.0"
|
|||
anyhow = "1.0.99"
|
||||
base64 = "0.22.1"
|
||||
bitflags = { version = "2.9.3", features = [ "serde" ] }
|
||||
clap = { version = "4.5.45", features = [ "derive" ] }
|
||||
clap = { version = "4.5.46", features = [ "derive" ] }
|
||||
core-foundation-sys = "0.8.7"
|
||||
crossterm = { version = "0.29.0", features = [ "event-stream" ] }
|
||||
dirs = "6.0.0"
|
||||
foldhash = "0.1.5"
|
||||
foldhash = "0.2.0"
|
||||
futures = "0.3.31"
|
||||
globset = "0.4.16"
|
||||
hashbrown = { version = "0.15.5", features = [ "serde" ] }
|
||||
|
|
@ -41,7 +41,7 @@ ordered-float = { version = "5.0.0", features = [ "serde" ] }
|
|||
parking_lot = "0.12.4"
|
||||
paste = "1.0.15"
|
||||
ratatui = { version = "0.29.0", features = [ "unstable-rendered-line-info" ] }
|
||||
regex = "1.11.1"
|
||||
regex = "1.11.2"
|
||||
scopeguard = "1.2.0"
|
||||
serde = { version = "1.0.219", features = [ "derive" ] }
|
||||
serde_json = "1.0.143"
|
||||
|
|
|
|||
56
README.md
56
README.md
|
|
@ -1,13 +1,13 @@
|
|||
<div align="center">
|
||||
<sup>Special thanks to:</sup>
|
||||
<br><br>
|
||||
<a href="https://www.warp.dev/?utm_source=github&utm_medium=referral&utm_campaign=yazi" target="_blank">
|
||||
<img alt="Warp sponsorship" width="300" src="https://github.com/user-attachments/assets/c7f141e7-9751-407d-bb0e-d6f2c487b34f">
|
||||
<br>
|
||||
<b>Warp, the intelligent terminal</b>
|
||||
<br>
|
||||
<sup>Yazi's AI-powered terminal of choice!<br>Available for macOS, Linux and Windows</sup>
|
||||
</a>
|
||||
<a href="https://go.warp.dev/yazi" target="_blank">
|
||||
<sup>Special thanks to:</sup>
|
||||
<br>
|
||||
<img alt="Warp sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-02.png">
|
||||
<br>
|
||||
<h>Warp, built for coding with multiple AI agents</b>
|
||||
<br>
|
||||
<sup>Available for macOS, Linux and Windows</sup>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
|
@ -52,25 +52,25 @@ Yazi is currently in heavy development, expect breaking changes.
|
|||
|
||||
## Image Preview
|
||||
|
||||
| Platform | Protocol | Support |
|
||||
| ---------------------------------------------------------------------------- | -------------------------------------- | ----------------------------------------------------- |
|
||||
| [kitty](https://github.com/kovidgoyal/kitty) (>= 0.28.0) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [iTerm2](https://iterm2.com) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [WezTerm](https://github.com/wez/wezterm) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Konsole](https://invent.kde.org/utilities/konsole) | [Kitty old protocol][kgp-old] | ✅ Built-in |
|
||||
| [foot](https://codeberg.org/dnkl/foot) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Ghostty](https://github.com/ghostty-org/ghostty) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [Windows Terminal](https://github.com/microsoft/terminal) (>= v1.22.10352.0) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [st with Sixel patch](https://github.com/bakkeby/st-flexipatch) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Warp](https://www.warp.dev) (macOS/Linux only) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Tabby](https://github.com/Eugeny/tabby) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [VSCode](https://github.com/microsoft/vscode) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Rio](https://github.com/raphamorim/rio) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Black Box](https://gitlab.gnome.org/raggesilver/blackbox) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Hyper](https://github.com/vercel/hyper) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Bobcat](https://github.com/ismail-yilmaz/Bobcat) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| X11 / Wayland | Window system protocol | ☑️ [Überzug++][ueberzug] required |
|
||||
| Fallback | [ASCII art (Unicode block)][ascii-art] | ☑️ [Chafa][chafa] required |
|
||||
| Platform | Protocol | Support |
|
||||
| ---------------------------------------------------------------------------- | -------------------------------------- | --------------------------------- |
|
||||
| [kitty](https://github.com/kovidgoyal/kitty) (>= 0.28.0) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [iTerm2](https://iterm2.com) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [WezTerm](https://github.com/wez/wezterm) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Konsole](https://invent.kde.org/utilities/konsole) | [Kitty old protocol][kgp-old] | ✅ Built-in |
|
||||
| [foot](https://codeberg.org/dnkl/foot) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Ghostty](https://github.com/ghostty-org/ghostty) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [Windows Terminal](https://github.com/microsoft/terminal) (>= v1.22.10352.0) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [st with Sixel patch](https://github.com/bakkeby/st-flexipatch) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Warp](https://www.warp.dev) (macOS/Linux only) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Tabby](https://github.com/Eugeny/tabby) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [VSCode](https://github.com/microsoft/vscode) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Rio](https://github.com/raphamorim/rio) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Black Box](https://gitlab.gnome.org/raggesilver/blackbox) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Hyper](https://github.com/vercel/hyper) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Bobcat](https://github.com/ismail-yilmaz/Bobcat) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| X11 / Wayland | Window system protocol | ☑️ [Überzug++][ueberzug] required |
|
||||
| Fallback | [ASCII art (Unicode block)][ascii-art] | ☑️ [Chafa][chafa] required |
|
||||
|
||||
See https://yazi-rs.github.io/docs/image-preview for details.
|
||||
|
||||
|
|
|
|||
12
flake.lock
generated
12
flake.lock
generated
|
|
@ -20,11 +20,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1752596105,
|
||||
"narHash": "sha256-lFNVsu/mHLq3q11MuGkMhUUoSXEdQjCHvpReaGP1S2k=",
|
||||
"lastModified": 1756288264,
|
||||
"narHash": "sha256-Om8adB1lfkU7D33VpR+/haZ2gI5r3Q+ZbIPzE5sYnwE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "dab3a6e781554f965bde3def0aa2fda4eb8f1708",
|
||||
"rev": "ddd1826f294a0ee5fdc198ab72c8306a0ea73aa9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -48,11 +48,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752633862,
|
||||
"narHash": "sha256-Bj7ozT1+5P7NmvDcuAXJvj56txcXuAhk3Vd9FdWFQzk=",
|
||||
"lastModified": 1756348497,
|
||||
"narHash": "sha256-xJp3VnoYh4kpsaKFO/7SsGbwOz7pI1ZmjbqpXEuR2cw=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "8668ca94858206ac3db0860a9dec471de0d995f8",
|
||||
"rev": "0adf92c70d23fb4f703aea5d3ebb51ac65994f7f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
|
|
@ -79,8 +79,10 @@ impl Trigger {
|
|||
const SEP: char = std::path::MAIN_SEPARATOR;
|
||||
|
||||
Some(match path.as_os_str().rsplit_once(SEP) {
|
||||
Some((p, c)) if p.is_empty() => (UrlBuf { loc: MAIN_SEPARATOR_STR.into(), scheme }, c.into()),
|
||||
Some((p, c)) => (expand_url(UrlBuf { loc: p.into(), scheme }), c.into()),
|
||||
Some((p, c)) if p.is_empty() => {
|
||||
(UrlBuf { loc: MAIN_SEPARATOR_STR.into(), scheme: scheme.into() }, c.into())
|
||||
}
|
||||
Some((p, c)) => (expand_url(UrlBuf { loc: p.into(), scheme: scheme.into() }), c.into()),
|
||||
None => (CWD.load().as_ref().clone(), path.into()),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ impl Actor for Cd {
|
|||
|
||||
// Parent
|
||||
if let Some(parent) = opt.target.parent() {
|
||||
tab.parent = Some(tab.history.remove_or(&parent));
|
||||
tab.parent = Some(tab.history.remove_or(parent));
|
||||
}
|
||||
|
||||
err!(Pubsub::pub_after_cd(tab.id, tab.cwd()));
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ impl Create {
|
|||
FilesOp::Deleting(parent.into(), [urn.into()].into()).emit();
|
||||
provider::create(&new).await?;
|
||||
} else if let Some(parent) = new.parent() {
|
||||
provider::create_dir_all(&parent).await.ok();
|
||||
provider::create_dir_all(parent).await.ok();
|
||||
ok_or_not_found(provider::remove_file(&new).await)?;
|
||||
provider::create(&new).await?;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl Actor for Reveal {
|
|||
let Some((parent, child)) = opt.target.pair() else { succ!() };
|
||||
|
||||
// Cd to the parent directory
|
||||
act!(mgr:cd, cx, (parent.clone(), opt.source))?;
|
||||
act!(mgr:cd, cx, (parent, opt.source))?;
|
||||
|
||||
// Try to hover on the child file
|
||||
let tab = cx.tab_mut();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ impl<'a> From<&'a Url> for yazi_shared::url::Url<'a> {
|
|||
}
|
||||
|
||||
impl<'a> From<&'a Url> for UrlCow<'a> {
|
||||
fn from(value: &'a Url) -> Self { UrlCow::Borrowed(value.as_url()) }
|
||||
fn from(value: &'a Url) -> Self {
|
||||
UrlCow::Borrowed { loc: value.loc.as_loc(), scheme: value.scheme.as_ref().into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Url> for yazi_shared::url::UrlBufCov {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
|||
use anyhow::Result;
|
||||
use globset::GlobBuilder;
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::url::{Scheme, UrlBuf};
|
||||
use yazi_shared::{scheme::{SchemeCow, SchemeRef}, url::UrlBuf};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(try_from = "String")]
|
||||
|
|
@ -108,14 +108,16 @@ impl PatternScheme {
|
|||
};
|
||||
|
||||
if protocol != "*" {
|
||||
me.0 = Some(Scheme::parse_kind(protocol.as_bytes())?);
|
||||
me.0 = Some(SchemeCow::parse_kind(protocol.as_bytes())?);
|
||||
}
|
||||
|
||||
Ok((me, protocol.len() + 3))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn matches(&self, scheme: &Scheme) -> bool { self.0.is_none_or(|s| s == scheme.kind()) }
|
||||
fn matches<'a>(&self, scheme: impl Into<SchemeRef<'a>>) -> bool {
|
||||
self.0.is_none_or(|s| s == scheme.into().kind())
|
||||
}
|
||||
}
|
||||
|
||||
// --- Tests
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl Selected {
|
|||
let mut parent = urls[0].parent();
|
||||
let mut parents = vec![];
|
||||
while let Some(u) = parent {
|
||||
if self.inner.contains_key(&UrlCov::new(&u)) {
|
||||
if self.inner.contains_key(&UrlCov::new(u)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -117,11 +117,11 @@ impl Selected {
|
|||
// FIXME: use UrlCov::parent() instead
|
||||
let mut parent = first.parent();
|
||||
while let Some(u) = parent {
|
||||
let n = self.parents.get_mut(&UrlCov::new(&u)).unwrap();
|
||||
let n = self.parents.get_mut(&UrlCov::new(u)).unwrap();
|
||||
|
||||
*n -= count;
|
||||
if *n == 0 {
|
||||
self.parents.remove(&UrlCov::new(&u));
|
||||
self.parents.remove(&UrlCov::new(u));
|
||||
}
|
||||
|
||||
parent = u.parent();
|
||||
|
|
@ -147,14 +147,14 @@ impl Selected {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use yazi_shared::url::UrlCow;
|
||||
use yazi_shared::{scheme::SchemeCow, url::UrlCow};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn url(s: &str) -> Url<'_> {
|
||||
match UrlCow::try_from(s).unwrap() {
|
||||
UrlCow::Borrowed(url) => url,
|
||||
UrlCow::Owned(_) => unreachable!(),
|
||||
UrlCow::Borrowed { loc, scheme: SchemeCow::Borrowed(scheme) } => Url { loc, scheme },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -275,16 +275,16 @@ mod tests {
|
|||
let child1 = url("/parent/child1");
|
||||
let child2 = url("/parent/child2");
|
||||
let child3 = url("/parent/child3");
|
||||
assert_eq!(3, s.add_same([&child1, &child2, &child3]));
|
||||
assert_eq!(3, s.add_same([child1, child2, child3]));
|
||||
|
||||
assert!(s.remove(&child1));
|
||||
assert!(s.remove(child1));
|
||||
assert_eq!(s.inner.len(), 2);
|
||||
assert!(!s.parents.is_empty());
|
||||
|
||||
assert!(s.remove(&child2));
|
||||
assert!(s.remove(child2));
|
||||
assert!(!s.parents.is_empty());
|
||||
|
||||
assert!(s.remove(&child3));
|
||||
assert!(s.remove(child3));
|
||||
assert!(s.inner.is_empty());
|
||||
assert!(s.parents.is_empty());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ pub fn max_common_root(urls: &[UrlBuf]) -> usize {
|
|||
.components()
|
||||
.zip(parent.components())
|
||||
.take_while(|(a, b)| match (a, b) {
|
||||
(Component::Scheme(a), Component::Scheme(b)) => a.covariant(b),
|
||||
(Component::Scheme(a), Component::Scheme(b)) => a.covariant(*b),
|
||||
(a, b) => a == b,
|
||||
})
|
||||
.count()
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ pub fn clean_url<'a>(url: impl Into<UrlCow<'a>>) -> UrlBuf {
|
|||
clean_path_impl(&cow.loc(), cow.loc().base().count(), cow.loc().trail().count());
|
||||
|
||||
let loc = LocBuf::with(path, uri, urn).expect("Failed to create Loc from cleaned path");
|
||||
match cow {
|
||||
UrlCow::Borrowed(u) => UrlBuf { loc, scheme: u.scheme.clone() },
|
||||
UrlCow::Owned(u) => UrlBuf { loc, scheme: u.scheme },
|
||||
}
|
||||
UrlBuf { loc, scheme: cow.into_scheme().into() }
|
||||
}
|
||||
|
||||
fn clean_path_impl(path: &Path, base: usize, trail: usize) -> (PathBuf, usize, usize) {
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ fn expand_url_impl<'a>(url: Url<'a>) -> UrlCow<'a> {
|
|||
)
|
||||
.expect("Failed to create Loc from expanded path");
|
||||
|
||||
let url = UrlBuf { loc, scheme: url.scheme.clone() };
|
||||
let url = UrlBuf { loc, scheme: url.scheme.into() };
|
||||
match absolute_url(url.as_url()) {
|
||||
UrlCow::Borrowed(_) => url.into(),
|
||||
UrlCow::Owned(u) => u.into(),
|
||||
UrlCow::Borrowed { .. } => url.into(),
|
||||
c @ UrlCow::Owned { .. } => c.into_owned().into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ fn absolute_url<'a>(url: Url<'a>) -> UrlCow<'a> {
|
|||
if url.has_trail() { 0 } else { 2 },
|
||||
)
|
||||
.expect("Failed to create Loc from drive letter");
|
||||
UrlBuf { loc, scheme: url.scheme.clone() }.into()
|
||||
UrlBuf { loc, scheme: url.scheme.into() }.into()
|
||||
} else if local
|
||||
&& let Ok(rest) = url.loc.strip_prefix("~/")
|
||||
&& let Some(home) = dirs::home_dir()
|
||||
|
|
@ -86,7 +86,7 @@ fn absolute_url<'a>(url: Url<'a>) -> UrlCow<'a> {
|
|||
url.urn().count() + if url.has_trail() { 0 } else { add },
|
||||
)
|
||||
.expect("Failed to create Loc from home directory");
|
||||
UrlBuf { loc, scheme: url.scheme.clone() }.into()
|
||||
UrlBuf { loc, scheme: url.scheme.into() }.into()
|
||||
} else if !url.is_absolute() {
|
||||
let cwd = CWD.load();
|
||||
let loc = LocBuf::with(cwd.loc.join(url.loc), url.uri().count(), url.urn().count())
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ pub fn path_relative_to<'a>(
|
|||
to: &'a impl AsRef<Path>,
|
||||
) -> Result<Cow<'a, Path>> {
|
||||
Ok(match url_relative_to(Url::regular(&from).into(), Url::regular(to).into())? {
|
||||
UrlCow::Borrowed(url) => Cow::Borrowed(url.loc.as_path()),
|
||||
UrlCow::Owned(url) => Cow::Owned(url.loc.into_path()),
|
||||
UrlCow::Borrowed { loc, .. } => Cow::Borrowed(loc.as_path()),
|
||||
UrlCow::Owned { loc, .. } => Cow::Owned(loc.into_path()),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -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().clone() }.into());
|
||||
return Ok(UrlBuf { loc: LocBuf::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().clone() }.into())
|
||||
Ok(UrlBuf { loc: LocBuf::zeroed(buf), scheme: to.scheme().into() }.into())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ impl File {
|
|||
};
|
||||
|
||||
let src = if task.relative {
|
||||
path_relative_to(provider::canonicalize(&task.to.parent().unwrap()).await?.loc, &src)?
|
||||
path_relative_to(provider::canonicalize(task.to.parent().unwrap()).await?.loc, &src)?
|
||||
} else {
|
||||
src
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::option_map_unit_fn)]
|
||||
|
||||
yazi_macro::mod_pub!(errors event loc pool shell translit url);
|
||||
yazi_macro::mod_pub!(errors event loc pool shell translit url scheme);
|
||||
|
||||
yazi_macro::mod_flat!(alias bytes chars condition debounce either env id layer natsort os osstr rand ro_cell source string sync_cell terminal tests throttle time utf8);
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,14 @@ impl<T: ?Sized> PartialEq for Symbol<T> {
|
|||
|
||||
impl<T: ?Sized> Eq for Symbol<T> {}
|
||||
|
||||
impl PartialEq<str> for Symbol<str> {
|
||||
fn eq(&self, other: &str) -> bool { self.as_ref() == other }
|
||||
}
|
||||
|
||||
impl PartialEq<[u8]> for Symbol<[u8]> {
|
||||
fn eq(&self, other: &[u8]) -> bool { self.as_ref() == other }
|
||||
}
|
||||
|
||||
// --- Hash
|
||||
impl<T: ?Sized> Hash for Symbol<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) { self.ptr.as_ptr().hash(state); }
|
||||
|
|
|
|||
|
|
@ -3,45 +3,75 @@ use std::{borrow::Cow, ops::Not, path::Path};
|
|||
use anyhow::{Result, bail, ensure};
|
||||
use percent_encoding::percent_decode;
|
||||
|
||||
use crate::{BytesExt, pool::{InternStr, Symbol}};
|
||||
use crate::{BytesExt, pool::InternStr, scheme::{Scheme, SchemeRef}};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum Scheme {
|
||||
#[default]
|
||||
Regular,
|
||||
|
||||
Search(Symbol<str>),
|
||||
|
||||
Archive(Symbol<str>),
|
||||
|
||||
Sftp(Symbol<str>),
|
||||
#[derive(Debug)]
|
||||
pub enum SchemeCow<'a> {
|
||||
Borrowed(SchemeRef<'a>),
|
||||
Owned(Scheme),
|
||||
}
|
||||
|
||||
impl Scheme {
|
||||
#[inline]
|
||||
pub const fn kind(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Regular => "regular",
|
||||
Self::Search(_) => "search",
|
||||
Self::Archive(_) => "archive",
|
||||
Self::Sftp(_) => "sftp",
|
||||
impl Default for SchemeCow<'_> {
|
||||
fn default() -> Self { Self::Borrowed(SchemeRef::Regular) }
|
||||
}
|
||||
|
||||
impl From<Scheme> for SchemeCow<'_> {
|
||||
fn from(value: Scheme) -> Self { Self::Owned(value) }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Scheme> for SchemeCow<'a> {
|
||||
fn from(value: &'a Scheme) -> Self { Self::Borrowed(value.as_ref()) }
|
||||
}
|
||||
|
||||
impl<'a> From<SchemeRef<'a>> for SchemeCow<'a> {
|
||||
fn from(value: SchemeRef<'a>) -> Self { Self::Borrowed(value) }
|
||||
}
|
||||
|
||||
impl From<SchemeCow<'_>> for Scheme {
|
||||
fn from(value: SchemeCow<'_>) -> Self {
|
||||
match value {
|
||||
SchemeCow::Borrowed(s) => s.into(),
|
||||
SchemeCow::Owned(s) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SchemeCow<'a> {
|
||||
pub fn search(domain: impl Into<Cow<'a, str>>) -> Self {
|
||||
match domain.into() {
|
||||
Cow::Borrowed(s) => SchemeRef::Search(s).into(),
|
||||
Cow::Owned(s) => Scheme::Search(s.intern()).into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn archive(domain: impl Into<Cow<'a, str>>) -> Self {
|
||||
match domain.into() {
|
||||
Cow::Borrowed(s) => SchemeRef::Archive(s).into(),
|
||||
Cow::Owned(s) => Scheme::Archive(s.intern()).into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sftp(domain: impl Into<Cow<'a, str>>) -> Self {
|
||||
match domain.into() {
|
||||
Cow::Borrowed(s) => SchemeRef::Sftp(s).into(),
|
||||
Cow::Owned(s) => Scheme::Sftp(s.intern()).into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn domain(&self) -> Option<&str> {
|
||||
pub fn as_ref(&self) -> SchemeRef<'_> {
|
||||
match self {
|
||||
Self::Regular => None,
|
||||
Self::Search(s) | Self::Archive(s) | Self::Sftp(s) => Some(s),
|
||||
Self::Borrowed(s) => *s,
|
||||
Self::Owned(s) => s.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parse(
|
||||
bytes: &[u8],
|
||||
pub(crate) fn parse(
|
||||
bytes: &'a [u8],
|
||||
skip: &mut usize,
|
||||
) -> Result<(Self, bool, Option<usize>, Option<usize>)> {
|
||||
let Some((mut protocol, rest)) = bytes.split_by_seq(b"://") else {
|
||||
return Ok((Self::Regular, false, None, None));
|
||||
return Ok((Self::default(), false, None, None));
|
||||
};
|
||||
|
||||
// Advance to the beginning of the path
|
||||
|
|
@ -54,18 +84,18 @@ impl Scheme {
|
|||
}
|
||||
|
||||
let (scheme, uri, urn) = match protocol {
|
||||
b"regular" => (Self::Regular, None, None),
|
||||
b"regular" => (Self::default(), None, None),
|
||||
b"search" => {
|
||||
let (domain, uri, urn) = Self::decode_param(rest, skip)?;
|
||||
(Self::Search(domain), uri, urn)
|
||||
(Self::search(domain), uri, urn)
|
||||
}
|
||||
b"archive" => {
|
||||
let (domain, uri, urn) = Self::decode_param(rest, skip)?;
|
||||
(Self::Archive(domain), uri, urn)
|
||||
(Self::archive(domain), uri, urn)
|
||||
}
|
||||
b"sftp" => {
|
||||
let (domain, uri, urn) = Self::decode_param(rest, skip)?;
|
||||
(Self::Sftp(domain), uri, urn)
|
||||
(Self::sftp(domain), uri, urn)
|
||||
}
|
||||
_ => bail!("Could not parse protocol from URL: {}", String::from_utf8_lossy(bytes)),
|
||||
};
|
||||
|
|
@ -84,31 +114,18 @@ impl Scheme {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn covariant(&self, other: &Self) -> bool {
|
||||
if self.is_virtual() || other.is_virtual() { self == other } else { true }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_virtual(&self) -> bool {
|
||||
match self {
|
||||
Self::Regular | Self::Search(_) => false,
|
||||
Self::Archive(_) | Self::Sftp(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_param(
|
||||
bytes: &[u8],
|
||||
bytes: &'a [u8],
|
||||
skip: &mut usize,
|
||||
) -> Result<(Symbol<str>, Option<usize>, Option<usize>)> {
|
||||
) -> Result<(Cow<'a, str>, Option<usize>, Option<usize>)> {
|
||||
let mut len = bytes.iter().copied().take_while(|&b| b != b'/').count();
|
||||
let slash = bytes.get(len).is_some_and(|&b| b == b'/');
|
||||
*skip += len + slash as usize;
|
||||
|
||||
let (uri, urn) = Self::decode_ports(&bytes[..len], &mut len)?;
|
||||
let domain = match Cow::from(percent_decode(&bytes[..len])) {
|
||||
Cow::Borrowed(b) => str::from_utf8(b)?.intern(),
|
||||
Cow::Owned(b) => String::from_utf8(b)?.intern(),
|
||||
Cow::Borrowed(b) => str::from_utf8(b)?.into(),
|
||||
Cow::Owned(b) => String::from_utf8(b)?.into(),
|
||||
};
|
||||
|
||||
Ok((domain, uri, urn))
|
||||
|
|
@ -131,24 +148,24 @@ impl Scheme {
|
|||
Ok((b, a))
|
||||
}
|
||||
|
||||
pub(super) fn normalize_ports(
|
||||
pub(crate) fn normalize_ports(
|
||||
&self,
|
||||
uri: Option<usize>,
|
||||
urn: Option<usize>,
|
||||
path: &Path,
|
||||
) -> Result<Option<(usize, usize)>> {
|
||||
Ok(match self {
|
||||
Scheme::Regular => {
|
||||
Ok(match self.as_ref() {
|
||||
SchemeRef::Regular => {
|
||||
ensure!(uri.is_none() && urn.is_none(), "Regular scheme cannot have ports");
|
||||
None
|
||||
}
|
||||
Scheme::Search(_) => {
|
||||
SchemeRef::Search(_) => {
|
||||
let (uri, urn) = (uri.unwrap_or(0), urn.unwrap_or(0));
|
||||
ensure!(uri == urn, "Search scheme requires URI and URN to be equal");
|
||||
Some((uri, urn))
|
||||
}
|
||||
Scheme::Archive(_) => Some((uri.unwrap_or(0), urn.unwrap_or(0))),
|
||||
Scheme::Sftp(_) => {
|
||||
SchemeRef::Archive(_) => Some((uri.unwrap_or(0), urn.unwrap_or(0))),
|
||||
SchemeRef::Sftp(_) => {
|
||||
let uri = uri.unwrap_or(path.as_os_str().is_empty().not() as usize);
|
||||
let urn = urn.unwrap_or(path.file_name().is_some() as usize);
|
||||
Some((uri, urn))
|
||||
|
|
@ -157,6 +174,14 @@ impl Scheme {
|
|||
}
|
||||
}
|
||||
|
||||
impl SchemeCow<'_> {
|
||||
#[inline]
|
||||
pub fn is_virtual(&self) -> bool { self.as_ref().is_virtual() }
|
||||
|
||||
#[inline]
|
||||
pub fn into_owned(self) -> Scheme { self.into() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -165,7 +190,7 @@ mod tests {
|
|||
fn test_decode_ports() -> Result<()> {
|
||||
fn assert(s: &str, len: usize, uri: Option<usize>, urn: Option<usize>) -> Result<()> {
|
||||
let mut n = usize::MAX;
|
||||
let port = Scheme::decode_ports(s.as_bytes(), &mut n)?;
|
||||
let port = SchemeCow::decode_ports(s.as_bytes(), &mut n)?;
|
||||
assert_eq!((usize::MAX - n, port.0, port.1), (len, uri, urn));
|
||||
Ok(())
|
||||
}
|
||||
1
yazi-shared/src/scheme/mod.rs
Normal file
1
yazi-shared/src/scheme/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(cow r#ref scheme);
|
||||
69
yazi-shared/src/scheme/ref.rs
Normal file
69
yazi-shared/src/scheme/ref.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
use crate::{pool::InternStr, scheme::Scheme};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub enum SchemeRef<'a> {
|
||||
#[default]
|
||||
Regular,
|
||||
|
||||
Search(&'a str),
|
||||
|
||||
Archive(&'a str),
|
||||
|
||||
Sftp(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Scheme> for SchemeRef<'a> {
|
||||
fn from(value: &'a Scheme) -> Self {
|
||||
match value {
|
||||
Scheme::Regular => Self::Regular,
|
||||
Scheme::Search(d) => Self::Search(d),
|
||||
Scheme::Archive(d) => Self::Archive(d),
|
||||
Scheme::Sftp(d) => Self::Sftp(d),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SchemeRef<'_>> for Scheme {
|
||||
fn from(value: SchemeRef) -> Self {
|
||||
match value {
|
||||
SchemeRef::Regular => Self::Regular,
|
||||
SchemeRef::Search(d) => Self::Search(d.intern()),
|
||||
SchemeRef::Archive(d) => Self::Archive(d.intern()),
|
||||
SchemeRef::Sftp(d) => Self::Sftp(d.intern()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SchemeRef<'a> {
|
||||
#[inline]
|
||||
pub const fn kind(self) -> &'static str {
|
||||
match self {
|
||||
Self::Regular => "regular",
|
||||
Self::Search(_) => "search",
|
||||
Self::Archive(_) => "archive",
|
||||
Self::Sftp(_) => "sftp",
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn domain(self) -> Option<&'a str> {
|
||||
match self {
|
||||
Self::Regular => None,
|
||||
Self::Search(s) | Self::Archive(s) | Self::Sftp(s) => Some(s),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn covariant(self, other: impl Into<Self>) -> bool {
|
||||
let other = other.into();
|
||||
if self.is_virtual() || other.is_virtual() { self == other } else { true }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_virtual(&self) -> bool {
|
||||
match self {
|
||||
Self::Regular | Self::Search(_) => false,
|
||||
Self::Archive(_) | Self::Sftp(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
36
yazi-shared/src/scheme/scheme.rs
Normal file
36
yazi-shared/src/scheme/scheme.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use crate::{pool::Symbol, scheme::SchemeRef};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub enum Scheme {
|
||||
#[default]
|
||||
Regular,
|
||||
|
||||
Search(Symbol<str>),
|
||||
|
||||
Archive(Symbol<str>),
|
||||
|
||||
Sftp(Symbol<str>),
|
||||
}
|
||||
|
||||
impl Hash for Scheme {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) { self.as_ref().hash(state); }
|
||||
}
|
||||
|
||||
impl Scheme {
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> SchemeRef<'_> { self.into() }
|
||||
|
||||
#[inline]
|
||||
pub fn kind(&self) -> &'static str { self.as_ref().kind() }
|
||||
|
||||
#[inline]
|
||||
pub fn domain(&self) -> Option<&str> { self.as_ref().domain() }
|
||||
|
||||
#[inline]
|
||||
pub fn covariant(&self, other: &Self) -> bool { self.as_ref().covariant(other) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_virtual(&self) -> bool { self.as_ref().is_virtual() }
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, hash::BuildHasher, p
|
|||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{loc::LocBuf, pool::Pool, url::{Components, Display, Encode, EncodeTilded, Scheme, Uri, Url, UrlCow, Urn}};
|
||||
use crate::{loc::LocBuf, pool::Pool, scheme::{Scheme, SchemeRef}, url::{Components, Display, Encode, EncodeTilded, Uri, Url, UrlCow, Urn}};
|
||||
|
||||
#[derive(Clone, Default, Eq, Ord, PartialOrd, PartialEq, Hash)]
|
||||
#[derive(Clone, Default, Eq, Hash, PartialEq)]
|
||||
pub struct UrlBuf {
|
||||
pub loc: LocBuf,
|
||||
pub scheme: Scheme,
|
||||
|
|
@ -20,11 +20,11 @@ impl From<PathBuf> for UrlBuf {
|
|||
}
|
||||
|
||||
impl From<&Url<'_>> for UrlBuf {
|
||||
fn from(url: &Url<'_>) -> Self { Self { loc: url.loc.into(), scheme: url.scheme.clone() } }
|
||||
fn from(url: &Url<'_>) -> Self { Self { loc: url.loc.into(), scheme: url.scheme.into() } }
|
||||
}
|
||||
|
||||
impl From<Url<'_>> for UrlBuf {
|
||||
fn from(url: Url<'_>) -> Self { Self { loc: url.loc.into(), scheme: url.scheme } }
|
||||
fn from(url: Url<'_>) -> Self { Self { loc: url.loc.into(), scheme: url.scheme.into() } }
|
||||
}
|
||||
|
||||
impl From<&UrlBuf> for UrlBuf {
|
||||
|
|
@ -107,34 +107,35 @@ impl UrlBuf {
|
|||
|
||||
pub fn strip_prefix<'a>(&self, base: impl Into<Url<'a>>) -> Option<&Urn> {
|
||||
use Scheme as S;
|
||||
use SchemeRef as T;
|
||||
|
||||
let base = base.into();
|
||||
let prefix = self.loc.strip_prefix(base.loc).ok()?;
|
||||
|
||||
Some(Urn::new(match (&self.scheme, &base.scheme) {
|
||||
Some(Urn::new(match (&self.scheme, base.scheme) {
|
||||
// Same scheme
|
||||
(S::Regular, S::Regular) => Some(prefix),
|
||||
(S::Search(_), S::Search(_)) => Some(prefix),
|
||||
(S::Archive(a), S::Archive(b)) => Some(prefix).filter(|_| a == b),
|
||||
(S::Sftp(a), S::Sftp(b)) => Some(prefix).filter(|_| a == b),
|
||||
(S::Regular, T::Regular) => Some(prefix),
|
||||
(S::Search(_), T::Search(_)) => Some(prefix),
|
||||
(S::Archive(a), T::Archive(b)) => Some(prefix).filter(|_| a == b),
|
||||
(S::Sftp(a), T::Sftp(b)) => Some(prefix).filter(|_| a == b),
|
||||
|
||||
// Both are local files
|
||||
(S::Regular, S::Search(_)) => Some(prefix),
|
||||
(S::Search(_), S::Regular) => Some(prefix),
|
||||
(S::Regular, T::Search(_)) => Some(prefix),
|
||||
(S::Search(_), T::Regular) => Some(prefix),
|
||||
|
||||
// Only the entry of archives is a local file
|
||||
(S::Regular, S::Archive(_)) => Some(prefix).filter(|_| base.uri().is_empty()),
|
||||
(S::Search(_), S::Archive(_)) => Some(prefix).filter(|_| base.uri().is_empty()),
|
||||
(S::Archive(_), S::Regular) => Some(prefix).filter(|_| self.uri().is_empty()),
|
||||
(S::Archive(_), S::Search(_)) => Some(prefix).filter(|_| self.uri().is_empty()),
|
||||
(S::Regular, T::Archive(_)) => Some(prefix).filter(|_| base.uri().is_empty()),
|
||||
(S::Search(_), T::Archive(_)) => Some(prefix).filter(|_| base.uri().is_empty()),
|
||||
(S::Archive(_), T::Regular) => Some(prefix).filter(|_| self.uri().is_empty()),
|
||||
(S::Archive(_), T::Search(_)) => Some(prefix).filter(|_| self.uri().is_empty()),
|
||||
|
||||
// Independent virtual file space
|
||||
(S::Regular, S::Sftp(_)) => None,
|
||||
(S::Search(_), S::Sftp(_)) => None,
|
||||
(S::Archive(_), S::Sftp(_)) => None,
|
||||
(S::Sftp(_), S::Regular) => None,
|
||||
(S::Sftp(_), S::Search(_)) => None,
|
||||
(S::Sftp(_), S::Archive(_)) => None,
|
||||
(S::Regular, T::Sftp(_)) => None,
|
||||
(S::Search(_), T::Sftp(_)) => None,
|
||||
(S::Archive(_), T::Sftp(_)) => None,
|
||||
(S::Sftp(_), T::Regular) => None,
|
||||
(S::Sftp(_), T::Search(_)) => None,
|
||||
(S::Sftp(_), T::Archive(_)) => None,
|
||||
}?))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::{borrow::Cow, ffi::{OsStr, OsString}, iter::FusedIterator, ops::Not, path::{self, PathBuf, PrefixComponent}};
|
||||
|
||||
use crate::{loc::Loc, url::{Encode, Scheme, Url, UrlBuf, UrlCow}};
|
||||
use crate::{loc::Loc, scheme::{Scheme, SchemeRef}, url::{Encode, Url, UrlBuf, UrlCow}};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Component<'a> {
|
||||
Scheme(&'a Scheme),
|
||||
Scheme(SchemeRef<'a>),
|
||||
Prefix(PrefixComponent<'a>),
|
||||
RootDir,
|
||||
CurDir,
|
||||
|
|
@ -29,7 +29,7 @@ impl<'a> FromIterator<Component<'a>> for UrlBuf {
|
|||
let mut scheme = Scheme::Regular;
|
||||
let mut buf = PathBuf::new();
|
||||
iter.into_iter().for_each(|c| match c {
|
||||
Component::Scheme(s) => scheme = s.clone(),
|
||||
Component::Scheme(s) => scheme = s.into(),
|
||||
Component::Prefix(p) => buf.push(path::Component::Prefix(p)),
|
||||
Component::RootDir => buf.push(path::Component::RootDir),
|
||||
Component::CurDir => buf.push(path::Component::CurDir),
|
||||
|
|
@ -61,16 +61,16 @@ impl<'a> FromIterator<Component<'a>> for PathBuf {
|
|||
pub struct Components<'a> {
|
||||
inner: path::Components<'a>,
|
||||
loc: Loc<'a>,
|
||||
scheme: &'a Scheme,
|
||||
scheme: SchemeRef<'a>,
|
||||
scheme_yielded: bool,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Url<'a>> for Components<'a> {
|
||||
fn from(value: &'a Url<'a>) -> Self {
|
||||
impl<'a> From<Url<'a>> for Components<'a> {
|
||||
fn from(value: Url<'a>) -> Self {
|
||||
Self {
|
||||
inner: value.loc.components(),
|
||||
inner: value.loc.as_path().components(),
|
||||
loc: value.loc,
|
||||
scheme: &value.scheme,
|
||||
scheme: value.scheme,
|
||||
scheme_yielded: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -81,19 +81,14 @@ impl<'a> From<&'a UrlBuf> for Components<'a> {
|
|||
Self {
|
||||
inner: value.loc.components(),
|
||||
loc: value.loc.as_loc(),
|
||||
scheme: &value.scheme,
|
||||
scheme: value.scheme.as_ref(),
|
||||
scheme_yielded: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a UrlCow<'a>> for Components<'a> {
|
||||
fn from(value: &'a UrlCow<'a>) -> Self {
|
||||
match value {
|
||||
UrlCow::Borrowed(url) => Self::from(url),
|
||||
UrlCow::Owned(url) => Self::from(url),
|
||||
}
|
||||
}
|
||||
fn from(value: &'a UrlCow<'a>) -> Self { Self::from(value.as_url()) }
|
||||
}
|
||||
|
||||
impl<'a> Components<'a> {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::url::{Url, UrlBuf, UrlCow};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UrlCov<'a>(Url<'a>);
|
||||
|
||||
impl<'a> Deref for UrlCov<'a> {
|
||||
|
|
|
|||
|
|
@ -3,28 +3,30 @@ use std::{borrow::Cow, path::{Path, PathBuf}};
|
|||
use anyhow::Result;
|
||||
use percent_encoding::percent_decode;
|
||||
|
||||
use crate::{IntoOsStr, loc::{Loc, LocBuf}, url::{Components, Scheme, Url, UrlBuf, Urn}};
|
||||
use crate::{IntoOsStr, loc::{Loc, LocBuf}, scheme::{SchemeCow, SchemeRef}, url::{Components, Url, UrlBuf, Urn}};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UrlCow<'a> {
|
||||
Borrowed(Url<'a>),
|
||||
Owned(UrlBuf),
|
||||
Borrowed { loc: Loc<'a>, scheme: SchemeCow<'a> },
|
||||
Owned { loc: LocBuf, scheme: SchemeCow<'a> },
|
||||
}
|
||||
|
||||
impl Default for UrlCow<'_> {
|
||||
fn default() -> Self { Self::Owned(UrlBuf::default()) }
|
||||
fn default() -> Self { Self::Owned { loc: Default::default(), scheme: Default::default() } }
|
||||
}
|
||||
|
||||
impl<'a> From<Url<'a>> for UrlCow<'a> {
|
||||
fn from(value: Url<'a>) -> Self { Self::Borrowed(value) }
|
||||
fn from(value: Url<'a>) -> Self { Self::Borrowed { loc: value.loc, scheme: value.scheme.into() } }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a UrlBuf> for UrlCow<'a> {
|
||||
fn from(value: &'a UrlBuf) -> Self { Self::Borrowed(value.into()) }
|
||||
fn from(value: &'a UrlBuf) -> Self {
|
||||
Self::Borrowed { loc: value.loc.as_loc(), scheme: SchemeCow::from(&value.scheme) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UrlBuf> for UrlCow<'_> {
|
||||
fn from(value: UrlBuf) -> Self { Self::Owned(value) }
|
||||
fn from(value: UrlBuf) -> Self { Self::Owned { loc: value.loc, scheme: value.scheme.into() } }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a UrlCow<'a>> for Url<'a> {
|
||||
|
|
@ -46,11 +48,13 @@ impl<'a> TryFrom<&'a [u8]> for UrlCow<'a> {
|
|||
let (scheme, path, port) = Self::parse(value)?;
|
||||
|
||||
Ok(match (path, port) {
|
||||
(Cow::Borrowed(p), None) => Url { loc: Loc::from(p), scheme }.into(),
|
||||
(Cow::Borrowed(p), Some((uri, urn))) => Url { loc: Loc::with(p, uri, urn)?, scheme }.into(),
|
||||
(Cow::Owned(p), None) => UrlBuf { loc: LocBuf::from(p), scheme }.into(),
|
||||
(Cow::Borrowed(p), None) => Self::Borrowed { loc: Loc::from(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))) => {
|
||||
UrlBuf { loc: LocBuf::with(p, uri, urn)?, scheme }.into()
|
||||
Self::Owned { loc: LocBuf::with(p, uri, urn)?, scheme }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -94,36 +98,44 @@ impl PartialEq<UrlBuf> for UrlCow<'_> {
|
|||
fn eq(&self, other: &UrlBuf) -> bool { self.as_url() == other.as_url() }
|
||||
}
|
||||
|
||||
impl UrlCow<'_> {
|
||||
impl<'a> UrlCow<'a> {
|
||||
#[inline]
|
||||
pub fn loc(&self) -> Loc<'_> {
|
||||
match self {
|
||||
UrlCow::Borrowed(u) => u.loc.as_loc(),
|
||||
UrlCow::Owned(u) => u.loc.as_loc(),
|
||||
UrlCow::Borrowed { loc, .. } => *loc,
|
||||
UrlCow::Owned { loc, .. } => loc.as_loc(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn scheme(&self) -> &Scheme {
|
||||
pub fn scheme(&self) -> SchemeRef<'_> {
|
||||
match self {
|
||||
UrlCow::Borrowed(u) => &u.scheme,
|
||||
UrlCow::Owned(u) => &u.scheme,
|
||||
UrlCow::Borrowed { scheme, .. } => scheme.as_ref(),
|
||||
UrlCow::Owned { scheme, .. } => scheme.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_url(&self) -> Url<'_> {
|
||||
match self {
|
||||
UrlCow::Borrowed(u) => u.as_url(),
|
||||
UrlCow::Owned(u) => u.as_url(),
|
||||
UrlCow::Borrowed { loc, scheme } => Url { loc: *loc, scheme: scheme.as_ref() },
|
||||
UrlCow::Owned { loc, scheme } => Url { loc: loc.as_loc(), scheme: scheme.as_ref() },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_owned(self) -> UrlBuf {
|
||||
match self {
|
||||
UrlCow::Borrowed(u) => u.into(),
|
||||
UrlCow::Owned(u) => u,
|
||||
UrlCow::Borrowed { loc, scheme } => UrlBuf { loc: loc.into(), scheme: scheme.into() },
|
||||
UrlCow::Owned { loc, scheme } => UrlBuf { loc, scheme: scheme.into() },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_scheme(self) -> SchemeCow<'a> {
|
||||
match self {
|
||||
UrlCow::Borrowed { scheme, .. } => scheme,
|
||||
UrlCow::Owned { scheme, .. } => scheme,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,9 +145,9 @@ impl UrlCow<'_> {
|
|||
#[inline]
|
||||
pub fn pair(&self) -> Option<(Url<'_>, &Urn)> { self.as_url().pair() }
|
||||
|
||||
pub fn parse(bytes: &[u8]) -> Result<(Scheme, Cow<'_, Path>, Option<(usize, usize)>)> {
|
||||
pub fn parse(bytes: &[u8]) -> Result<(SchemeCow<'_>, Cow<'_, Path>, Option<(usize, usize)>)> {
|
||||
let mut skip = 0;
|
||||
let (scheme, tilde, uri, urn) = Scheme::parse(bytes, &mut skip)?;
|
||||
let (scheme, tilde, uri, urn) = SchemeCow::parse(bytes, &mut skip)?;
|
||||
|
||||
let rest = if tilde {
|
||||
Cow::from(percent_decode(&bytes[skip..])).into_os_str()?
|
||||
|
|
|
|||
|
|
@ -2,24 +2,24 @@ use std::{fmt::{self, Display}, ops::Not};
|
|||
|
||||
use percent_encoding::{AsciiSet, CONTROLS, PercentEncode, percent_encode};
|
||||
|
||||
use crate::{loc::Loc, url::{Scheme, Url, UrlBuf}};
|
||||
use crate::{loc::Loc, scheme::SchemeRef, url::{Url, UrlBuf}};
|
||||
|
||||
pub struct Encode<'a> {
|
||||
loc: Loc<'a>,
|
||||
scheme: &'a Scheme,
|
||||
scheme: SchemeRef<'a>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Url<'a>> for Encode<'a> {
|
||||
fn from(url: &'a Url<'a>) -> Self { Self::new(url.loc, &url.scheme) }
|
||||
impl<'a> From<Url<'a>> for Encode<'a> {
|
||||
fn from(url: Url<'a>) -> Self { Self::new(url.loc, url.scheme) }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a UrlBuf> for Encode<'a> {
|
||||
fn from(url: &'a UrlBuf) -> Self { Self::new(url.loc.as_loc(), &url.scheme) }
|
||||
fn from(url: &'a UrlBuf) -> Self { Self::new(url.loc.as_loc(), url.scheme.as_ref()) }
|
||||
}
|
||||
|
||||
impl<'a> Encode<'a> {
|
||||
#[inline]
|
||||
pub(super) fn new(loc: Loc<'a>, scheme: &'a Scheme) -> Self { Self { loc, scheme } }
|
||||
pub(super) fn new(loc: Loc<'a>, scheme: SchemeRef<'a>) -> Self { Self { loc, scheme } }
|
||||
|
||||
#[inline]
|
||||
fn domain<'s>(s: &'s str) -> PercentEncode<'s> {
|
||||
|
|
@ -46,9 +46,9 @@ impl<'a> Encode<'a> {
|
|||
}
|
||||
|
||||
match self.0.scheme {
|
||||
Scheme::Regular => Ok(()),
|
||||
Scheme::Search(_) | Scheme::Archive(_) => w!(0, 0),
|
||||
Scheme::Sftp(_) => w!(
|
||||
SchemeRef::Regular => Ok(()),
|
||||
SchemeRef::Search(_) | SchemeRef::Archive(_) => w!(0, 0),
|
||||
SchemeRef::Sftp(_) => w!(
|
||||
self.0.loc.as_os_str().is_empty().not() as usize,
|
||||
self.0.loc.file_name().is_some() as usize
|
||||
),
|
||||
|
|
@ -62,11 +62,12 @@ impl<'a> Encode<'a> {
|
|||
|
||||
impl Display for Encode<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use SchemeRef as S;
|
||||
match self.scheme {
|
||||
Scheme::Regular => write!(f, "regular://"),
|
||||
Scheme::Search(d) => write!(f, "search://{}{}/", Self::domain(d), self.ports()),
|
||||
Scheme::Archive(d) => write!(f, "archive://{}{}/", Self::domain(d), self.ports()),
|
||||
Scheme::Sftp(d) => write!(f, "sftp://{}{}/", Self::domain(d), self.ports()),
|
||||
S::Regular => write!(f, "regular://"),
|
||||
S::Search(d) => write!(f, "search://{}{}/", Self::domain(d), self.ports()),
|
||||
S::Archive(d) => write!(f, "archive://{}{}/", Self::domain(d), self.ports()),
|
||||
S::Sftp(d) => write!(f, "sftp://{}{}/", Self::domain(d), self.ports()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -74,15 +75,11 @@ impl Display for Encode<'_> {
|
|||
// --- Tilded
|
||||
pub struct EncodeTilded<'a> {
|
||||
loc: Loc<'a>,
|
||||
scheme: &'a Scheme,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Url<'a>> for EncodeTilded<'a> {
|
||||
fn from(url: &'a Url<'a>) -> Self { Self { loc: url.loc, scheme: &url.scheme } }
|
||||
scheme: SchemeRef<'a>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a UrlBuf> for EncodeTilded<'a> {
|
||||
fn from(url: &'a UrlBuf) -> Self { Self { loc: url.loc.as_loc(), scheme: &url.scheme } }
|
||||
fn from(url: &'a UrlBuf) -> Self { Self { loc: url.loc.as_loc(), scheme: url.scheme.as_ref() } }
|
||||
}
|
||||
|
||||
impl<'a> From<&EncodeTilded<'a>> for Encode<'a> {
|
||||
|
|
@ -92,15 +89,16 @@ impl<'a> From<&EncodeTilded<'a>> for Encode<'a> {
|
|||
impl Display for EncodeTilded<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use Encode as E;
|
||||
use SchemeRef as S;
|
||||
|
||||
let loc = percent_encode(self.loc.as_os_str().as_encoded_bytes(), CONTROLS);
|
||||
match self.scheme {
|
||||
Scheme::Regular => write!(f, "regular~://{loc}"),
|
||||
Scheme::Search(d) => write!(f, "search~://{}{}/{loc}", E::domain(d), E::ports(&self.into())),
|
||||
Scheme::Archive(d) => {
|
||||
S::Regular => write!(f, "regular~://{loc}"),
|
||||
S::Search(d) => write!(f, "search~://{}{}/{loc}", E::domain(d), E::ports(&self.into())),
|
||||
S::Archive(d) => {
|
||||
write!(f, "archive~://{}{}/{loc}", E::domain(d), E::ports(&self.into()))
|
||||
}
|
||||
Scheme::Sftp(d) => write!(f, "sftp~://{}{}/{loc}", E::domain(d), E::ports(&self.into())),
|
||||
S::Sftp(d) => write!(f, "sftp~://{}{}/{loc}", E::domain(d), E::ports(&self.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(buf component cov cow display encode scheme uri url urn);
|
||||
yazi_macro::mod_flat!(buf component cov cow display encode uri url urn);
|
||||
|
|
|
|||
|
|
@ -2,22 +2,17 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::Path};
|
|||
|
||||
use hashbrown::Equivalent;
|
||||
|
||||
use crate::{loc::{Loc, LocBuf}, url::{Components, Encode, Scheme, Uri, UrlBuf, Urn}};
|
||||
use crate::{loc::{Loc, LocBuf}, scheme::SchemeRef, url::{Components, Encode, Uri, UrlBuf, Urn}};
|
||||
|
||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub struct Url<'a> {
|
||||
pub loc: Loc<'a>,
|
||||
pub scheme: Scheme,
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
impl<'a> From<&'a Url<'a>> for Url<'a> {
|
||||
fn from(value: &'a Url) -> Self { Self { loc: value.loc.as_loc(), scheme: value.scheme.clone() } }
|
||||
pub scheme: SchemeRef<'a>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a UrlBuf> for Url<'a> {
|
||||
fn from(value: &'a UrlBuf) -> Self {
|
||||
Self { loc: value.loc.as_loc(), scheme: value.scheme.clone() }
|
||||
Self { loc: value.loc.as_loc(), scheme: value.scheme.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -38,10 +33,10 @@ impl Equivalent<UrlBuf> for Url<'_> {
|
|||
// --- Debug
|
||||
impl Debug for Url<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
if self.scheme == Scheme::Regular {
|
||||
if self.scheme == SchemeRef::Regular {
|
||||
write!(f, "{}", self.loc.display())
|
||||
} else {
|
||||
write!(f, "{}{}", Encode::from(self), self.loc.display())
|
||||
write!(f, "{}{}", Encode::from(*self), self.loc.display())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,34 +44,31 @@ 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: Scheme::Regular }
|
||||
Self { loc: path.as_ref().into(), scheme: SchemeRef::Regular }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_regular(&self) -> bool { self.scheme == Scheme::Regular }
|
||||
pub fn is_regular(self) -> bool { self.scheme == SchemeRef::Regular }
|
||||
|
||||
#[inline]
|
||||
pub fn into_regular(self) -> Self {
|
||||
Self { loc: self.loc.as_path().into(), scheme: Scheme::Regular }
|
||||
Self { loc: self.loc.as_path().into(), scheme: SchemeRef::Regular }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_search(&self) -> bool { matches!(self.scheme, Scheme::Search(_)) }
|
||||
pub fn is_search(self) -> bool { matches!(self.scheme, SchemeRef::Search(_)) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_absolute(&self) -> bool { self.loc.is_absolute() }
|
||||
pub fn is_absolute(self) -> bool { self.loc.is_absolute() }
|
||||
|
||||
#[inline]
|
||||
pub fn has_root(&self) -> bool { self.loc.has_root() }
|
||||
pub fn has_root(self) -> bool { self.loc.has_root() }
|
||||
|
||||
#[inline]
|
||||
pub fn as_url(&'a self) -> Url<'a> { Self::from(self) }
|
||||
pub fn to_owned(self) -> UrlBuf { self.into() }
|
||||
|
||||
#[inline]
|
||||
pub fn to_owned(&self) -> UrlBuf { self.into() }
|
||||
|
||||
pub fn join(&self, path: impl AsRef<Path>) -> UrlBuf {
|
||||
use Scheme as S;
|
||||
pub fn join(self, path: impl AsRef<Path>) -> UrlBuf {
|
||||
use SchemeRef as S;
|
||||
|
||||
let join = self.loc.join(path);
|
||||
|
||||
|
|
@ -87,26 +79,26 @@ impl<'a> Url<'a> {
|
|||
S::Sftp(_) => join.into(),
|
||||
};
|
||||
|
||||
UrlBuf { loc, scheme: self.scheme.clone() }
|
||||
UrlBuf { loc, scheme: self.scheme.into() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn uri(&self) -> &'a Uri { self.loc.uri() }
|
||||
pub fn uri(self) -> &'a Uri { self.loc.uri() }
|
||||
|
||||
#[inline]
|
||||
pub fn urn(&self) -> &'a Urn { self.loc.urn() }
|
||||
pub fn urn(self) -> &'a Urn { self.loc.urn() }
|
||||
|
||||
#[inline]
|
||||
pub fn name(self) -> Option<&'a OsStr> { self.loc.name() }
|
||||
|
||||
#[inline]
|
||||
pub fn stem(&self) -> Option<&'a OsStr> { self.loc.stem() }
|
||||
pub fn stem(self) -> Option<&'a OsStr> { self.loc.stem() }
|
||||
|
||||
#[inline]
|
||||
pub fn ext(&self) -> Option<&'a OsStr> { self.loc.ext() }
|
||||
pub fn ext(self) -> Option<&'a OsStr> { self.loc.ext() }
|
||||
|
||||
pub fn base(&self) -> Option<Self> {
|
||||
use Scheme as S;
|
||||
pub fn base(self) -> Option<Self> {
|
||||
use SchemeRef as S;
|
||||
|
||||
if !self.loc.has_base() {
|
||||
return None;
|
||||
|
|
@ -115,14 +107,14 @@ impl<'a> Url<'a> {
|
|||
let loc: Loc = self.loc.base().into();
|
||||
Some(match self.scheme {
|
||||
S::Regular => Self { loc, scheme: S::Regular },
|
||||
S::Search(_) => Self { loc, scheme: self.scheme.clone() },
|
||||
S::Archive(_) => Self { loc, scheme: self.scheme.clone() },
|
||||
S::Sftp(_) => Self { loc, scheme: self.scheme.clone() },
|
||||
S::Search(_) => Self { loc, scheme: self.scheme },
|
||||
S::Archive(_) => Self { loc, scheme: self.scheme },
|
||||
S::Sftp(_) => Self { loc, scheme: self.scheme },
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<Self> {
|
||||
use Scheme as S;
|
||||
pub fn parent(self) -> Option<Self> {
|
||||
use SchemeRef as S;
|
||||
|
||||
let parent = self.loc.parent()?;
|
||||
let uri = self.loc.uri();
|
||||
|
|
@ -133,60 +125,57 @@ impl<'a> Url<'a> {
|
|||
|
||||
// Search
|
||||
S::Search(_) if uri.is_empty() => Self { loc: parent.into(), scheme: S::Regular },
|
||||
S::Search(_) => Self {
|
||||
loc: Loc::new(parent, self.loc.base(), self.loc.base()),
|
||||
scheme: self.scheme.clone(),
|
||||
},
|
||||
S::Search(_) => {
|
||||
Self { loc: Loc::new(parent, self.loc.base(), self.loc.base()), scheme: self.scheme }
|
||||
}
|
||||
|
||||
// Archive
|
||||
S::Archive(_) if uri.is_empty() => Self { loc: parent.into(), scheme: S::Regular },
|
||||
S::Archive(_) if uri.nth(1).is_none() => {
|
||||
Self { loc: Loc::zeroed(parent), scheme: self.scheme.clone() }
|
||||
}
|
||||
S::Archive(_) => {
|
||||
Self { loc: Loc::floated(parent, self.loc.base()), scheme: self.scheme.clone() }
|
||||
Self { loc: Loc::zeroed(parent), scheme: self.scheme }
|
||||
}
|
||||
S::Archive(_) => Self { loc: Loc::floated(parent, self.loc.base()), scheme: self.scheme },
|
||||
|
||||
// SFTP
|
||||
S::Sftp(_) => Self { loc: parent.into(), scheme: self.scheme.clone() },
|
||||
S::Sftp(_) => Self { loc: parent.into(), scheme: self.scheme },
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn starts_with<'b>(&self, base: impl Into<Url<'b>>) -> bool {
|
||||
pub fn starts_with<'b>(self, base: impl Into<Url<'b>>) -> bool {
|
||||
let base: Url = base.into();
|
||||
self.scheme.covariant(&base.scheme) && self.loc.starts_with(base.loc)
|
||||
self.scheme.covariant(base.scheme) && self.loc.starts_with(base.loc)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ends_with<'b>(&self, child: impl Into<Url<'b>>) -> bool {
|
||||
pub fn ends_with<'b>(self, child: impl Into<Url<'b>>) -> bool {
|
||||
let child: Url = child.into();
|
||||
self.scheme.covariant(&child.scheme) && self.loc.ends_with(child.loc)
|
||||
self.scheme.covariant(child.scheme) && self.loc.ends_with(child.loc)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn components(&self) -> Components<'_> { Components::from(self) }
|
||||
pub fn components(self) -> Components<'a> { Components::from(self) }
|
||||
|
||||
#[inline]
|
||||
pub fn os_str(&self) -> Cow<'_, OsStr> { self.components().os_str() }
|
||||
pub fn os_str(self) -> Cow<'a, OsStr> { self.components().os_str() }
|
||||
|
||||
#[inline]
|
||||
pub fn covariant(&self, other: impl Into<Self>) -> bool {
|
||||
pub fn covariant(self, other: impl Into<Self>) -> bool {
|
||||
let other = other.into();
|
||||
self.scheme.covariant(&other.scheme) && self.loc == other.loc
|
||||
self.scheme.covariant(other.scheme) && self.loc == other.loc
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pair(&self) -> Option<(Url<'a>, &'a Urn)> { Some((self.parent()?, self.loc.urn())) }
|
||||
pub fn pair(self) -> Option<(Url<'a>, &'a Urn)> { Some((self.parent()?, self.loc.urn())) }
|
||||
|
||||
#[inline]
|
||||
pub fn as_path(&self) -> Option<&'a Path> {
|
||||
pub fn as_path(self) -> Option<&'a Path> {
|
||||
Some(self.loc.as_path()).filter(|_| !self.scheme.is_virtual())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_base(&self) -> bool { self.loc.has_base() }
|
||||
pub fn has_base(self) -> bool { self.loc.has_base() }
|
||||
|
||||
#[inline]
|
||||
pub fn has_trail(&self) -> bool { self.loc.has_trail() }
|
||||
pub fn has_trail(self) -> bool { self.loc.has_trail() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ impl Backend {
|
|||
let Some(parent) = url.parent() else { continue };
|
||||
if todo.contains(&parent) {
|
||||
todo.insert(url);
|
||||
} else if watched.contains(&parent)
|
||||
|| LINKED.read().from_dir(&parent).any(|p| watched.contains(Url::regular(p)))
|
||||
} else if watched.contains(parent)
|
||||
|| LINKED.read().from_dir(parent).any(|p| watched.contains(Url::regular(p)))
|
||||
{
|
||||
todo.insert(parent.to_owned());
|
||||
todo.insert(url);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue