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();
if !selected.is_empty() {
return Ok(Url::from(selected).into_dir());
return Ok(Url::from(selected).push_slash());
}
bail!("No match")
}

View file

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

View file

@ -10,7 +10,7 @@ use crate::{emit, files::{File, FilesOp}, input::InputOpt, tab::Tab};
impl Tab {
pub fn cd(&mut self, mut target: Url) -> bool {
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())));
hovered = Some(target);
target = parent;

View file

@ -36,7 +36,7 @@ impl Tab {
while let Some(chunk) = rx.next().await {
if first {
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
));
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;
@ -20,15 +20,24 @@ fn _expand_path(p: &Path) -> PathBuf {
});
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)]
if let Some(home) = env::var_os("HOME") {
return Path::new(&home).join(p);
}
let Some(home) = env::var_os("HOME") else {
return rest.to_path_buf();
};
#[cfg(windows)]
if let Some(home) = env::var_os("USERPROFILE") {
return Path::new(&home).join(p);
let Some(home) = env::var_os("USERPROFILE") else {
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() {
@ -46,6 +55,39 @@ pub fn expand_url(mut u: Url) -> Url {
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 {
let Some(stem) = p.file_stem().map(|s| s.to_owned()) else {
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 crate::{ends_with_slash, pop_end_slash};
const ENCODE_SET: &AsciiSet = &CONTROLS.add(b'#');
#[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
@ -158,43 +160,14 @@ impl Url {
}
#[inline]
pub fn was_dir(&self) -> bool {
// 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 }
}
}
pub fn pop_slash(&mut self) -> bool { pop_end_slash(self) }
#[inline]
pub fn pop_dir(&mut self) -> bool {
if !self.was_dir() {
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() {
pub fn push_slash(mut self) -> Self {
if !ends_with_slash(&self) {
self
} else {
self.path.as_mut_os_string().push("/");
self.path.as_mut_os_string().push(MAIN_SEPARATOR_STR);
self
}
}