Skip to content

Commit 396f634

Browse files
authored
fix: add preset VFS config file to avoid TOML parsing errors (#3414)
1 parent 9ae8b90 commit 396f634

File tree

13 files changed

+184
-52
lines changed

13 files changed

+184
-52
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[services]

yazi-config/src/preset.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Yazi, keymap::Keymap, theme::Theme};
1+
use crate::{Yazi, keymap::Keymap, theme::Theme, vfs::Vfs};
22

33
pub(crate) struct Preset;
44

@@ -19,6 +19,10 @@ impl Preset {
1919
})
2020
}
2121

22+
pub(super) fn vfs() -> Result<Vfs, toml::de::Error> {
23+
toml::from_str(&yazi_macro::config_preset!("vfs"))
24+
}
25+
2226
#[inline]
2327
pub(crate) fn mix<E, A, B, C>(a: A, b: B, c: C) -> impl Iterator<Item = E>
2428
where

yazi-config/src/vfs/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
yazi_macro::mod_flat!(service vfs);
1+
yazi_macro::mod_flat!(service services vfs);

yazi-config/src/vfs/services.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use std::ops::Deref;
2+
3+
use anyhow::{Result, bail};
4+
use hashbrown::HashMap;
5+
use serde::{Deserialize, Serialize};
6+
7+
use crate::vfs::Service;
8+
9+
#[derive(Deserialize, Serialize)]
10+
pub struct Services(HashMap<String, Service>);
11+
12+
impl Deref for Services {
13+
type Target = HashMap<String, Service>;
14+
15+
fn deref(&self) -> &Self::Target { &self.0 }
16+
}
17+
18+
impl Services {
19+
pub(super) fn reshape(mut self) -> Result<Self> {
20+
for (name, service) in &mut self.0 {
21+
if name.is_empty() || name.len() > 20 {
22+
bail!("VFS name `{name}` must be between 1 and 20 characters");
23+
} else if !name.bytes().all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'z' | b'-')) {
24+
bail!("VFS name `{name}` must be in kebab-case");
25+
}
26+
27+
service.reshape()?;
28+
}
29+
30+
Ok(self)
31+
}
32+
33+
pub(super) fn deserialize_over<'de, D>(mut self, deserializer: D) -> Result<Self, D::Error>
34+
where
35+
D: serde::Deserializer<'de>,
36+
{
37+
let map: HashMap<String, Service> = HashMap::deserialize(deserializer)?;
38+
self.0.extend(map);
39+
40+
Ok(self)
41+
}
42+
}

yazi-config/src/vfs/vfs.rs

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
use std::io;
22

3-
use hashbrown::HashMap;
3+
use anyhow::{Context, Result};
44
use serde::{Deserialize, Serialize};
55
use tokio::sync::OnceCell;
6-
use yazi_fs::Xdg;
7-
use yazi_macro::ok_or_not_found;
6+
use yazi_codegen::DeserializeOver1;
7+
use yazi_fs::{Xdg, ok_or_not_found};
88

99
use super::Service;
10+
use crate::{Preset, vfs::Services};
1011

11-
#[derive(Deserialize, Serialize)]
12+
#[derive(Deserialize, Serialize, DeserializeOver1)]
1213
pub struct Vfs {
13-
pub services: HashMap<String, Service>,
14+
pub services: Services,
1415
}
1516

1617
impl Vfs {
@@ -19,9 +20,10 @@ impl Vfs {
1920

2021
async fn init() -> io::Result<Vfs> {
2122
tokio::task::spawn_blocking(|| {
22-
toml::from_str::<Vfs>(&Vfs::read()?).map_err(io::Error::other)?.reshape()
23+
Preset::vfs()?.deserialize_over(toml::Deserializer::parse(&Vfs::read()?)?)?.reshape()
2324
})
2425
.await?
26+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
2527
}
2628

2729
LOADED.get_or_try_init(init).await
@@ -40,24 +42,11 @@ impl Vfs {
4042
}
4143
}
4244

43-
fn read() -> io::Result<String> {
45+
fn read() -> Result<String> {
4446
let p = Xdg::config_dir().join("vfs.toml");
45-
Ok(ok_or_not_found!(std::fs::read_to_string(&p).map_err(|e| {
46-
std::io::Error::new(e.kind(), format!("Failed to read VFS config {p:?}: {e}"))
47-
})))
47+
ok_or_not_found(std::fs::read_to_string(&p))
48+
.with_context(|| format!("Failed to read config {p:?}"))
4849
}
4950

50-
fn reshape(mut self) -> io::Result<Self> {
51-
for (name, service) in &mut self.services {
52-
if name.is_empty() || name.len() > 20 {
53-
Err(io::Error::other(format!("VFS name `{name}` must be between 1 and 20 characters")))?;
54-
} else if !name.bytes().all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'z' | b'-')) {
55-
Err(io::Error::other(format!("VFS name `{name}` must be in kebab-case")))?;
56-
}
57-
58-
service.reshape()?;
59-
}
60-
61-
Ok(self)
62-
}
51+
fn reshape(self) -> Result<Self> { Ok(Self { services: self.services.reshape()? }) }
6352
}

yazi-scheduler/src/file/file.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,12 @@ impl File {
119119
.await?;
120120

121121
if !links.is_empty() {
122-
let len = links.len();
123-
let (tx, mut rx) = mpsc::channel(len);
122+
let (tx, mut rx) = mpsc::channel(1);
124123
for task in links {
125124
self.queue(task.with_drop(&tx), LOW);
126125
}
127-
for _ in 0..len {
128-
rx.recv().await;
129-
}
126+
drop(tx);
127+
while rx.recv().await.is_some() {}
130128
}
131129

132130
for task in files {

yazi-scheduler/src/file/in.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,7 @@ pub(crate) struct FileInCut {
4242
}
4343

4444
impl Drop for FileInCut {
45-
fn drop(&mut self) {
46-
if let Some(tx) = self.drop.take() {
47-
tx.try_send(()).ok();
48-
}
49-
}
45+
fn drop(&mut self) { _ = self.drop.take(); }
5046
}
5147

5248
impl FileInCut {

yazi-shared/src/loc/buf.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,24 +266,24 @@ mod tests {
266266
#[test]
267267
fn test_new() {
268268
let loc: LocBuf = Path::new("/").into();
269-
assert_eq!(loc.uri().as_os_str(), OsStr::new("/"));
269+
assert_eq!(loc.uri().as_os_str(), OsStr::new(""));
270270
assert_eq!(loc.urn().as_os_str(), OsStr::new(""));
271271
assert_eq!(loc.file_name(), None);
272-
assert_eq!(loc.base().as_os_str(), OsStr::new(""));
272+
assert_eq!(loc.base().as_os_str(), OsStr::new("/"));
273273
assert_eq!(loc.trail().as_os_str(), OsStr::new("/"));
274274

275275
let loc: LocBuf = Path::new("/root").into();
276-
assert_eq!(loc.uri().as_os_str(), OsStr::new("/root"));
276+
assert_eq!(loc.uri().as_os_str(), OsStr::new("root"));
277277
assert_eq!(loc.urn().as_os_str(), OsStr::new("root"));
278278
assert_eq!(loc.file_name().unwrap(), OsStr::new("root"));
279-
assert_eq!(loc.base().as_os_str(), OsStr::new(""));
279+
assert_eq!(loc.base().as_os_str(), OsStr::new("/"));
280280
assert_eq!(loc.trail().as_os_str(), OsStr::new("/"));
281281

282282
let loc: LocBuf = Path::new("/root/code/foo/").into();
283-
assert_eq!(loc.uri().as_os_str(), OsStr::new("/root/code/foo"));
283+
assert_eq!(loc.uri().as_os_str(), OsStr::new("foo"));
284284
assert_eq!(loc.urn().as_os_str(), OsStr::new("foo"));
285285
assert_eq!(loc.file_name().unwrap(), OsStr::new("foo"));
286-
assert_eq!(loc.base().as_os_str(), OsStr::new(""));
286+
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/code/"));
287287
assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/code/"));
288288
}
289289

yazi-shared/src/loc/loc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ where
8686
let path = path.as_path_view();
8787
let Some(name) = path.file_name() else {
8888
let p = path.strip_prefix(P::empty()).unwrap();
89-
return Self { inner: p, uri: p.len(), urn: 0, _phantom: PhantomData };
89+
return Self { inner: p, uri: 0, urn: 0, _phantom: PhantomData };
9090
};
9191

9292
let name_len = name.len();
@@ -97,7 +97,7 @@ where
9797
let bytes = &path.as_encoded_bytes()[..prefix_len + name_len];
9898
Self {
9999
inner: unsafe { P::from_encoded_bytes_unchecked(bytes) },
100-
uri: bytes.len(),
100+
uri: name_len,
101101
urn: name_len,
102102
_phantom: PhantomData,
103103
}

yazi-shared/src/scheme/cow.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ impl<'a> SchemeCow<'a> {
146146
Ok(match kind {
147147
SchemeKind::Regular => {
148148
ensure!(uri.is_none() && urn.is_none(), "Regular scheme cannot have ports");
149-
(path.components().count(), path.name().is_some() as usize)
149+
(path.name().is_some() as usize, path.name().is_some() as usize)
150150
}
151151
SchemeKind::Search => {
152152
let (uri, urn) = (uri.unwrap_or(0), urn.unwrap_or(0));
@@ -155,15 +155,20 @@ impl<'a> SchemeCow<'a> {
155155
}
156156
SchemeKind::Archive => (uri.unwrap_or(0), urn.unwrap_or(0)),
157157
SchemeKind::Sftp => {
158-
let uri = uri.unwrap_or_else(|| path.components().count());
158+
let uri = uri.unwrap_or(path.name().is_some() as usize);
159159
let urn = urn.unwrap_or(path.name().is_some() as usize);
160160
(uri, urn)
161161
}
162162
})
163163
}
164164

165165
pub fn retrieve_ports(url: Url) -> (usize, usize) {
166-
(url.uri().components().count(), url.urn().components().count())
166+
match url {
167+
Url::Regular(loc) => (loc.file_name().is_some() as usize, loc.file_name().is_some() as usize),
168+
Url::Search { loc, .. } => (loc.uri().components().count(), loc.urn().components().count()),
169+
Url::Archive { loc, .. } => (loc.uri().components().count(), loc.urn().components().count()),
170+
Url::Sftp { loc, .. } => (loc.uri().components().count(), loc.urn().components().count()),
171+
}
167172
}
168173
}
169174

0 commit comments

Comments
 (0)