feat: automatically change the current working directory after closing yazi (#40)

This commit is contained in:
三咲雅 · Misaki Masa 2023-08-09 18:15:02 +08:00 committed by GitHub
parent d198f142e2
commit b6f1aa552f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 261 additions and 47 deletions

166
Cargo.lock generated
View file

@ -60,6 +60,55 @@ dependencies = [
"thiserror",
]
[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
]
[[package]]
name = "anyhow"
version = "1.0.72"
@ -218,12 +267,59 @@ dependencies = [
"winapi",
]
[[package]]
name = "clap"
version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
name = "clap_builder"
version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "concurrent-queue"
version = "2.2.0"
@ -238,6 +334,7 @@ name = "config"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"crossterm 0.27.0",
"futures",
"glob",
@ -419,6 +516,27 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "event-listener"
version = "2.5.3"
@ -664,6 +782,12 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.2"
@ -768,6 +892,17 @@ dependencies = [
"libc",
]
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "itoa"
version = "1.0.9"
@ -845,6 +980,12 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "lock_api"
version = "0.4.10"
@ -1254,6 +1395,19 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399"
dependencies = [
"bitflags 2.3.3",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.48.0",
]
[[package]]
name = "ryu"
version = "1.0.15"
@ -1424,6 +1578,12 @@ dependencies = [
"lock_api",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.28"
@ -1741,6 +1901,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "valuable"
version = "0.1.0"

View file

@ -88,6 +88,19 @@ yazi
If you want to use your own config, copy the [config folder](https://github.com/sxyazi/yazi/tree/main/config/preset) to `~/.config/yazi`, and modify it as you like.
There is a wrapper of yazi that provides the ability to change the current shell's working directory when yazi exited, feel free to use it:
```bash
function ya() {
tmp="$(mktemp -t "yazi-cwd")"
yazi --cwd-file="$tmp"
if cwd="$(cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
cd -- "$cwd"
fi
rm -f -- "$tmp"
}
```
## Image Preview
| Platform | Protocol | Support |

View file

@ -1,7 +1,7 @@
use std::{path::{Path, PathBuf}, sync::Arc};
use anyhow::Result;
use config::{MANAGER, PREVIEW};
use config::{BOOT, PREVIEW};
use image::{imageops::FilterType, DynamicImage, ImageFormat};
use md5::{Digest, Md5};
use shared::tty_ratio;
@ -57,8 +57,8 @@ impl Image {
#[inline]
pub fn cache(path: &Path) -> PathBuf {
MANAGER
.cache
BOOT
.cache_dir
.join(format!("{:x}", Md5::new_with_prefix(path.to_string_lossy().as_bytes()).finalize()))
}
}

View file

@ -1,7 +1,8 @@
use core::{emit, files::FilesOp, input::InputMode, Event};
use std::os::unix::prelude::OsStrExt;
use anyhow::{Ok, Result};
use config::keymap::{Control, Key, KeymapLayer};
use config::{keymap::{Control, Key, KeymapLayer}, BOOT};
use crossterm::event::KeyEvent;
use shared::{absolute_path, Term};
use tokio::sync::oneshot;
@ -24,7 +25,10 @@ impl App {
while let Some(event) = app.signals.recv().await {
match event {
Event::Quit => break,
Event::Quit => {
app.dispatch_quit();
break;
}
Event::Key(key) => app.dispatch_key(key),
Event::Paste(str) => app.dispatch_paste(str),
Event::Render(_) => app.dispatch_render(),
@ -37,6 +41,13 @@ impl App {
Ok(())
}
fn dispatch_quit(&mut self) {
if let Some(p) = &BOOT.cwd_file {
let cwd = self.cx.manager.cwd().as_os_str();
std::fs::write(p, cwd.as_bytes()).ok();
}
}
fn dispatch_key(&mut self, key: KeyEvent) {
let key = Key::from(key);
if Executor::handle(&mut self.cx, key) {

View file

@ -86,7 +86,7 @@ impl Executor {
"open" => cx.manager.open(exec.named.contains_key("interactive")),
"yank" => cx.manager.yank(exec.named.contains_key("cut")),
"paste" => {
let dest = cx.manager.current().cwd.clone();
let dest = cx.manager.cwd().to_owned();
let (cut, src) = cx.manager.yanked();
let force = exec.named.contains_key("force");
@ -133,7 +133,7 @@ impl Executor {
// Tabs
"tab_create" => {
let path = if exec.named.contains_key("current") {
cx.manager.current().cwd.clone()
cx.manager.cwd().to_owned()
} else {
exec.args.get(0).map(|p| p.into()).unwrap_or("/".into())
};

View file

@ -1,5 +1,5 @@
use anyhow::{Context, Result};
use config::LOG;
use config::BOOT;
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::{fmt, prelude::__tracing_subscriber_SubscriberExt, Registry};
@ -7,7 +7,7 @@ pub(super) struct Logs;
impl Logs {
pub(super) fn init() -> Result<WorkerGuard> {
let appender = tracing_appender::rolling::never(&LOG.root, "yazi.log");
let appender = tracing_appender::rolling::never(&BOOT.state_dir, "yazi.log");
let (handle, guard) = tracing_appender::non_blocking(appender);
// let filter = EnvFilter::from_default_env();

View file

@ -8,6 +8,7 @@ shared = { path = "../shared" }
# External dependencies
anyhow = "^1"
clap = { version = "^4", features = [ "derive" ] }
crossterm = "^0"
futures = "^0"
glob = "^0"

39
config/src/boot/boot.rs Normal file
View file

@ -0,0 +1,39 @@
use std::{env, fs, path::PathBuf};
use clap::Parser;
#[derive(Debug)]
pub struct Boot {
pub cwd: PathBuf,
pub cwd_file: Option<PathBuf>,
pub cache_dir: PathBuf,
pub state_dir: PathBuf,
}
#[derive(Debug, Parser)]
struct Args {
/// Write the cwd on exit to this file
#[arg(long)]
cwd_file: Option<PathBuf>,
}
impl Default for Boot {
fn default() -> Self {
let args = Args::parse();
let boot = Self {
cwd: env::current_dir().unwrap_or("/".into()),
cwd_file: args.cwd_file,
cache_dir: env::temp_dir().join("yazi"),
state_dir: xdg::BaseDirectories::with_prefix("yazi").unwrap().get_state_home(),
};
if !boot.cache_dir.is_dir() {
fs::create_dir(&boot.cache_dir).unwrap();
}
if !boot.state_dir.is_dir() {
fs::create_dir_all(&boot.state_dir).unwrap();
}
boot
}
}

3
config/src/boot/mod.rs Normal file
View file

@ -0,0 +1,3 @@
mod boot;
pub use boot::*;

View file

@ -2,6 +2,7 @@
use once_cell::sync::Lazy;
mod boot;
pub mod keymap;
mod log;
pub mod manager;
@ -18,6 +19,7 @@ static MERGED_KEYMAP: Lazy<String> = Lazy::new(Preset::keymap);
static MERGED_THEME: Lazy<String> = Lazy::new(Preset::theme);
static MERGED_YAZI: Lazy<String> = Lazy::new(Preset::yazi);
pub static BOOT: Lazy<boot::Boot> = Lazy::new(Default::default);
pub static KEYMAP: Lazy<keymap::Keymap> = Lazy::new(Default::default);
pub static LOG: Lazy<log::Log> = Lazy::new(Default::default);
pub static MANAGER: Lazy<manager::Manager> = Lazy::new(Default::default);
@ -26,6 +28,7 @@ pub static PREVIEW: Lazy<preview::Preview> = Lazy::new(Default::default);
pub static THEME: Lazy<theme::Theme> = Lazy::new(Default::default);
pub fn init() {
Lazy::force(&BOOT);
Lazy::force(&KEYMAP);
Lazy::force(&LOG);
Lazy::force(&MANAGER);

View file

@ -1,13 +1,10 @@
use std::path::PathBuf;
use serde::{de, Deserialize, Deserializer};
use serde::{Deserialize, Deserializer};
use crate::MERGED_YAZI;
#[derive(Debug)]
pub struct Log {
pub enabled: bool,
pub root: PathBuf,
}
impl Default for Log {
@ -30,13 +27,6 @@ impl<'de> Deserialize<'de> for Log {
let outer = Outer::deserialize(deserializer)?;
let root = xdg::BaseDirectories::with_prefix("yazi")
.map_err(|e| de::Error::custom(e.to_string()))?
.get_state_home();
if !root.is_dir() {
std::fs::create_dir_all(&root).map_err(|e| de::Error::custom(e.to_string()))?;
}
Ok(Self { enabled: outer.log.enabled, root })
Ok(Self { enabled: outer.log.enabled })
}
}

View file

@ -1,5 +1,3 @@
use std::{env, fs, path::PathBuf};
use serde::Deserialize;
use super::SortBy;
@ -7,11 +5,6 @@ use crate::MERGED_YAZI;
#[derive(Debug, Deserialize)]
pub struct Manager {
#[serde(skip)]
pub cwd: PathBuf,
#[serde(skip)]
pub cache: PathBuf,
// Sorting
pub sort_by: SortBy,
pub sort_reverse: bool,
@ -27,14 +20,6 @@ impl Default for Manager {
manager: Manager,
}
let mut manager = toml::from_str::<Outer>(&MERGED_YAZI).unwrap().manager;
manager.cwd = env::current_dir().unwrap_or("/".into());
manager.cache = env::temp_dir().join("yazi");
if !manager.cache.is_dir() {
fs::create_dir(&manager.cache).unwrap();
}
manager
toml::from_str::<Outer>(&MERGED_YAZI).unwrap().manager
}
}

View file

@ -1,4 +1,4 @@
use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, mem, path::PathBuf};
use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, mem, path::{Path, PathBuf}};
use anyhow::Error;
use config::{open::Opener, OPEN};
@ -28,9 +28,9 @@ impl Manager {
}
pub fn refresh(&mut self) {
env::set_current_dir(&self.current().cwd).ok();
env::set_current_dir(self.cwd()).ok();
self.watcher.trigger(&self.current().cwd);
self.watcher.trigger(self.cwd());
if let Some(p) = self.parent() {
self.watcher.trigger(&p.cwd);
}
@ -174,7 +174,7 @@ impl Manager {
}
pub fn create(&self) -> bool {
let cwd = self.current().cwd.clone();
let cwd = self.cwd().to_owned();
tokio::spawn(async move {
let result = emit!(Input(InputOpt::top("Create:")));
@ -248,7 +248,7 @@ impl Manager {
pub fn update_read(&mut self, op: FilesOp) -> bool {
let path = op.path();
let cwd = self.current().cwd.clone();
let cwd = self.cwd().to_owned();
let hovered = self.hovered().map(|h| h.path());
let mut b = if cwd == path && !self.current().in_search {
@ -277,7 +277,7 @@ impl Manager {
pub fn update_search(&mut self, op: FilesOp) -> bool {
let path = op.path();
if self.current().in_search && self.current().cwd == path {
if self.current().in_search && self.cwd() == path {
return self.current_mut().update(op);
}
@ -293,7 +293,7 @@ impl Manager {
let path = op.path();
let op = FilesOp::read_empty(&path);
if path == self.current().cwd {
if path == self.cwd() {
self.current_mut().update(op);
} else if matches!(self.parent(), Some(p) if p.cwd == path) {
self.active_mut().parent.as_mut().unwrap().update(op);
@ -338,6 +338,9 @@ impl Manager {
}
impl Manager {
#[inline]
pub fn cwd(&self) -> &Path { &self.current().cwd }
#[inline]
pub fn tabs(&self) -> &Tabs { &self.tabs }

View file

@ -1,6 +1,6 @@
use std::path::Path;
use config::MANAGER;
use config::BOOT;
use super::Tab;
use crate::emit;
@ -14,7 +14,7 @@ pub struct Tabs {
impl Tabs {
pub fn make() -> Self {
let mut tabs = Self { idx: usize::MAX, items: vec![Tab::new(&MANAGER.cwd)] };
let mut tabs = Self { idx: usize::MAX, items: vec![Tab::new(&BOOT.cwd)] };
tabs.set_idx(0);
tabs
}

View file

@ -1 +1 @@
{"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp"," Überzug"," Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt"],"language":"en","version":"0.2","flagWords":[]}
{"flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp"," Überzug"," Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp"],"version":"0.2","language":"en"}