feat: implement opening multi tabs at once

1. CLI can receive more than one paths as entries now.
2. Modify Boot in yazi-boot/ and Tabs in yazi-core to
fit the change above.
3. Add a test for parse_entries().

issue: #1322
This commit is contained in:
coolkiid 2024-08-07 23:33:45 +08:00 committed by sxyazi
parent b066652b65
commit cf5d9d252e
No known key found for this signature in database
4 changed files with 72 additions and 23 deletions

View file

@ -6,8 +6,8 @@ use clap::{command, Parser};
#[command(name = "yazi")]
pub struct Args {
/// Set the current working entry
#[arg(index = 1)]
pub entry: Option<PathBuf>,
#[arg(index = 1, num_args = 1..=9)]
pub entries: Vec<PathBuf>,
/// Write the cwd on exit to this file
#[arg(long)]

View file

@ -5,8 +5,8 @@ use yazi_shared::{fs::{current_cwd, expand_path}, Xdg};
#[derive(Debug, Default, Serialize)]
pub struct Boot {
pub cwd: PathBuf,
pub file: Option<OsString>,
pub cwds: Vec<PathBuf>,
pub files: Vec<Option<OsString>>,
pub local_events: HashSet<String>,
pub remote_events: HashSet<String>,
@ -18,25 +18,34 @@ pub struct Boot {
}
impl Boot {
fn parse_entry(entry: Option<&Path>) -> (PathBuf, Option<OsString>) {
let entry = match entry {
Some(p) => expand_path(p),
None => return (current_cwd().unwrap(), None),
};
let parent = entry.parent();
if parent.is_none() || entry.is_dir() {
return (entry, None);
fn parse_entries(entries: Vec<&Path>) -> (Vec<PathBuf>, Vec<Option<OsString>>) {
if entries.len() == 0 {
return (vec![current_cwd().unwrap()], vec![None]);
}
(parent.unwrap().to_owned(), Some(entry.file_name().unwrap().to_owned()))
let mut cwds = vec![];
let mut files = vec![];
for entry in entries {
let _entry = expand_path(entry);
let parent = _entry.parent();
if parent.is_none() || _entry.is_dir() {
cwds.push(_entry);
files.push(None);
} else {
cwds.push(parent.unwrap().to_owned());
files.push(Some(_entry.file_name().unwrap().to_owned()));
}
}
(cwds, files)
}
}
impl From<&crate::Args> for Boot {
fn from(args: &crate::Args) -> Self {
let config_dir = Xdg::config_dir();
let (cwd, file) = Self::parse_entry(args.entry.as_deref());
let entries = args.entries.iter().map(PathBuf::as_path).collect();
let (cwds, files) = Self::parse_entries(entries);
let local_events = args
.local_events
@ -50,8 +59,8 @@ impl From<&crate::Args> for Boot {
.unwrap_or_default();
Self {
cwd,
file,
cwds,
files,
local_events,
remote_events,
@ -63,3 +72,36 @@ impl From<&crate::Args> for Boot {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_entries() {
use std::{env::temp_dir, fs};
let foo_dir = temp_dir().join(&Path::new("foo"));
let bar_dir = temp_dir().join(&Path::new("bar"));
let poem_path = &foo_dir.join(&Path::new("poem.txt"));
let _ = fs::create_dir_all(&foo_dir);
let _ = fs::create_dir_all(&bar_dir);
let _ =
fs::OpenOptions::new().create(true).write(true).open(foo_dir.join(&Path::new("poem.txt")));
assert_eq!(Boot::parse_entries(vec![]), (vec![current_cwd().unwrap()], vec![None]));
assert_eq!(Boot::parse_entries(vec![&foo_dir]), (vec![foo_dir.clone()], vec![None]));
assert_eq!(
Boot::parse_entries(vec![&poem_path]),
(vec![foo_dir.clone()], vec![Some(OsString::from("poem.txt"))])
);
assert_eq!(
Boot::parse_entries(vec![&foo_dir, &bar_dir]),
(vec![foo_dir.clone(), bar_dir.clone()], vec![None, None])
);
let _ = fs::remove_dir_all(&foo_dir);
let _ = fs::remove_dir_all(&bar_dir);
}
}

View file

@ -17,7 +17,10 @@ impl From<Cmd> for Opt {
Self { url: Default::default(), current: true }
} else {
Self {
url: c.take_first().and_then(Data::into_url).unwrap_or_else(|| Url::from(&BOOT.cwd)),
url: c
.take_first()
.and_then(Data::into_url)
.unwrap_or_else(|| Url::from(&BOOT.cwds[0])),
current: false,
}
}

View file

@ -13,11 +13,15 @@ pub struct Tabs {
impl Tabs {
pub fn make() -> Self {
let mut tabs = Self { cursor: 0, items: vec![Tab::default()] };
if let Some(file) = &BOOT.file {
tabs.items[0].reveal(Url::from(BOOT.cwd.join(file)));
let mut tabs = Self { cursor: 0, items: vec![] };
for (i, file) in BOOT.files.iter().enumerate() {
let mut tab = Tab::default();
if let Some(f) = file {
tab.reveal(Url::from(BOOT.cwds[i].join(f)));
} else {
tabs.items[0].cd(Url::from(&BOOT.cwd));
tab.cd(Url::from(&BOOT.cwds[i]));
}
tabs.push(tab);
}
tabs