Skip to content

Commit

Permalink
feat: implement opening multi tabs at once
Browse files Browse the repository at this point in the history
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
  • Loading branch information
coolkiid committed Aug 10, 2024
1 parent 6e94776 commit 6de5817
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 23 deletions.
4 changes: 2 additions & 2 deletions yazi-boot/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, value_delimiter = ' ', num_args = 1..=9)]
pub entries: Vec<PathBuf>,

/// Write the cwd on exit to this file
#[arg(long)]
Expand Down
72 changes: 57 additions & 15 deletions yazi-boot/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand All @@ -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
Expand All @@ -50,8 +59,8 @@ impl From<&crate::Args> for Boot {
.unwrap_or_default();

Self {
cwd,
file,
cwds,
files,

local_events,
remote_events,
Expand All @@ -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);
}
}
5 changes: 4 additions & 1 deletion yazi-core/src/manager/commands/tab_create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Expand Down
14 changes: 9 additions & 5 deletions yazi-core/src/manager/tabs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
} else {
tabs.items[0].cd(Url::from(&BOOT.cwd));
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 {
tab.cd(Url::from(&BOOT.cwds[i]));
}
tabs.push(tab);
}

tabs
Expand Down

0 comments on commit 6de5817

Please sign in to comment.