This commit is contained in:
sxyazi 2023-11-09 02:15:03 +08:00
parent 8100598224
commit bbe157bd9f
No known key found for this signature in database
6 changed files with 61 additions and 46 deletions

View file

@ -20,7 +20,7 @@ pub async fn zoxide(opt: ZoxideOpt) -> Result<Url> {
let selected = String::from_utf8_lossy(&output.stdout).trim().to_string(); let selected = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !selected.is_empty() { if !selected.is_empty() {
return Ok(Url::from(selected).into_dir()); return Ok(Url::from(selected).push_slash());
} }
bail!("No match") bail!("No match")
} }

View file

@ -3,14 +3,14 @@ use crate::tab::Tab;
impl Tab { impl Tab {
pub fn back(&mut self) -> bool { pub fn back(&mut self) -> bool {
if let Some(url) = self.backstack.shift_backward().cloned() { if let Some(url) = self.backstack.shift_backward().cloned() {
self.cd(url.into_dir()); self.cd(url.push_slash());
} }
false false
} }
pub fn forward(&mut self) -> bool { pub fn forward(&mut self) -> bool {
if let Some(url) = self.backstack.shift_forward().cloned() { if let Some(url) = self.backstack.shift_forward().cloned() {
self.cd(url.into_dir()); self.cd(url.push_slash());
} }
false false
} }

View file

@ -10,7 +10,7 @@ use crate::{emit, files::{File, FilesOp}, input::InputOpt, tab::Tab};
impl Tab { impl Tab {
pub fn cd(&mut self, mut target: Url) -> bool { pub fn cd(&mut self, mut target: Url) -> bool {
let mut hovered = None; let mut hovered = None;
if let (false, Some(parent)) = (target.pop_dir(), target.parent_url()) { if let (false, Some(parent)) = (target.pop_slash(), target.parent_url()) {
emit!(Files(FilesOp::Creating(parent.clone(), File::from_dummy(target.clone()).into_map()))); emit!(Files(FilesOp::Creating(parent.clone(), File::from_dummy(target.clone()).into_map())));
hovered = Some(target); hovered = Some(target);
target = parent; target = parent;

View file

@ -36,7 +36,7 @@ impl Tab {
while let Some(chunk) = rx.next().await { while let Some(chunk) = rx.next().await {
if first { if first {
emit!(Call( emit!(Call(
Exec::call("cd", vec![cwd.clone().into_dir().to_string()]).vec(), Exec::call("cd", vec![cwd.clone().push_slash().to_string()]).vec(),
KeymapLayer::Manager KeymapLayer::Manager
)); ));
first = false; first = false;

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, env, ffi::OsString, path::{Component, Path, PathBuf}}; use std::{borrow::Cow, env, ffi::OsString, path::{Component, Path, PathBuf, MAIN_SEPARATOR, MAIN_SEPARATOR_STR}};
use tokio::fs; use tokio::fs;
@ -20,15 +20,24 @@ fn _expand_path(p: &Path) -> PathBuf {
}); });
let p = Path::new(s.as_ref()); let p = Path::new(s.as_ref());
if let Ok(p) = p.strip_prefix("~") { if let (slash, Ok(rest)) = (ends_with_slash(p), p.strip_prefix("~")) {
#[cfg(unix)] #[cfg(unix)]
if let Some(home) = env::var_os("HOME") { let Some(home) = env::var_os("HOME") else {
return Path::new(&home).join(p); return rest.to_path_buf();
} };
#[cfg(windows)] #[cfg(windows)]
if let Some(home) = env::var_os("USERPROFILE") { let Some(home) = env::var_os("USERPROFILE") else {
return Path::new(&home).join(p); return rest.to_path_buf();
};
let mut home = PathBuf::from(home);
pop_end_slash(&mut home);
let mut p = if rest == Path::new("") { home } else { home.join(rest) };
if slash {
p.as_mut_os_string().push(MAIN_SEPARATOR_STR);
} }
return p;
} }
if p.is_absolute() { if p.is_absolute() {
@ -46,6 +55,39 @@ pub fn expand_url(mut u: Url) -> Url {
u u
} }
#[inline]
pub fn ends_with_slash(p: &Path) -> bool {
// TODO: uncomment this when Rust 1.74 is released
// let b = p.as_os_str().as_encoded_bytes();
// if let [.., last] = b { *last == MAIN_SEPARATOR as u8 } else { false }
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
let b = p.as_os_str().as_bytes();
if let [.., last] = b { *last == MAIN_SEPARATOR as u8 } else { false }
}
#[cfg(windows)]
{
let s = p.to_string_lossy();
let b = s.as_bytes();
if let [.., last] = b { *last == MAIN_SEPARATOR as u8 } else { false }
}
}
#[inline]
#[allow(clippy::unnecessary_to_owned)]
pub fn pop_end_slash(p: &mut PathBuf) -> bool {
if !ends_with_slash(p) {
return false;
}
if let Some(n) = p.file_name() {
p.set_file_name(n.to_owned());
}
true
}
pub async fn unique_path(mut p: Url) -> Url { pub async fn unique_path(mut p: Url) -> Url {
let Some(stem) = p.file_stem().map(|s| s.to_owned()) else { let Some(stem) = p.file_stem().map(|s| s.to_owned()) else {
return p; return p;

View file

@ -1,7 +1,9 @@
use std::{ffi::{OsStr, OsString}, fmt::{Debug, Formatter}, ops::{Deref, DerefMut}, path::{Path, PathBuf, MAIN_SEPARATOR}}; use std::{ffi::{OsStr, OsString}, fmt::{Debug, Formatter}, ops::{Deref, DerefMut}, path::{Path, PathBuf, MAIN_SEPARATOR_STR}};
use percent_encoding::{percent_decode_str, percent_encode, AsciiSet, CONTROLS}; use percent_encoding::{percent_decode_str, percent_encode, AsciiSet, CONTROLS};
use crate::{ends_with_slash, pop_end_slash};
const ENCODE_SET: &AsciiSet = &CONTROLS.add(b'#'); const ENCODE_SET: &AsciiSet = &CONTROLS.add(b'#');
#[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
@ -158,43 +160,14 @@ impl Url {
} }
#[inline] #[inline]
pub fn was_dir(&self) -> bool { pub fn pop_slash(&mut self) -> bool { pop_end_slash(self) }
// TODO: uncomment this when Rust 1.74 is released
// let b = self.path.as_os_str().as_encoded_bytes();
// if let [.., last] = b { *last == MAIN_SEPARATOR as u8 } else { false }
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
let b = self.path.as_os_str().as_bytes();
if let [.., last] = b { *last == MAIN_SEPARATOR as u8 } else { false }
}
#[cfg(windows)]
{
let s = self.path.to_string_lossy();
let b = s.as_bytes();
if let [.., last] = b { *last == MAIN_SEPARATOR as u8 } else { false }
}
}
#[inline] #[inline]
pub fn pop_dir(&mut self) -> bool { pub fn push_slash(mut self) -> Self {
if !self.was_dir() { if !ends_with_slash(&self) {
return false;
}
if let Some(n) = self.path.file_name() {
self.path.set_file_name(n.to_owned());
}
true
}
#[inline]
pub fn into_dir(mut self) -> Self {
if self.was_dir() {
self self
} else { } else {
self.path.as_mut_os_string().push("/"); self.path.as_mut_os_string().push(MAIN_SEPARATOR_STR);
self self
} }
} }