mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
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:
parent
b066652b65
commit
cf5d9d252e
4 changed files with 72 additions and 23 deletions
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue