-
Notifications
You must be signed in to change notification settings - Fork 699
feat: new fs.copy() and fs.rename() APIs
#3467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this 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 adds new fs.copy() and fs.rename() Lua APIs to Yazi's plugin system, enabling scripts to programmatically copy and rename files. The implementation includes support for both local and SFTP filesystems, with appropriate error handling for cross-device operations.
Key changes include:
- New
fs.copy(from, to)andfs.rename(from, to)Lua APIs with proper error handling - Refactored
Attrsconversion logic fromFromtoTryFromto handle cases where attributes are empty or invalid - Updated dependencies (ratatui 0.29.0 → 0.30.0, with corresponding API updates)
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| yazi-plugin/src/fs/fs.rs | Adds Lua bindings for copy and rename operations, returning appropriate success/error values |
| yazi-fs/src/provider/attrs.rs | Converts From implementations to TryFrom for FileTimes and Permissions, adds helper methods |
| yazi-fs/src/provider/local/copier.rs | Updates attribute setting logic to use TryFrom pattern instead of unconditional conversion |
| yazi-vfs/src/provider/rw_file.rs | Refactors set_attrs to check for empty attributes and handle conversion failures gracefully |
| yazi-vfs/src/provider/sftp/*.rs | Updates SFTP provider to use TryFrom for attribute conversion with fallback to defaults |
| yazi-sftp/src/fs/attrs.rs | Adds is_empty() method and Eq/PartialEq derives to support empty attribute detection |
| yazi-binding/src/elements/border.rs | Updates ratatui API usage from deprecated Position to TitlePosition |
| yazi-plugin/src/utils/spot.rs | Updates ratatui API usage from deprecated Position to TitlePosition |
| yazi-fm/src/tasks/tasks.rs | Updates ratatui widget rendering API from render_ref to reference-based render |
| Cargo.toml | Upgrades ratatui (0.29.0 → 0.30.0), ansi-to-tui (7.0.0 → 8.0.0), and other dependencies |
| Cargo.lock | Reflects updated dependency versions and transitive dependencies |
| CHANGELOG.md | Documents the new fs.copy() and fs.rename() APIs |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pub async fn set_attrs(&self, attrs: Attrs) -> io::Result<()> { | ||
| match self { | ||
| Self::Tokio(f) => { | ||
| let (perm, times) = (attrs.try_into(), attrs.try_into()); |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type inference for these try_into() calls relies on the compiler determining which TryFrom implementation to use based on context. Consider adding explicit type annotations to improve code clarity and make the conversions more self-documenting.
| let (perm, times) = (attrs.try_into(), attrs.try_into()); | |
| let (perm, times): (Result<std::fs::Permissions, _>, Result<std::fs::FileTimes, _>) = | |
| (attrs.try_into(), attrs.try_into()); |
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [sxyazi/yazi](https://github.com/sxyazi/yazi) | minor | `v25.5.31` → `v25.12.29` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>sxyazi/yazi (sxyazi/yazi)</summary> ### [`v25.12.29`](https://github.com/sxyazi/yazi/blob/HEAD/CHANGELOG.md#v251229) [Compare Source](sxyazi/yazi@v25.5.31...v25.12.29) ##### Added - Remote file management (\[[#​3396](sxyazi/yazi#3396)]) - Virtual file system (\[[#​3034](sxyazi/yazi#3034)], \[[#​3035](sxyazi/yazi#3035)], \[[#​3094](sxyazi/yazi#3094)], \[[#​3108](sxyazi/yazi#3108)], \[[#​3187](sxyazi/yazi#3187)], \[[#​3203](sxyazi/yazi#3203)]) - Shell formatting (\[[#​3232](sxyazi/yazi#3232)]) - Multi-entry support for plugin system (\[[#​3154](sxyazi/yazi#3154)]) - Zoom in or out of the preview image (\[[#​2864](sxyazi/yazi#2864)]) - Improve the UX of the pick and input components (\[[#​2906](sxyazi/yazi#2906)], \[[#​2935](sxyazi/yazi#2935)]) - Show progress of each task in task manager (\[[#​3121](sxyazi/yazi#3121)], \[[#​3131](sxyazi/yazi#3131)], \[[#​3134](sxyazi/yazi#3134)]) - New `fs.copy()` and `fs.rename()` APIs (\[[#​3467](sxyazi/yazi#3467)]) - New experimental `ya.async()` API (\[[#​3422](sxyazi/yazi#3422)]) - New `overall` option to set the overall background color (\[[#​3317](sxyazi/yazi#3317)]) - Rounded corners for indicator bar (\[[#​3419](sxyazi/yazi#3419)]) - New `bulk_rename` command always renames files with the editor (\[[#​2984](sxyazi/yazi#2984)]) - `key-*` DDS events to allow changing or canceling user key events (\[[#​3005](sxyazi/yazi#3005)], \[[#​3037](sxyazi/yazi#3037)]) - New `--bg` specifying image background color in the preset SVG and ImageMagick previewers (\[[#​3189](sxyazi/yazi#3189)]) - `filter` by full path (prefix + filename) in search view instead of just filename (\[[#​2915](sxyazi/yazi#2915)]) - New `casefy` command for case conversion of the input content (\[[#​3235](sxyazi/yazi#3235)]) - Allow dynamic adjustment of layout ratio via `rt.mgr.ratio` (\[[#​2964](sxyazi/yazi#2964)]) - Support `.deb` packages (\[[#​2807](sxyazi/yazi#2807)], \[[#​3128](sxyazi/yazi#3128)], \[[#​3209](sxyazi/yazi#3209)]) - Port several widespread GUI keys to the input component (\[[#​2849](sxyazi/yazi#2849)]) - Support invalid UTF-8 paths throughout the codebase (\[[#​2884](sxyazi/yazi#2884)], \[[#​2889](sxyazi/yazi#2889)], \[[#​2890](sxyazi/yazi#2890)], \[[#​2895](sxyazi/yazi#2895)], \[[#​3023](sxyazi/yazi#3023)], \[[#​3290](sxyazi/yazi#3290)], \[[#​3369](sxyazi/yazi#3369)]) - Allow upgrading only specific packages with `ya pkg` (\[[#​2841](sxyazi/yazi#2841)]) - Respect the user's `image_filter` setting in the preset ImageMagick previewer (\[[#​3286](sxyazi/yazi#3286)]) - New `duplicate` DDS event for copying files (\[[#​3456](sxyazi/yazi#3456)]) - New `ind-sort` and `key-sort` DDS events to change sorting in Lua (\[[#​3391](sxyazi/yazi#3391)]) - Allow custom mouse click behavior for individual files (\[[#​2925](sxyazi/yazi#2925)]) - Display newlines in input as spaces to improve readability (\[[#​2932](sxyazi/yazi#2932)]) - Fill in error messages if preview fails (\[[#​2917](sxyazi/yazi#2917)], \[[#​3383](sxyazi/yazi#3383)], \[[#​3387](sxyazi/yazi#3387)]) - Search view shares file selection and yank state (\[[#​2855](sxyazi/yazi#2855)]) - Offload mimetype fetching on opening files to the task scheduler (\[[#​3141](sxyazi/yazi#3141)]) - Increase terminal response timeout to better tolerate slow SSH network environments (\[[#​2843](sxyazi/yazi#2843)]) ##### Changed - Rename `name` to `url` for open, fetchers, spotters, preloaders, previewers, filetype, and `globs` icon rules to support virtual file system (\[[#​3034](sxyazi/yazi#3034)]) - Rename `mime` fetcher to `mime.local`, and introduce `mime.dir` fetcher to support folder MIME types (\[[#​3222](sxyazi/yazi#3222)]) - Reclassify `hovered` and `preview_hovered` under `[mgr]` of `theme.toml` into `[indicator]` as `current` and `preview`, respectively (\[[#​3419](sxyazi/yazi#3419)]) - Remove `$0` parameter in opener rules to make the `open` command work under empty directories (\[[#​3226](sxyazi/yazi#3226)]) - Return `Path` instead of `Url` from `Url:strip_prefix()` and `File.link_to` to enforce type safety (\[[#​3361](sxyazi/yazi#3361)], \[[#​3385](sxyazi/yazi#3385)]) - Use `body` instead of the term `content` in confirmations (\[[#​2921](sxyazi/yazi#2921)]) - Use `u16` instead of `u32` as the type of `max_width` and `max_height` options to avoid memory exhaustion (\[[#​3313](sxyazi/yazi#3313)]) - Implement `__pairs` metamethod instead of `__index` for the callback argument of the `@yank` DDS event (\[[#​2997](sxyazi/yazi#2997)]) ##### Deprecated - Deprecate `$n`, `$@​` (\*nix) and `%n`, `%*` (Windows) in `shell` command and opener rules in favor of new shell formatting (\[[#​3232](sxyazi/yazi#3232)]) - Deprecate `ya.hide`, `ya.render`, and `ya.truncate` in favor of `ui.hide`, `ui.render`, and `ui.truncate` (\[[#​2939](sxyazi/yazi#2939)]) - Deprecate `position` property of `ya.input()` in favor of `pos` to align with `ya.confirm()` and its type `ui.Pos` (\[[#​2921](sxyazi/yazi#2921)]) - Deprecate `cx.tasks.progress` in favor of `cx.tasks.summary` (\[[#​3131](sxyazi/yazi#3131)]) - Deprecate `frag` properly of `Url` in favor of `domain` (\[[#​3034](sxyazi/yazi#3034)]) - Deprecate `ui.Rect.default` in favor of `ui.Rect {}` (\[[#​2927](sxyazi/yazi#2927)]) ##### Fixed - User-prepended open rules do not override presets (\[[#​3360](sxyazi/yazi#3360)]) - Respect user's system media opener instead of hardcoding `mpv` (\[[#​2959](sxyazi/yazi#2959)]) - Incorrect `$0` and `$@​` parameters in `shell` command under empty directories (\[[#​3225](sxyazi/yazi#3225)]) - Avoid appending a newline when reading clipboard contents (\[[#​3059](sxyazi/yazi#3059)]) - Renew package `rev` only when it's empty (\[[#​3200](sxyazi/yazi#3200)]) - Suspend only when there is a parent process (\[[#​3008](sxyazi/yazi#3008)]) - Preserve open order for files with post-resolved MIME types (\[[#​2931](sxyazi/yazi#2931)]) - A race condition in concurrent directory loading on a slow device (\[[#​3271](sxyazi/yazi#3271)]) - Erase overlapping image portions when previewing errors (\[[#​3067](sxyazi/yazi#3067)]) - Force Git checkout for plugin cache repositories (\[[#​3169](sxyazi/yazi#3169)]) - Check compatibility when reusing previewer bytecode cache (\[[#​3190](sxyazi/yazi#3190)]) - Disable kitty keyboard protocol on Windows due to `crossterm` inability to handle it (\[[#​3250](sxyazi/yazi#3250)]) - Prevent quotes in file(1) arguments from being stripped under MSYS2 (\[[#​3364](sxyazi/yazi#3364)]) - Expose `ya` CLI in the Snap build (\[[#​2904](sxyazi/yazi#2904)]) - Fallback to `PollWatcher` for file changes watching on NetBSD (\[[#​2941](sxyazi/yazi#2941)]) - Generate unique image IDs for Kgp to tolerate tmux (\[[#​3038](sxyazi/yazi#3038)]) ##### Improved - Make copy, cut, delete, link, hardlink, download, and upload tasks immediately cancellable (\[[#​3429](sxyazi/yazi#3429)]) - Make preload tasks discardable (\[[#​2875](sxyazi/yazi#2875)]) - Reduce file change event frequency (\[[#​2820](sxyazi/yazi#2820)]) - Upload and download of a single file over SFTP in chunks concurrently (\[[#​3393](sxyazi/yazi#3393)]) - Do not listen for file changes in inactive tabs (\[[#​2958](sxyazi/yazi#2958)]) - Switch to a higher-performance hash algorithm (\[[#​3083](sxyazi/yazi#3083)]) - Sequence-based rendering merge strategy (\[[#​2861](sxyazi/yazi#2861)]) - Store only `Urn` instead of full `Url` in find results (\[[#​2914](sxyazi/yazi#2914)]) - Zero-copy `UrlBuf` to `Url` conversion (\[[#​3117](sxyazi/yazi#3117)]) - String interning to reduce memory usage of mimetype and URL domain (\[[#​3084](sxyazi/yazi#3084)], \[[#​3091](sxyazi/yazi#3091)]) - Do not pre-allocate memory for Lua tables (\[[#​2879](sxyazi/yazi#2879)]) - Copy-on-write on command data, and avoid converting primitive types to strings thereby allocating memory (\[[#​2862](sxyazi/yazi#2862)]) - Use `AnyUserData::type_id()` to reduce stack pushes (\[[#​2834](sxyazi/yazi#2834)]) - App data instead of Lua registry to reduce stack pushes (\[[#​2880](sxyazi/yazi#2880)]) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi42Ni4xMSIsInVwZGF0ZWRJblZlciI6IjQyLjY2LjExIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWlub3IiXX0=-->
An implementation of the feature request: #3408
fs.copy(from, to)- copy a filefrom: source file URLto: destination URL(len, err)len: length of the copied content, which is an integer, ornilif the operation failserr:Errorof the failureNotes:
fromandtoare the same file, the file will likely get truncated by this operation.fromandtoif they exist.fs.rename(from, to)- rename a filefrom: source file URLto: destination URL(ok, err)ok: whether this operation succeeds, which is a booleanerr:Errorof the failureNotes:
fromandtoare on different filesystems.If you want to move files across filesystems, use the combination
fs.copy()andfs.remove():