Skip to content

Conversation

@sxyazi
Copy link
Owner

@sxyazi sxyazi commented Aug 4, 2025

Prepare for #611


⚠️ Breaking changes

The name rule for open, fetchers, spotters, preloaders, previewers, filetype, and globs icon rules has been renamed to url, e.g.:

# yazi.toml
[plugin]
prepend_previewers = [
-   { name = "*/", run = "folder" },
+   { url = "*/", run = "folder" },
]
# theme.toml / flavor.toml
[filetype]
rules = [
-   { name = "*/", fg = "blue" },
+   { url = "*/", fg = "blue" },
]

This change addresses:

  • The original term name was inaccurate since the name rule doesn't apply to the filename actually, but to the full file path, e.g., { name = "/Downloads/**/*.zip", ... }.
  • With this PR, virtual file system has been supported, and there needs to be a way for matching URL schemes, for instance, to disable previews for SFTP servers: { url = "sftp://**", run = "noop" }.

URL is a superset of path, which means that the new url rule will inherit the functionality of the original name rule while also providing support for URL scheme matching.

Deprecated

The frag property of Url has been deprecated and replaced by the new domain:

- print(url.frag)
+ print(url.domain)

This change is part of the redesign of the URL system. Previously, the fragment was included after the URL's path:

search:///path/to/file#keyword

But this means that the character # could no longer appear in the path, otherwise it would be unclear where the fragment starts, hence it required the path to be URL encoded:

search://%2Fpath%2Fto%2Ffile#keyword

This reduced readability and made typing URLs more cumbersome since the path is the most critical part of a URL. The new implementation stores the original fragment as the URL's domain:

search://keyword//path/to/file

Fragments occur far less frequently than paths, and they are typically only used for internal data exchange in Yazi, and users usually do not have to input them, so encoding fragments instead is acceptable.

@sxyazi sxyazi requested a review from Copilot August 4, 2025 11:37

This comment was marked as outdated.

sxyazi added a commit to yazi-rs/flavors that referenced this pull request Aug 4, 2025
@sxyazi sxyazi requested a review from Copilot August 4, 2025 17:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a virtual file system (VFS) abstraction layer to prepare for virtual filesystems support. The changes refactor filesystem operations to use a provider pattern, enabling future support for non-local filesystems like archives and remote connections.

  • Replaces direct filesystem operations with provider abstraction layer
  • Refactors URL scheme handling to support virtual filesystem contexts
  • Updates search functionality to use domain-based schemes instead of fragment-based approach

Reviewed Changes

Copilot reviewed 73 out of 74 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
yazi-shared/src/url/*.rs Core URL and scheme handling refactor for VFS support
yazi-fs/src/provider/*.rs New VFS provider abstraction layer
yazi-fs/src/services/mod.rs Removed old services module
yazi-plugin/src/*.rs Updated to use new provider APIs
yazi-scheduler/src/*.rs Migrated to provider pattern
yazi-config/src/*.rs Updated pattern matching for URLs
Various other files Migration from services to provider APIs
Comments suppressed due to low confidence (1)

yazi-shared/src/url/url.rs:67

  • The method offset_from_unsigned does not exist in Rust's standard library. This should be offset_from which returns a signed integer.
	fn as_ref(&self) -> &Url { self }

Self::Archive(id) => write!(f, "archive://{}/", Self::encode_param(id)),
Self::Sftp(id) => write!(f, "sftp://{}/", Self::encode_param(id)),
}
*skip -= len;
Copy link

Copilot AI Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is incorrect. When len == 1, it means there's only a colon with no port number, but the function should handle this case properly. Also, *skip -= len on line 115 modifies skip incorrectly - it should be adding the port length, not subtracting.

Suggested change
*skip -= len;
*skip += len;

Copilot uses AI. Check for mistakes.
}
}

loc.urn = loc.strip_prefix(it).unwrap().as_os_str().len();
Copy link

Copilot AI Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable it is a Components iterator, but strip_prefix expects a Path. This should likely be loc.urn = loc.inner.strip_prefix(it.as_path()).unwrap().as_os_str().len(); or similar.

Suggested change
loc.urn = loc.strip_prefix(it).unwrap().as_os_str().len();
loc.urn = loc.inner.strip_prefix(it.as_path()).unwrap().as_os_str().len();

Copilot uses AI. Check for mistakes.
pub async fn create(path: impl AsRef<Path>) -> io::Result<tokio::fs::File> {
tokio::fs::File::create(path).await
pub async fn create(path: impl AsRef<Path>) -> io::Result<RwFile> {
Gate::default().write(true).create(true).truncate(true).open(path).await.map(Into::into)
Copy link

Copilot AI Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The Gate pattern is inconsistent with the direct tokio::fs::File::create call it replaces. Consider either using tokio::fs::File::create directly or ensuring all file operations consistently use the Gate abstraction.

Suggested change
Gate::default().write(true).create(true).truncate(true).open(path).await.map(Into::into)
tokio::fs::File::create(path).await.map(Into::into)

Copilot uses AI. Check for mistakes.
Comment on lines +108 to +110
// FIXME: VFS
let glob = if let Ok(s) = options.raw_get::<mlua::String>("glob") {
return Err("`glob` is disabled temporarily".into_lua_err());
Copy link

Copilot AI Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This FIXME comment indicates incomplete VFS implementation that disables glob functionality. This should be tracked as a known limitation or the functionality should be restored.

Suggested change
// FIXME: VFS
let glob = if let Ok(s) = options.raw_get::<mlua::String>("glob") {
return Err("`glob` is disabled temporarily".into_lua_err());
// Restore glob functionality
let glob = if let Ok(s) = options.raw_get::<mlua::String>("glob") {

Copilot uses AI. Check for mistakes.
@sxyazi sxyazi merged commit d5f225b into main Aug 4, 2025
6 checks passed
@sxyazi sxyazi deleted the pr-11f2e987 branch August 4, 2025 18:23
@sxyazi sxyazi changed the title feat: virtual file system feat!: virtual file system Aug 4, 2025
GrzegorzKozub added a commit to GrzegorzKozub/yazi that referenced this pull request Aug 5, 2025
@boydaihungst
Copy link
Contributor

Also, [open] > rules: name -> url

xfzv pushed a commit to xfzv/yazi that referenced this pull request Aug 6, 2025
xfzv pushed a commit to xfzv/yazi that referenced this pull request Aug 6, 2025
xfzv pushed a commit to xfzv/yazi that referenced this pull request Aug 6, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 5, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants