From a42da833fe1e33fc21297996c0ecf825baa6dc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Thu, 27 Jul 2023 08:08:09 +0800 Subject: [PATCH] feat: make folder openable --- Cargo.lock | 12 +++++----- config/yazi.toml | 8 ++++++- src/config/open/open.rs | 10 ++++++--- src/core/manager/manager.rs | 44 ++++++++++++++++++------------------- src/core/tasks/tasks.rs | 5 ++--- src/misc/mime.rs | 4 +++- 6 files changed, 47 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02810056..84f49620 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1502,18 +1502,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.175" +version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" +checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.175" +version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" +checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" dependencies = [ "proc-macro2", "quote", @@ -1522,9 +1522,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", diff --git a/config/yazi.toml b/config/yazi.toml index f0152391..6c7eb5c1 100644 --- a/config/yazi.toml +++ b/config/yazi.toml @@ -9,11 +9,15 @@ max_width = 600 max_height = 900 [opener] +folder = [ + { cmd = "open", args = [ "-R", "$*" ] }, + { cmd = "code", args = [ "$*" ] }, +] archive = [ { cmd = "unar", args = [ "$1" ] }, ] text = [ - { cmd = "vi", args = [ "$*" ], block = true }, + { cmd = "vim", args = [ "$*" ], block = true }, ] image = [ { cmd = "open", args = [ "$*" ] }, @@ -29,10 +33,12 @@ audio = [ ] fallback = [ { cmd = "open", args = [ "$*" ] }, + { cmd = "open", args = [ "-R", "$*" ] }, ] [open] rules = [ + { name = "*/", use = "folder" }, { name = "*.html", use = "fallback" }, { mime = "text/*", use = "text" }, diff --git a/src/config/open/open.rs b/src/config/open/open.rs index 1bb107db..a1f95fdc 100644 --- a/src/config/open/open.rs +++ b/src/config/open/open.rs @@ -3,7 +3,7 @@ use std::{collections::{BTreeMap, BTreeSet}, path::Path}; use serde::{Deserialize, Deserializer}; use super::Opener; -use crate::config::{Pattern, MERGED_YAZI}; +use crate::{config::{Pattern, MERGED_YAZI}, misc::MIME_DIR}; #[derive(Debug)] pub struct Open { @@ -22,9 +22,13 @@ struct OpenRule { impl Open { pub fn new() -> Self { toml::from_str(&MERGED_YAZI).unwrap() } - pub fn openers(&self, path: impl AsRef, mime: impl AsRef) -> Option> { + pub fn openers(&self, path: P, mime: M) -> Option> + where + P: AsRef, + M: AsRef, + { self.rules.iter().find_map(|rule| { - if rule.name.as_ref().map_or(false, |e| e.match_path(&path, Some(false))) + if rule.name.as_ref().map_or(false, |e| e.match_path(&path, Some(mime.as_ref() == MIME_DIR))) || rule.mime.as_ref().map_or(false, |m| m.matches(&mime)) { self.openers.get(&rule.use_).map(|v| v.iter().collect()) diff --git a/src/core/manager/manager.rs b/src/core/manager/manager.rs index 5c36c183..b4632535 100644 --- a/src/core/manager/manager.rs +++ b/src/core/manager/manager.rs @@ -3,7 +3,7 @@ use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, mem, path::P use tokio::fs; use super::{PreviewData, Tab, Tabs, Watcher}; -use crate::{config::OPEN, core::{external, files::{File, FilesOp}, input::InputOpt, manager::Folder, select::SelectOpt, tasks::Tasks, Position}, emit}; +use crate::{config::OPEN, core::{external, files::{File, FilesOp}, input::InputOpt, manager::Folder, select::SelectOpt, tasks::Tasks, Position}, emit, misc::MIME_DIR}; pub struct Manager { tabs: Tabs, @@ -56,7 +56,7 @@ impl Manager { }; if hovered.meta.is_dir() { - self.active_mut().preview.go(&hovered.path, "inode/directory"); + self.active_mut().preview.go(&hovered.path, MIME_DIR); if self.active().history(&hovered.path).is_some() { emit!(Preview(hovered.path, PreviewData::Folder)); } @@ -95,10 +95,9 @@ impl Manager { title: format!("There are {} tasks running, sure to quit? (y/N)", tasks), value: "".to_string(), position: Position::Top, - })) - .await; + })); - if let Ok(choice) = result { + if let Ok(choice) = result.await { if choice.to_lowercase() == "y" { emit!(Quit); } @@ -115,15 +114,19 @@ impl Manager { } pub fn open(&mut self, interactive: bool) -> bool { - let files = self.selected(); - if files.len() == 1 && files[0].meta.is_dir() { - return self.active_mut().enter(); - } - - let mut files = files + let mut files = self + .selected() .into_iter() - .filter(|f| f.meta.is_file()) - .map(|f| (f.path(), self.mimetype.get(&f.path).cloned())) + .map(|f| { + ( + f.path(), + if f.meta.is_dir() { + Some(MIME_DIR.to_owned()) + } else { + self.mimetype.get(&f.path).cloned() + }, + ) + }) .collect::>(); if files.is_empty() { @@ -157,9 +160,8 @@ impl Manager { title: "Open with:".to_string(), items: openers.iter().map(|o| o.cmd.clone()).collect(), position: Position::Hovered, - })) - .await; - if let Ok(choice) = result { + })); + if let Ok(choice) = result.await { emit!(Open(files, Some(openers[choice].clone()))); } }); @@ -173,10 +175,9 @@ impl Manager { title: "Create:".to_string(), value: "".to_string(), position: Position::Top, - })) - .await; + })); - if let Ok(name) = result { + if let Ok(name) = result.await { let path = cwd.join(&name); if name.ends_with('/') { fs::create_dir_all(path).await.ok(); @@ -205,10 +206,9 @@ impl Manager { title: "Rename:".to_string(), value: hovered.file_name().unwrap().to_string_lossy().to_string(), position: Position::Hovered, - })) - .await; + })); - if let Ok(new) = result { + if let Ok(new) = result.await { let to = hovered.parent().unwrap().join(new); fs::rename(&hovered, to).await.ok(); } diff --git a/src/core/tasks/tasks.rs b/src/core/tasks/tasks.rs index 665d0502..4507008b 100644 --- a/src/core/tasks/tasks.rs +++ b/src/core/tasks/tasks.rs @@ -161,10 +161,9 @@ impl Tasks { title: "Are you sure delete these files? (y/N)".to_string(), value: "".to_string(), position: Position::Hovered, - })) - .await; + })); - if let Ok(choice) = result { + if let Ok(choice) = result.await { if choice.to_lowercase() != "y" { return; } diff --git a/src/misc/mime.rs b/src/misc/mime.rs index bdfb5009..1b212dd9 100644 --- a/src/misc/mime.rs +++ b/src/misc/mime.rs @@ -1,3 +1,5 @@ +pub const MIME_DIR: &str = "inode/directory"; + #[derive(Clone, Copy, PartialEq, Eq)] pub enum MimeKind { Dir, @@ -33,7 +35,7 @@ impl MimeKind { } pub fn new(s: &str) -> Self { - if s == "inode/directory" { + if s == MIME_DIR { Self::Dir } else if s == "application/json" { Self::JSON