Skip to content

Commit

Permalink
feat: new extract builtin plugin for archive extracting (#1321)
Browse files Browse the repository at this point in the history
  • Loading branch information
sxyazi authored Jul 28, 2024
1 parent f024ce0 commit bce0fc1
Show file tree
Hide file tree
Showing 42 changed files with 702 additions and 344 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions yazi-boot/src/actions/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ impl Actions {
writeln!(s, "\nVariables")?;
writeln!(s, " SHELL : {:?}", env::var_os("SHELL"))?;
writeln!(s, " EDITOR : {:?}", env::var_os("EDITOR"))?;
writeln!(s, " ZELLIJ_SESSION_NAME: {:?}", env::var_os("ZELLIJ_SESSION_NAME"))?;
writeln!(s, " YAZI_FILE_ONE : {:?}", env::var_os("YAZI_FILE_ONE"))?;
writeln!(s, " YAZI_CONFIG_HOME : {:?}", env::var_os("YAZI_CONFIG_HOME"))?;
writeln!(s, " ZELLIJ_SESSION_NAME: {:?}", env::var_os("ZELLIJ_SESSION_NAME"))?;

writeln!(s, "\nText Opener")?;
writeln!(
Expand Down Expand Up @@ -74,7 +74,8 @@ impl Actions {
writeln!(s, " rg : {}", Self::process_output("rg", "--version"))?;
writeln!(s, " chafa : {}", Self::process_output("chafa", "--version"))?;
writeln!(s, " zoxide : {}", Self::process_output("zoxide", "--version"))?;
writeln!(s, " unar : {}", Self::process_output("unar", "--version"))?;
writeln!(s, " 7z : {}", Self::process_output("7z", "i"))?;
writeln!(s, " 7zz : {}", Self::process_output("7zz", "i"))?;
writeln!(s, " jq : {}", Self::process_output("jq", "--version"))?;

writeln!(s, "\n\n--------------------------------------------------")?;
Expand Down
3 changes: 3 additions & 0 deletions yazi-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ tokio = { version = "1.39.1", features = [ "full" ] }
toml_edit = "0.22.16"

[build-dependencies]
yazi-shared = { path = "../yazi-shared", version = "0.2.5" }

# External build dependencies
anyhow = "1.0.86"
clap = { version = "4.5.10", features = [ "derive" ] }
clap_complete = "4.5.9"
Expand Down
87 changes: 59 additions & 28 deletions yazi-cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,52 +16,67 @@ pub(super) struct Args {

#[derive(Subcommand)]
pub(super) enum Command {
/// Publish a message to remote instance(s).
/// Publish a message to the current instance.
Pub(CommandPub),
/// Manage packages.
Pack(CommandPack),
/// Publish a message to the specified instance.
PubTo(CommandPubTo),
/// Subscribe to messages from all remote instances.
Sub(CommandSub),
/// Manage packages.
Pack(CommandPack),
}

#[derive(clap::Args)]
pub(super) struct CommandPub {
/// The kind of message.
#[arg(index = 1)]
pub(super) kind: String,
/// The receiver ID.
#[arg(index = 2)]
pub(super) receiver: Option<u64>,
pub(super) kind: String,
/// Send the message with a string body.
#[arg(long)]
pub(super) str: Option<String>,
pub(super) str: Option<String>,
/// Send the message with a JSON body.
#[arg(long)]
pub(super) json: Option<String>,
pub(super) json: Option<String>,
/// Send the message as string of list.
#[arg(long, num_args = 0..)]
pub(super) list: Vec<String>,
}

impl CommandPub {
#[allow(dead_code)]
pub(super) fn receiver(&self) -> Result<u64> {
if let Some(receiver) = self.receiver {
Ok(receiver)
} else if let Some(s) = std::env::var("YAZI_PID").ok().filter(|s| !s.is_empty()) {
if let Some(s) = std::env::var("YAZI_PID").ok().filter(|s| !s.is_empty()) {
Ok(s.parse()?)
} else {
bail!("No receiver ID provided, neither YAZI_ID environment variable found.")
bail!("No `YAZI_ID` environment variable found.")
}
}
}

#[allow(dead_code)]
pub(super) fn body(&self) -> Result<Cow<str>> {
if let Some(json) = &self.json {
Ok(json.into())
} else if let Some(str) = &self.str {
Ok(serde_json::to_string(str)?.into())
} else {
Ok("".into())
}
}
#[derive(clap::Args)]
pub(super) struct CommandPubTo {
/// The receiver ID.
#[arg(index = 1)]
pub(super) receiver: u64,
/// The kind of message.
#[arg(index = 2)]
pub(super) kind: String,
/// Send the message with a string body.
#[arg(long)]
pub(super) str: Option<String>,
/// Send the message with a JSON body.
#[arg(long)]
pub(super) json: Option<String>,
/// Send the message as string of list.
#[arg(long, num_args = 0..)]
pub(super) list: Vec<String>,
}

#[derive(clap::Args)]
pub(super) struct CommandSub {
/// The kind of messages to subscribe to, separated by commas if multiple.
#[arg(index = 1)]
pub(super) kinds: String,
}

#[derive(clap::Args)]
Expand All @@ -81,9 +96,25 @@ pub(super) struct CommandPack {
pub(super) upgrade: bool,
}

#[derive(clap::Args)]
pub(super) struct CommandSub {
/// The kind of messages to subscribe to, separated by commas if multiple.
#[arg(index = 1)]
pub(super) kinds: String,
// --- Macros
macro_rules! impl_body {
($name:ident) => {
impl $name {
#[allow(dead_code)]
pub(super) fn body(&self) -> Result<Cow<str>> {
if let Some(json) = &self.json {
Ok(json.into())
} else if let Some(str) = &self.str {
Ok(serde_json::to_string(str)?.into())
} else if !self.list.is_empty() {
Ok(serde_json::to_string(&self.list)?.into())
} else {
Ok("".into())
}
}
}
};
}

impl_body!(CommandPub);
impl_body!(CommandPubTo);
26 changes: 18 additions & 8 deletions yazi-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ async fn main() -> anyhow::Result<()> {
std::process::exit(1);
}
}

Command::PubTo(cmd) => {
yazi_boot::init_default();
yazi_dds::init();
if let Err(e) = yazi_dds::Client::shot(&cmd.kind, cmd.receiver, &cmd.body()?).await {
eprintln!("Cannot send message: {e}");
std::process::exit(1);
}
}

Command::Sub(cmd) => {
yazi_boot::init_default();
yazi_dds::init();
yazi_dds::Client::draw(cmd.kinds.split(',').collect()).await?;

tokio::signal::ctrl_c().await?;
}

Command::Pack(cmd) => {
package::init();
if cmd.install {
Expand All @@ -40,14 +58,6 @@ async fn main() -> anyhow::Result<()> {
package::Package::add_to_config(repo).await?;
}
}

Command::Sub(cmd) => {
yazi_boot::init_default();
yazi_dds::init();
yazi_dds::Client::draw(cmd.kinds.split(',').collect()).await?;

tokio::signal::ctrl_c().await?;
}
}

Ok(())
Expand Down
12 changes: 6 additions & 6 deletions yazi-config/preset/yazi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@ open = [
{ run = 'start "" "%1"', orphan = true, desc = "Open", for = "windows" },
]
reveal = [
{ run = 'xdg-open "$(dirname "$1")"', desc = "Reveal", for = "linux" },
{ run = 'open -R "$1"', desc = "Reveal", for = "macos" },
{ run = 'explorer /select, "%1"', orphan = true, desc = "Reveal", for = "windows" },
{ run = 'xdg-open "$(dirname "$1")"', desc = "Reveal", for = "linux" },
{ run = 'open -R "$1"', desc = "Reveal", for = "macos" },
{ run = 'explorer /select,"%1"', orphan = true, desc = "Reveal", for = "windows" },
{ run = '''exiftool "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show EXIF", for = "unix" },
]
extract = [
{ run = 'unar "$1"', desc = "Extract here", for = "unix" },
{ run = 'unar "%1"', desc = "Extract here", for = "windows" },
{ run = 'ya pub extract --list "$@"', desc = "Extract here", for = "unix" },
{ run = 'ya pub extract --list %*', desc = "Extract here", for = "windows" },
]
play = [
{ run = 'mpv --force-window "$@"', orphan = true, for = "unix" },
{ run = 'mpv --force-window "%1"', orphan = true, for = "windows" },
{ run = 'mpv --force-window %*', orphan = true, for = "windows" },
{ run = '''mediainfo "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show media info", for = "unix" },
]

Expand Down
13 changes: 12 additions & 1 deletion yazi-config/src/plugin/fetcher.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::path::Path;

use serde::Deserialize;
use yazi_shared::{event::Cmd, Condition};
use yazi_shared::{event::Cmd, Condition, MIME_DIR};

use crate::{Pattern, Priority};

Expand All @@ -18,6 +20,15 @@ pub struct Fetcher {
pub prio: Priority,
}

impl Fetcher {
#[inline]
pub fn matches(&self, path: &Path, mime: Option<&str>, f: impl Fn(&str) -> bool + Copy) -> bool {
self.if_.as_ref().and_then(|c| c.eval(f)) != Some(false)
&& (self.mime.as_ref().zip(mime).map_or(false, |(p, m)| p.match_mime(m))
|| self.name.as_ref().is_some_and(|p| p.match_path(path, mime == Some(MIME_DIR))))
}
}

#[derive(Debug, Clone)]
pub struct FetcherProps {
pub id: u8,
Expand Down
47 changes: 20 additions & 27 deletions yazi-config/src/plugin/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{path::Path, str::FromStr};
use std::{collections::HashSet, path::Path, str::FromStr};

use serde::Deserialize;
use yazi_shared::MIME_DIR;

use super::{Fetcher, Preloader, Previewer};
use crate::{plugin::MAX_PREWORKERS, Preset};
Expand All @@ -20,39 +19,33 @@ impl Plugin {
mime: Option<&'a str>,
factor: impl Fn(&str) -> bool + Copy,
) -> impl Iterator<Item = &'a Fetcher> {
let is_dir = mime == Some(MIME_DIR);
let mut seen = HashSet::new();
self.fetchers.iter().filter(move |&f| {
f.if_.as_ref().and_then(|c| c.eval(factor)) != Some(false)
&& (f.mime.as_ref().zip(mime).map_or(false, |(p, m)| p.match_mime(m))
|| f.name.as_ref().is_some_and(|p| p.match_path(path, is_dir)))
if seen.contains(&f.id) || !f.matches(path, mime, factor) {
return false;
}
seen.insert(&f.id);
true
})
}

pub fn preloaders(&self, path: &Path, mime: Option<&str>) -> Vec<&Preloader> {
let is_dir = mime == Some(MIME_DIR);
let mut preloaders = Vec::with_capacity(1);

for p in &self.preloaders {
if !p.mime.as_ref().zip(mime).map_or(false, |(p, m)| p.match_mime(m))
&& !p.name.as_ref().is_some_and(|p| p.match_path(path, is_dir))
{
continue;
}

preloaders.push(p);
if !p.next {
break;
pub fn preloaders<'a>(
&'a self,
path: &'a Path,
mime: Option<&'a str>,
) -> impl Iterator<Item = &'a Preloader> {
let mut next = true;
self.preloaders.iter().filter(move |&p| {
if !next || !p.matches(path, mime) {
return false;
}
}
preloaders
next = p.next;
true
})
}

pub fn previewer(&self, path: &Path, mime: &str) -> Option<&Previewer> {
let is_dir = mime == MIME_DIR;
self.previewers.iter().find(|&p| {
p.mime.as_ref().is_some_and(|p| p.match_mime(mime))
|| p.name.as_ref().is_some_and(|p| p.match_path(path, is_dir))
})
self.previewers.iter().find(|&p| p.matches(path, mime))
}
}
impl FromStr for Plugin {
Expand Down
12 changes: 11 additions & 1 deletion yazi-config/src/plugin/preloader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::path::Path;

use serde::Deserialize;
use yazi_shared::event::Cmd;
use yazi_shared::{event::Cmd, MIME_DIR};

use crate::{Pattern, Priority};

Expand All @@ -17,6 +19,14 @@ pub struct Preloader {
pub prio: Priority,
}

impl Preloader {
#[inline]
pub fn matches(&self, path: &Path, mime: Option<&str>) -> bool {
self.mime.as_ref().zip(mime).map_or(false, |(p, m)| p.match_mime(m))
|| self.name.as_ref().is_some_and(|p| p.match_path(path, mime == Some(MIME_DIR)))
}
}

#[derive(Debug, Clone)]
pub struct PreloaderProps {
pub id: u8,
Expand Down
10 changes: 9 additions & 1 deletion yazi-config/src/plugin/previewer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::path::Path;

use serde::Deserialize;
use yazi_shared::event::Cmd;
use yazi_shared::{event::Cmd, MIME_DIR};

use crate::Pattern;

Expand All @@ -13,6 +15,12 @@ pub struct Previewer {
}

impl Previewer {
#[inline]
pub fn matches(&self, path: &Path, mime: &str) -> bool {
self.mime.as_ref().is_some_and(|p| p.match_mime(mime))
|| self.name.as_ref().is_some_and(|p| p.match_path(path, mime == MIME_DIR))
}

#[inline]
pub fn any_file(&self) -> bool { self.name.as_ref().is_some_and(|p| p.any_file()) }

Expand Down
5 changes: 3 additions & 2 deletions yazi-core/src/manager/commands/update_mimetype.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;

use tracing::error;
use yazi_shared::{event::Cmd, fs::Url, render};

use crate::{manager::{Manager, LINKED}, tasks::Tasks};
Expand All @@ -12,14 +13,14 @@ impl TryFrom<Cmd> for Opt {
type Error = ();

fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
Ok(Self { updates: c.take("updates").ok_or(())?.into_table_string() })
Ok(Self { updates: c.take("updates").ok_or(())?.into_dict_string() })
}
}

impl Manager {
pub fn update_mimetype(&mut self, opt: impl TryInto<Opt>, tasks: &Tasks) {
let Ok(opt) = opt.try_into() else {
return;
return error!("invalid arguments for update_mimetype");
};

let linked = LINKED.read();
Expand Down
Loading

0 comments on commit bce0fc1

Please sign in to comment.