fix!: introduce a new btime term to align ctime with Unix

This commit is contained in:
sxyazi 2024-10-11 17:26:28 +08:00
parent 558d97d084
commit 8b47ebf2ce
No known key found for this signature in database
76 changed files with 285 additions and 240 deletions

17
Cargo.lock generated
View file

@ -3247,6 +3247,14 @@ dependencies = [
"yazi-shared",
]
[[package]]
name = "yazi-codegen"
version = "0.3.3"
dependencies = [
"quote",
"syn 2.0.79",
]
[[package]]
name = "yazi-config"
version = "0.3.3"
@ -3287,10 +3295,10 @@ dependencies = [
"unicode-width",
"yazi-adapter",
"yazi-boot",
"yazi-codegen",
"yazi-config",
"yazi-dds",
"yazi-fs",
"yazi-macro",
"yazi-plugin",
"yazi-proxy",
"yazi-scheduler",
@ -3339,11 +3347,11 @@ dependencies = [
"tracing-subscriber",
"yazi-adapter",
"yazi-boot",
"yazi-codegen",
"yazi-config",
"yazi-core",
"yazi-dds",
"yazi-fs",
"yazi-macro",
"yazi-plugin",
"yazi-proxy",
"yazi-shared",
@ -3366,10 +3374,6 @@ dependencies = [
[[package]]
name = "yazi-macro"
version = "0.3.3"
dependencies = [
"quote",
"syn 2.0.79",
]
[[package]]
name = "yazi-plugin"
@ -3460,6 +3464,7 @@ dependencies = [
"tokio",
"uzers",
"windows-sys 0.59.0",
"yazi-macro",
]
[[package]]

View file

@ -1 +1 @@
{"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp"," Überzug"," Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK"],"version":"0.2","language":"en","flagWords":[]}
{"language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp"," Überzug"," Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen"],"version":"0.2","flagWords":[]}

View file

@ -113,10 +113,11 @@ impl Emulator {
}
let mut term = std::env::var("TERM").unwrap_or_default();
let program = std::env::var("TERM_PROGRAM").unwrap_or_default();
let mut program = std::env::var("TERM_PROGRAM").unwrap_or_default();
if *TMUX {
term = tmux_env("TERM").unwrap_or(term);
program = tmux_env("TERM_PROGRAM").unwrap_or(program);
}
(term, program)

17
yazi-codegen/Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "yazi-codegen"
version = "0.3.3"
edition = "2021"
license = "MIT"
authors = [ "sxyazi <sxyazi@gmail.com>" ]
description = "Yazi codegen"
homepage = "https://yazi-rs.github.io"
repository = "https://github.com/sxyazi/yazi"
[lib]
proc-macro = true
[dependencies]
# External dependencies
syn = "2.0.79"
quote = "1.0.37"

41
yazi-codegen/src/lib.rs Normal file
View file

@ -0,0 +1,41 @@
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{FnArg, ItemFn};
#[proc_macro_attribute]
pub fn command(_: TokenStream, item: TokenStream) -> TokenStream {
let mut f: ItemFn = syn::parse(item).unwrap();
let mut ins = f.sig.inputs.clone();
// Turn `opt: Opt` into `opt: impl Into<Opt>`
ins[1] = {
let FnArg::Typed(opt) = &f.sig.inputs[1] else {
panic!("Cannot find the `opt` argument in the function signature.");
};
let opt_ty = &opt.ty;
syn::parse2(quote! { opt: impl Into<#opt_ty> }).unwrap()
};
// Make the original function private and add a public wrapper
assert!(matches!(f.vis, syn::Visibility::Public(_)));
f.vis = syn::Visibility::Inherited;
// Add `__` prefix to the original function name
let name_ori = f.sig.ident;
f.sig.ident = format_ident!("__{}", name_ori);
let name_new = &f.sig.ident;
// Collect the rest of the arguments
let rest_args = ins.iter().skip(2).map(|arg| match arg {
FnArg::Receiver(_) => unreachable!(),
FnArg::Typed(t) => &t.pat,
});
quote! {
#[inline]
pub fn #name_ori(#ins) { self.#name_new(opt.into(), #(#rest_args),*); }
#f
}
.into()
}

View file

@ -83,7 +83,7 @@ keymap = [
# Linemode
{ on = [ "m", "s" ], run = "linemode size", desc = "Linemode: size" },
{ on = [ "m", "p" ], run = "linemode permissions", desc = "Linemode: permissions" },
{ on = [ "m", "c" ], run = "linemode ctime", desc = "Linemode: ctime" },
{ on = [ "m", "b" ], run = "linemode btime", desc = "Linemode: btime" },
{ on = [ "m", "m" ], run = "linemode mtime", desc = "Linemode: mtime" },
{ on = [ "m", "o" ], run = "linemode owner", desc = "Linemode: owner" },
{ on = [ "m", "n" ], run = "linemode none", desc = "Linemode: none" },
@ -104,19 +104,19 @@ keymap = [
{ on = "N", run = "find_arrow --previous", desc = "Goto the previous found" },
# Sorting
{ on = [ ",", "m" ], run = [ "sort modified --reverse=no", "linemode mtime" ], desc = "Sort by modified time" },
{ on = [ ",", "M" ], run = [ "sort modified --reverse", "linemode mtime" ], desc = "Sort by modified time (reverse)" },
{ on = [ ",", "c" ], run = [ "sort created --reverse=no", "linemode ctime" ], desc = "Sort by created time" },
{ on = [ ",", "C" ], run = [ "sort created --reverse", "linemode ctime" ], desc = "Sort by created time (reverse)" },
{ on = [ ",", "e" ], run = "sort extension --reverse=no", desc = "Sort by extension" },
{ on = [ ",", "E" ], run = "sort extension --reverse", desc = "Sort by extension (reverse)" },
{ on = [ ",", "a" ], run = "sort alphabetical --reverse=no", desc = "Sort alphabetically" },
{ on = [ ",", "A" ], run = "sort alphabetical --reverse", desc = "Sort alphabetically (reverse)" },
{ on = [ ",", "n" ], run = "sort natural --reverse=no", desc = "Sort naturally" },
{ on = [ ",", "N" ], run = "sort natural --reverse", desc = "Sort naturally (reverse)" },
{ on = [ ",", "s" ], run = [ "sort size --reverse=no", "linemode size" ], desc = "Sort by size" },
{ on = [ ",", "S" ], run = [ "sort size --reverse", "linemode size" ], desc = "Sort by size (reverse)" },
{ on = [ ",", "r" ], run = "sort random --reverse=no", desc = "Sort randomly" },
{ on = [ ",", "m" ], run = [ "sort mtime --reverse=no", "linemode mtime" ], desc = "Sort by modified time" },
{ on = [ ",", "M" ], run = [ "sort mtime --reverse", "linemode mtime" ], desc = "Sort by modified time (reverse)" },
{ on = [ ",", "b" ], run = [ "sort btime --reverse=no", "linemode btime" ], desc = "Sort by birth time" },
{ on = [ ",", "B" ], run = [ "sort btime --reverse", "linemode btime" ], desc = "Sort by birth time (reverse)" },
{ on = [ ",", "e" ], run = "sort extension --reverse=no", desc = "Sort by extension" },
{ on = [ ",", "E" ], run = "sort extension --reverse", desc = "Sort by extension (reverse)" },
{ on = [ ",", "a" ], run = "sort alphabetical --reverse=no", desc = "Sort alphabetically" },
{ on = [ ",", "A" ], run = "sort alphabetical --reverse", desc = "Sort alphabetically (reverse)" },
{ on = [ ",", "n" ], run = "sort natural --reverse=no", desc = "Sort naturally" },
{ on = [ ",", "N" ], run = "sort natural --reverse", desc = "Sort naturally (reverse)" },
{ on = [ ",", "s" ], run = [ "sort size --reverse=no", "linemode size" ], desc = "Sort by size" },
{ on = [ ",", "S" ], run = [ "sort size --reverse", "linemode size" ], desc = "Sort by size (reverse)" },
{ on = [ ",", "r" ], run = "sort random --reverse=no", desc = "Sort randomly" },
# Goto
{ on = [ "g", "h" ], run = "cd ~", desc = "Go home" },

View file

@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize};
pub enum SortBy {
#[default]
None,
Modified,
Created,
Mtime,
Btime,
Extension,
Alphabetical,
Natural,
@ -23,8 +23,8 @@ impl FromStr for SortBy {
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"none" => Self::None,
"modified" => Self::Modified,
"created" => Self::Created,
"mtime" => Self::Mtime,
"btime" => Self::Btime,
"extension" => Self::Extension,
"alphabetical" => Self::Alphabetical,
"natural" => Self::Natural,
@ -45,8 +45,8 @@ impl Display for SortBy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::None => "none",
Self::Modified => "modified",
Self::Created => "created",
Self::Mtime => "mtime",
Self::Btime => "btime",
Self::Extension => "extension",
Self::Alphabetical => "alphabetical",
Self::Natural => "natural",

View file

@ -11,10 +11,10 @@ repository = "https://github.com/sxyazi/yazi"
[dependencies]
yazi-adapter = { path = "../yazi-adapter", version = "0.3.3" }
yazi-boot = { path = "../yazi-boot", version = "0.3.3" }
yazi-codegen = { path = "../yazi-codegen", version = "0.3.3" }
yazi-config = { path = "../yazi-config", version = "0.3.3" }
yazi-dds = { path = "../yazi-dds", version = "0.3.3" }
yazi-fs = { path = "../yazi-fs", version = "0.3.3" }
yazi-macro = { path = "../yazi-macro", version = "0.3.3" }
yazi-plugin = { path = "../yazi-plugin", version = "0.3.3" }
yazi-proxy = { path = "../yazi-proxy", version = "0.3.3" }
yazi-scheduler = { path = "../yazi-scheduler", version = "0.3.3" }

View file

@ -11,7 +11,7 @@ impl From<Cmd> for Opt {
}
impl Completion {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn arrow(&mut self, opt: Opt) {
if opt.step > 0 {
self.next(opt.step as usize);

View file

@ -15,7 +15,7 @@ impl From<bool> for Opt {
}
impl Completion {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn close(&mut self, opt: Opt) {
if let Some(s) = self.selected().filter(|_| opt.submit) {
InputProxy::complete(s, self.ticket);

View file

@ -25,7 +25,7 @@ impl From<Cmd> for Opt {
}
impl Completion {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn show(&mut self, opt: Opt) {
if self.ticket != opt.ticket {
return;

View file

@ -26,7 +26,7 @@ impl From<Cmd> for Opt {
}
impl Completion {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn trigger(&mut self, opt: Opt) {
if opt.ticket < self.ticket {
return;

View file

@ -11,7 +11,7 @@ impl From<Cmd> for Opt {
}
impl Confirm {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn arrow(&mut self, opt: Opt, manager: &Manager) {
if opt.step > 0 {
self.next(opt.step as usize, manager.area(self.position).width)

View file

@ -14,7 +14,7 @@ impl From<bool> for Opt {
}
impl Confirm {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn close(&mut self, opt: Opt) {
if let Some(cb) = self.callback.take() {
_ = cb.send(opt.submit);

View file

@ -14,7 +14,7 @@ impl From<isize> for Opt {
}
impl Help {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn arrow(&mut self, opt: Opt) {
let max = self.bindings.len().saturating_sub(1);
self.offset = self.offset.min(max);

View file

@ -14,7 +14,7 @@ impl From<bool> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn backspace(&mut self, opt: Opt) {
let snap = self.snaps.current_mut();
if !opt.under && snap.cursor < 1 {

View file

@ -15,7 +15,7 @@ impl From<bool> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn close(&mut self, opt: Opt) {
if self.completion {
CompletionProxy::close();

View file

@ -25,7 +25,7 @@ impl From<Cmd> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn complete(&mut self, opt: Opt) {
if self.ticket != opt.ticket {
return;

View file

@ -12,7 +12,7 @@ impl From<Cmd> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn delete(&mut self, opt: Opt) {
match self.snap().op {
InputOp::None => {

View file

@ -13,7 +13,7 @@ impl From<()> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn escape(&mut self, _: Opt) {
let snap = self.snap_mut();
match snap.mode {

View file

@ -11,7 +11,7 @@ impl From<Cmd> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn forward(&mut self, opt: Opt) {
let snap = self.snap();

View file

@ -14,7 +14,7 @@ impl From<bool> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn insert(&mut self, opt: Opt) {
let snap = self.snap_mut();
if snap.mode == InputMode::Normal {

View file

@ -13,7 +13,7 @@ impl From<Cmd> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn kill(&mut self, opt: Opt) {
let snap = self.snap_mut();
match opt.kind.as_str() {

View file

@ -21,7 +21,7 @@ impl From<isize> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn move_(&mut self, opt: Opt) {
let snap = self.snap();
if opt.in_operating && snap.op == InputOp::None {

View file

@ -12,7 +12,7 @@ impl From<Cmd> for Opt {
}
impl Input {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn paste(&mut self, opt: Opt) {
if let Some(start) = self.snap().op.start() {
self.snap_mut().op = InputOp::Delete(false, false, start);

View file

@ -18,7 +18,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn create(&self, opt: Opt) {
let cwd = self.cwd().to_owned();
tokio::spawn(async move {

View file

@ -12,7 +12,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn hardlink(&mut self, opt: Opt, tasks: &Tasks) {
if self.yanked.cut {
return;

View file

@ -23,7 +23,7 @@ impl From<Option<Url>> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn hover(&mut self, opt: Opt) {
if let Some(u) = opt.url {
self.hover_do(u, opt.tab);

View file

@ -12,7 +12,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn link(&mut self, opt: Opt, tasks: &Tasks) {
if self.yanked.cut {
return;

View file

@ -23,7 +23,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn open(&mut self, opt: Opt, tasks: &Tasks) {
if !self.active_mut().try_escape_visual() {
return;
@ -72,7 +72,7 @@ impl Manager {
});
}
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn open_do(&mut self, opt: OpenDoOpt, tasks: &Tasks) {
let targets: Vec<_> = opt
.targets

View file

@ -12,7 +12,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn paste(&mut self, opt: Opt, tasks: &Tasks) {
let (src, dest) = (self.yanked.iter().collect::<Vec<_>>(), self.cwd());

View file

@ -25,7 +25,7 @@ impl From<bool> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn peek(&mut self, opt: Opt) {
let Some(hovered) = self.hovered().cloned() else {
return self.active_mut().preview.reset();

View file

@ -19,7 +19,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn quit(&self, opt: Opt, tasks: &Tasks) {
let opt = EventQuit { no_cwd_file: opt.no_cwd_file, ..Default::default() };

View file

@ -23,7 +23,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn remove(&mut self, mut opt: Opt, tasks: &Tasks) {
if !self.active_mut().try_escape_visual() {
return;
@ -55,7 +55,7 @@ impl Manager {
});
}
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn remove_do(&mut self, opt: Opt, tasks: &Tasks) {
self.tabs.iter_mut().for_each(|t| {
t.selected.remove_many(&opt.targets, false);

View file

@ -28,7 +28,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn rename(&mut self, opt: Opt) {
if !self.active_mut().try_escape_visual() {
return;

View file

@ -14,7 +14,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn seek(&mut self, opt: Opt) {
let Some(hovered) = self.hovered() else {
return self.active_mut().preview.reset();

View file

@ -15,7 +15,7 @@ impl From<usize> for Opt {
}
impl Tabs {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn close(&mut self, opt: Opt) {
let len = self.items.len();
if len < 2 || opt.idx >= len {

View file

@ -28,7 +28,7 @@ impl From<Cmd> for Opt {
}
impl Tabs {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn create(&mut self, opt: Opt) {
if self.items.len() >= MAX_TABS {
AppProxy::notify_warn("Too many tabs", "You can only open up to 9 tabs at the same time.");

View file

@ -11,7 +11,7 @@ impl From<Cmd> for Opt {
}
impl Tabs {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn swap(&mut self, opt: Opt) {
let idx = self.absolute(opt.step);
if idx == self.cursor {

View file

@ -14,7 +14,7 @@ impl From<Cmd> for Opt {
}
impl Tabs {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn switch(&mut self, opt: Opt) {
let idx = if opt.relative {
(self.cursor as isize + opt.step).rem_euclid(self.items.len() as isize) as usize

View file

@ -12,7 +12,7 @@ impl From<()> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn unyank(&mut self, _: Opt) {
self.yanked.clear();
render!(self.yanked.catchup_revision(false));

View file

@ -11,7 +11,7 @@ impl From<Cmd> for Opt {
}
impl Manager {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn yank(&mut self, opt: Opt) {
if !self.active_mut().try_escape_visual() {
return;

View file

@ -11,7 +11,7 @@ impl From<Cmd> for Opt {
}
impl Select {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn arrow(&mut self, opt: Opt) {
if opt.step > 0 { self.next(opt.step as usize) } else { self.prev(opt.step.unsigned_abs()) }
}

View file

@ -15,7 +15,7 @@ impl From<bool> for Opt {
}
impl Select {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn close(&mut self, opt: Opt) {
if let Some(cb) = self.callback.take() {
_ = cb.send(if opt.submit { Ok(self.cursor) } else { Err(anyhow!("canceled")) });

View file

@ -25,7 +25,7 @@ impl From<isize> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn arrow(&mut self, opt: Opt) {
if !self.current.arrow(opt.step) {
return;

View file

@ -29,7 +29,7 @@ impl From<Url> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn cd(&mut self, opt: Opt) {
if !self.try_escape_visual() {
return;

View file

@ -14,7 +14,7 @@ impl From<Cmd> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn copy(&mut self, opt: Opt) {
if !self.try_escape_visual() {
return;

View file

@ -31,7 +31,7 @@ impl From<Cmd> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn escape(&mut self, opt: Opt) {
if opt.is_empty() {
_ = self.escape_find()

View file

@ -27,7 +27,7 @@ impl From<Cmd> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn filter(&mut self, opt: Opt) {
tokio::spawn(async move {
let rx = InputProxy::show(InputCfg::filter());

View file

@ -6,7 +6,7 @@ use super::filter::Opt;
use crate::tab::Tab;
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn filter_do(&mut self, opt: Opt) {
let filter = if opt.query.is_empty() {
None

View file

@ -22,7 +22,7 @@ impl From<Cmd> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn find(&mut self, opt: Opt) {
tokio::spawn(async move {
let rx = InputProxy::show(InputCfg::find(opt.prev));

View file

@ -11,7 +11,7 @@ impl From<Cmd> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn find_arrow(&mut self, opt: Opt) {
let Some(finder) = &mut self.finder else {
return;

View file

@ -4,7 +4,7 @@ use super::find::Opt;
use crate::tab::{Finder, Tab};
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn find_do(&mut self, opt: Opt) {
let Some(query) = opt.query else {
return;

View file

@ -11,7 +11,7 @@ impl From<Cmd> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn leave(&mut self, _: Opt) {
self
.current

View file

@ -22,7 +22,7 @@ impl From<Url> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn reveal(&mut self, opt: Opt) {
let Some(parent) = opt.target.parent_url() else {
return;

View file

@ -24,7 +24,7 @@ impl<'a> From<Cmd> for Opt<'a> {
}
impl<'a> Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn select(&mut self, opt: Opt<'a>) {
let Some(url) = opt.url.or_else(|| self.current.hovered().map(|h| Cow::Borrowed(&h.url)))
else {

View file

@ -23,7 +23,7 @@ impl From<Option<bool>> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn select_all(&mut self, opt: Opt) {
let iter = self.current.files.iter().map(|f| &f.url);
let (removal, addition): (Vec<_>, Vec<_>) = match opt.state {

View file

@ -13,7 +13,7 @@ impl From<Cmd> for Opt {
}
impl Tab {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn visual_mode(&mut self, opt: Opt) {
let idx = self.current.cursor;
if opt.unset {

View file

@ -15,7 +15,7 @@ impl From<isize> for Opt {
}
impl Tasks {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn arrow(&mut self, opt: Opt) {
let old = self.cursor;
if opt.step > 0 {

View file

@ -12,7 +12,7 @@ impl From<()> for Opt {
}
impl Tasks {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn toggle(&mut self, _: Opt) {
self.visible = !self.visible;

View file

@ -15,11 +15,11 @@ vendored-lua = [ "mlua/vendored" ]
[dependencies]
yazi-adapter = { path = "../yazi-adapter", version = "0.3.3" }
yazi-boot = { path = "../yazi-boot", version = "0.3.3" }
yazi-codegen = { path = "../yazi-codegen", version = "0.3.3" }
yazi-config = { path = "../yazi-config", version = "0.3.3" }
yazi-core = { path = "../yazi-core", version = "0.3.3" }
yazi-dds = { path = "../yazi-dds", version = "0.3.3" }
yazi-fs = { path = "../yazi-fs", version = "0.3.3" }
yazi-macro = { path = "../yazi-macro", version = "0.3.3" }
yazi-plugin = { path = "../yazi-plugin", version = "0.3.3" }
yazi-proxy = { path = "../yazi-proxy", version = "0.3.3" }
yazi-shared = { path = "../yazi-shared", version = "0.3.3" }

View file

@ -15,7 +15,7 @@ impl From<MouseEvent> for Opt {
}
impl App {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn mouse(&mut self, opt: Opt) {
let event = opt.event;
let Some(size) = self.term.as_ref().and_then(|t| t.size().ok()) else { return };

View file

@ -13,7 +13,7 @@ impl From<()> for Opt {
}
impl App {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn resize(&mut self, _: Opt) {
self.cx.manager.active_mut().preview.reset();
self.render();

View file

@ -12,7 +12,7 @@ impl From<Cmd> for Opt {
}
impl App {
#[yazi_macro::command]
#[yazi_codegen::command]
pub fn stop(&mut self, opt: Opt) {
self.cx.manager.active_mut().preview.reset_image();

View file

@ -28,12 +28,12 @@ impl FilesSorter {
match self.by {
SortBy::None => {}
SortBy::Modified => items.sort_unstable_by(|a, b| {
SortBy::Mtime => items.sort_unstable_by(|a, b| {
let ord = self.cmp(a.mtime, b.mtime, self.promote(a, b));
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
}),
SortBy::Created => items.sort_unstable_by(|a, b| {
let ord = self.cmp(a.ctime, b.ctime, self.promote(a, b));
SortBy::Btime => items.sort_unstable_by(|a, b| {
let ord = self.cmp(a.btime, b.btime, self.promote(a, b));
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
}),
SortBy::Extension => items.sort_unstable_by(|a, b| {

View file

@ -7,11 +7,3 @@ authors = [ "sxyazi <sxyazi@gmail.com>" ]
description = "Yazi macros"
homepage = "https://yazi-rs.github.io"
repository = "https://github.com/sxyazi/yazi"
[lib]
proc-macro = true
[dependencies]
# External dependencies
syn = "2.0.79"
quote = "1.0.37"

View file

@ -1,41 +1,2 @@
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{FnArg, ItemFn};
#[proc_macro_attribute]
pub fn command(_: TokenStream, item: TokenStream) -> TokenStream {
let mut f: ItemFn = syn::parse(item).unwrap();
let mut ins = f.sig.inputs.clone();
// Turn `opt: Opt` into `opt: impl Into<Opt>`
ins[1] = {
let FnArg::Typed(opt) = &f.sig.inputs[1] else {
panic!("Cannot find the `opt` argument in the function signature.");
};
let opt_ty = &opt.ty;
syn::parse2(quote! { opt: impl Into<#opt_ty> }).unwrap()
};
// Make the original function private and add a public wrapper
assert!(matches!(f.vis, syn::Visibility::Public(_)));
f.vis = syn::Visibility::Inherited;
// Add `__` prefix to the original function name
let name_ori = f.sig.ident;
f.sig.ident = format_ident!("__{}", name_ori);
let name_new = &f.sig.ident;
// Collect the rest of the arguments
let rest_args = ins.iter().skip(2).map(|arg| match arg {
FnArg::Receiver(_) => unreachable!(),
FnArg::Typed(t) => &t.pat,
});
quote! {
#[inline]
pub fn #name_ori(#ins) { self.#name_new(opt.into(), #(#rest_args),*); }
#f
}
.into()
}
mod module;
mod platform;

9
yazi-macro/src/module.rs Normal file
View file

@ -0,0 +1,9 @@
#[macro_export]
macro_rules! mod_use {
[ $( $name:ident $(,)? )+ ] => {
$(
mod $name;
pub use $name::*;
)+
};
}

View file

@ -0,0 +1,13 @@
#[macro_export]
macro_rules! unix_either {
($a:expr, $b:expr) => {{
#[cfg(unix)]
{
$a
}
#[cfg(not(unix))]
{
$b
}
}};
}

View file

@ -32,8 +32,8 @@ function Linemode:size()
end
end
function Linemode:ctime()
local time = (self._file.cha.created or 0) // 1
function Linemode:btime()
local time = math.floor(self._file.cha.btime or 0)
if time == 0 then
return ui.Line("")
elseif os.date("%Y", time) == os.date("%Y") then
@ -44,7 +44,7 @@ function Linemode:ctime()
end
function Linemode:mtime()
local time = (self._file.cha.modified or 0) // 1
local time = math.floor(self._file.cha.mtime or 0)
if time == 0 then
return ui.Line("")
elseif os.date("%Y", time) == os.date("%Y") then
@ -54,7 +54,7 @@ function Linemode:mtime()
end
end
function Linemode:permissions() return ui.Line(self._file.cha:permissions() or "") end
function Linemode:permissions() return ui.Line(self._file.cha:perm() or "") end
function Linemode:owner()
local user = self._file.cha.uid and ya.user_name(self._file.cha.uid) or self._file.cha.uid

View file

@ -52,7 +52,7 @@ function Status:size()
local style = self:style()
return ui.Line {
ui.Span(" " .. ya.readable_size(h:size() or h.cha.length) .. " "):fg(style.bg):bg(THEME.status.separator_style.bg),
ui.Span(" " .. ya.readable_size(h:size() or h.cha.len) .. " "):fg(style.bg):bg(THEME.status.separator_style.bg),
ui.Span(THEME.status.separator_close):fg(THEME.status.separator_style.fg),
}
end
@ -72,7 +72,7 @@ function Status:permissions()
return ui.Line {}
end
local perm = h.cha:permissions()
local perm = h.cha:perm()
if not perm then
return ui.Line {}
end

View file

@ -34,7 +34,7 @@ function M:preload()
end
local cha = fs.cha(cache)
if cha and cha.length > 0 then
if cha and cha.len > 0 then
return 1
end

View file

@ -7,6 +7,22 @@ use crate::bindings::Cast;
pub struct Cha;
static WARNED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
#[inline]
fn warn_deprecated() {
if !WARNED.swap(true, std::sync::atomic::Ordering::Relaxed) {
yazi_proxy::AppProxy::notify(yazi_proxy::options::NotifyOpt {
title: "Deprecated API".to_owned(),
content: "The `created`, `modified`, `accessed`, `length`, and `permissions` properties of `Cha` have been deprecated.
Please use the new `btime`, `mtime`, `atime`, `len`, and `perm` instead.".to_string(),
level: yazi_proxy::options::NotifyLevel::Warn,
timeout: Duration::from_secs(20),
});
}
}
impl Cha {
pub fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<yazi_shared::fs::Cha>(|reg| {
@ -29,17 +45,21 @@ impl Cha {
reg.add_field_method_get("nlink", |_, me| Ok((!me.is_dummy()).then_some(me.nlink)));
}
reg.add_field_method_get("length", |_, me| Ok(me.len));
reg.add_field_method_get("created", |_, me| {
Ok(me.ctime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
reg.add_field_method_get("modified", |_, me| {
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
reg.add_field_method_get("accessed", |_, me| {
reg.add_field_method_get("len", |_, me| Ok(me.len));
reg.add_field_method_get("atime", |_, me| {
Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
reg.add_method("permissions", |_, _me, ()| {
reg.add_field_method_get("btime", |_, me| {
Ok(me.btime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
#[cfg(unix)]
reg.add_field_method_get("ctime", |_, me| {
Ok(me.ctime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
reg.add_field_method_get("mtime", |_, me| {
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
reg.add_method("perm", |_, _me, ()| {
Ok(
#[cfg(unix)]
Some(yazi_shared::fs::permissions(_me.perm, _me.is_dummy())),
@ -47,6 +67,35 @@ impl Cha {
None::<String>,
)
});
// TODO: remove these deprecated properties in the future
{
reg.add_field_method_get("length", |_, me| {
warn_deprecated();
Ok(me.len)
});
reg.add_field_method_get("created", |_, me| {
warn_deprecated();
Ok(me.btime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
reg.add_field_method_get("modified", |_, me| {
warn_deprecated();
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
reg.add_field_method_get("accessed", |_, me| {
warn_deprecated();
Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
reg.add_method("permissions", |_, _me, ()| {
warn_deprecated();
Ok(
#[cfg(unix)]
Some(yazi_shared::fs::permissions(_me.perm, _me.is_dummy())),
#[cfg(windows)]
None::<String>,
)
});
}
})?;
Ok(())
@ -72,6 +121,8 @@ impl Cha {
kind,
len: t.raw_get("len").unwrap_or_default(),
atime: parse_time(t.raw_get("atime").ok())?,
btime: parse_time(t.raw_get("btime").ok())?,
#[cfg(unix)]
ctime: parse_time(t.raw_get("ctime").ok())?,
mtime: parse_time(t.raw_get("mtime").ok())?,
#[cfg(unix)]

View file

@ -27,27 +27,21 @@ impl AppProxy {
#[inline]
pub fn notify_warn(title: &str, content: impl ToString) {
emit!(Call(
Cmd::new("notify").with_any("option", NotifyOpt {
title: title.to_owned(),
content: content.to_string(),
level: NotifyLevel::Warn,
timeout: Duration::from_secs(5),
}),
Layer::App
));
Self::notify(NotifyOpt {
title: title.to_owned(),
content: content.to_string(),
level: NotifyLevel::Warn,
timeout: Duration::from_secs(5),
});
}
#[inline]
pub fn notify_error(title: &str, content: impl ToString) {
emit!(Call(
Cmd::new("notify").with_any("option", NotifyOpt {
title: title.to_owned(),
content: content.to_string(),
level: NotifyLevel::Error,
timeout: Duration::from_secs(10),
}),
Layer::App
));
Self::notify(NotifyOpt {
title: title.to_owned(),
content: content.to_string(),
level: NotifyLevel::Error,
timeout: Duration::from_secs(10),
});
}
}

View file

@ -10,6 +10,9 @@ repository = "https://github.com/sxyazi/yazi"
rust-version = "1.78.0"
[dependencies]
yazi-macro = { path = "../yazi-macro", version = "0.3.3" }
# External dependencies
anyhow = { workspace = true }
bitflags = { workspace = true }
crossterm = { workspace = true }

View file

@ -1,6 +1,7 @@
use std::{fs::{FileType, Metadata}, time::SystemTime};
use bitflags::bitflags;
use yazi_macro::unix_either;
bitflags! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
@ -20,6 +21,8 @@ pub struct Cha {
pub kind: ChaKind,
pub len: u64,
pub atime: Option<SystemTime>,
pub btime: Option<SystemTime>,
#[cfg(unix)]
pub ctime: Option<SystemTime>,
pub mtime: Option<SystemTime>,
#[cfg(unix)]
@ -40,11 +43,16 @@ impl From<Metadata> for Cha {
}
Self {
kind: ck,
len: m.len(),
atime: m.accessed().ok(),
ctime: m.created().ok(),
mtime: m.modified().ok(),
kind: ck,
len: m.len(),
atime: m.accessed().ok(),
btime: m.created().ok(),
#[cfg(unix)]
ctime: {
use std::{os::unix::fs::MetadataExt, time::{Duration, UNIX_EPOCH}};
UNIX_EPOCH.checked_add(Duration::new(m.ctime() as u64, m.ctime_nsec() as u32))
},
mtime: m.modified().ok(),
#[cfg(unix)]
perm: {
@ -126,16 +134,12 @@ impl Cha {
#[inline]
pub fn hits(self, c: Self) -> bool {
self.len == c.len && self.mtime == c.mtime && self.ctime == c.ctime && self.kind == c.kind && {
#[cfg(unix)]
{
self.perm == c.perm
}
#[cfg(windows)]
{
true
}
}
self.len == c.len
&& self.mtime == c.mtime
&& unix_either!(self.ctime == c.ctime, true)
&& self.btime == c.btime
&& self.kind == c.kind
&& unix_either!(self.perm == c.perm, true)
}
}
@ -157,73 +161,27 @@ impl Cha {
#[inline]
pub const fn is_block(&self) -> bool {
#[cfg(unix)]
{
self.perm & libc::S_IFMT == libc::S_IFBLK
}
#[cfg(windows)]
{
false
}
unix_either!(self.perm & libc::S_IFMT == libc::S_IFBLK, false)
}
#[inline]
pub const fn is_char(&self) -> bool {
#[cfg(unix)]
{
self.perm & libc::S_IFMT == libc::S_IFCHR
}
#[cfg(windows)]
{
false
}
unix_either!(self.perm & libc::S_IFMT == libc::S_IFCHR, false)
}
#[inline]
pub const fn is_fifo(&self) -> bool {
#[cfg(unix)]
{
self.perm & libc::S_IFMT == libc::S_IFIFO
}
#[cfg(windows)]
{
false
}
unix_either!(self.perm & libc::S_IFMT == libc::S_IFIFO, false)
}
#[inline]
pub const fn is_sock(&self) -> bool {
#[cfg(unix)]
{
self.perm & libc::S_IFMT == libc::S_IFSOCK
}
#[cfg(windows)]
{
false
}
unix_either!(self.perm & libc::S_IFMT == libc::S_IFSOCK, false)
}
#[inline]
pub const fn is_exec(&self) -> bool {
#[cfg(unix)]
{
self.perm & libc::S_IXUSR != 0
}
#[cfg(windows)]
{
false
}
}
pub const fn is_exec(&self) -> bool { unix_either!(self.perm & libc::S_IXUSR != 0, false) }
#[inline]
pub const fn is_sticky(&self) -> bool {
#[cfg(unix)]
{
self.perm & libc::S_ISVTX != 0
}
#[cfg(windows)]
{
false
}
}
pub const fn is_sticky(&self) -> bool { unix_either!(self.perm & libc::S_ISVTX != 0, false) }
}