mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: new cache_dir option (#96)
This commit is contained in:
parent
4d4586409d
commit
c0c1a6cae6
10 changed files with 85 additions and 50 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{path::{Path, PathBuf}, sync::atomic::{AtomicBool, Ordering}};
|
use std::{path::{Path, PathBuf}, sync::atomic::{AtomicBool, Ordering}};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use config::{preview::PreviewAdaptor, BOOT, PREVIEW};
|
use config::{preview::PreviewAdaptor, PREVIEW};
|
||||||
use ratatui::prelude::Rect;
|
use ratatui::prelude::Rect;
|
||||||
use shared::RoCell;
|
use shared::RoCell;
|
||||||
use tokio::{fs, sync::mpsc::UnboundedSender};
|
use tokio::{fs, sync::mpsc::UnboundedSender};
|
||||||
|
|
@ -19,7 +19,7 @@ pub struct Adaptor;
|
||||||
|
|
||||||
impl Adaptor {
|
impl Adaptor {
|
||||||
pub async fn image_show(mut path: &Path, rect: Rect) -> Result<()> {
|
pub async fn image_show(mut path: &Path, rect: Rect) -> Result<()> {
|
||||||
let cache = BOOT.cache(path, 0);
|
let cache = PREVIEW.cache(path, 0);
|
||||||
if fs::metadata(&cache).await.is_ok() {
|
if fs::metadata(&cache).await.is_ok() {
|
||||||
path = cache.as_path();
|
path = cache.as_path();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
- tab_size: Tab width
|
- tab_size: Tab width
|
||||||
- max_width: Maximum preview width for images and videos
|
- max_width: Maximum preview width for images and videos
|
||||||
- max_height: Maximum preview height for images and videos
|
- max_height: Maximum preview height for images and videos
|
||||||
|
- cache_dir: The system cache directory is used by default, and the cached files will go away on a reboot automatically. If you want to make it more persistent, you can specify the cache directory manually as an absolute path.
|
||||||
|
|
||||||
## opener
|
## opener
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ show_symlink = true
|
||||||
tab_size = 2
|
tab_size = 2
|
||||||
max_width = 600
|
max_width = 600
|
||||||
max_height = 900
|
max_height = 900
|
||||||
|
cache_dir = ""
|
||||||
|
|
||||||
[opener]
|
[opener]
|
||||||
folder = [
|
folder = [
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
use std::{env, fs, path::{Path, PathBuf}, process, time::{self, SystemTime}};
|
use std::{env, fs, path::PathBuf, process};
|
||||||
|
|
||||||
use clap::{command, Parser};
|
use clap::{command, Parser};
|
||||||
use md5::{Digest, Md5};
|
|
||||||
use shared::absolute_path;
|
use shared::absolute_path;
|
||||||
|
|
||||||
use crate::Xdg;
|
use crate::{Xdg, PREVIEW};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Boot {
|
pub struct Boot {
|
||||||
pub cwd: PathBuf,
|
pub cwd: PathBuf,
|
||||||
pub cache_dir: PathBuf,
|
|
||||||
pub state_dir: PathBuf,
|
pub state_dir: PathBuf,
|
||||||
|
|
||||||
pub cwd_file: Option<PathBuf>,
|
pub cwd_file: Option<PathBuf>,
|
||||||
|
|
@ -43,46 +41,37 @@ impl Default for Boot {
|
||||||
let cwd = args
|
let cwd = args
|
||||||
.cwd
|
.cwd
|
||||||
.map(|p| futures::executor::block_on(absolute_path(p)))
|
.map(|p| futures::executor::block_on(absolute_path(p)))
|
||||||
.and_then(|p| p.is_dir().then_some(p))
|
.filter(|p| p.is_dir())
|
||||||
.or_else(|| env::current_dir().ok());
|
.or_else(|| env::current_dir().ok());
|
||||||
|
|
||||||
let boot = Self {
|
let boot = Self {
|
||||||
cwd: cwd.unwrap_or("/".into()),
|
cwd: cwd.unwrap_or("/".into()),
|
||||||
cache_dir: env::temp_dir().join("yazi"),
|
|
||||||
state_dir: Xdg::state_dir().unwrap(),
|
state_dir: Xdg::state_dir().unwrap(),
|
||||||
|
|
||||||
cwd_file: args.cwd_file,
|
cwd_file: args.cwd_file,
|
||||||
chooser_file: args.chooser_file,
|
chooser_file: args.chooser_file,
|
||||||
};
|
};
|
||||||
|
|
||||||
if !boot.cache_dir.is_dir() {
|
|
||||||
fs::create_dir(&boot.cache_dir).unwrap();
|
|
||||||
}
|
|
||||||
if !boot.state_dir.is_dir() {
|
if !boot.state_dir.is_dir() {
|
||||||
fs::create_dir_all(&boot.state_dir).unwrap();
|
fs::create_dir_all(&boot.state_dir).unwrap();
|
||||||
}
|
}
|
||||||
|
if !PREVIEW.cache_dir.is_dir() {
|
||||||
|
fs::create_dir(&PREVIEW.cache_dir).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
if args.clear_cache {
|
if args.clear_cache {
|
||||||
println!("Clearing cache directory: {:?}", boot.cache_dir);
|
if PREVIEW.cache_dir == Xdg::cache_dir() {
|
||||||
fs::remove_dir_all(&boot.cache_dir).unwrap();
|
println!("Clearing cache directory: \n{:?}", PREVIEW.cache_dir);
|
||||||
|
fs::remove_dir_all(&PREVIEW.cache_dir).unwrap();
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"You've changed the default cache directory, for your data's safety, please clear it manually: \n{:?}",
|
||||||
|
PREVIEW.cache_dir
|
||||||
|
);
|
||||||
|
}
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
boot
|
boot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boot {
|
|
||||||
#[inline]
|
|
||||||
pub fn cache(&self, path: &Path, skip: usize) -> PathBuf {
|
|
||||||
self
|
|
||||||
.cache_dir
|
|
||||||
.join(format!("{:x}", Md5::new_with_prefix(format!("{:?}///{}", path, skip)).finalize()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn tmpfile(&self, prefix: &str) -> PathBuf {
|
|
||||||
let nanos = SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos();
|
|
||||||
self.cache_dir.join(format!("{prefix}-{}", nanos / 1000))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ static MERGED_KEYMAP: RoCell<String> = RoCell::new();
|
||||||
static MERGED_THEME: RoCell<String> = RoCell::new();
|
static MERGED_THEME: RoCell<String> = RoCell::new();
|
||||||
static MERGED_YAZI: RoCell<String> = RoCell::new();
|
static MERGED_YAZI: RoCell<String> = RoCell::new();
|
||||||
|
|
||||||
pub static BOOT: RoCell<boot::Boot> = RoCell::new();
|
|
||||||
pub static KEYMAP: RoCell<keymap::Keymap> = RoCell::new();
|
pub static KEYMAP: RoCell<keymap::Keymap> = RoCell::new();
|
||||||
pub static LOG: RoCell<log::Log> = RoCell::new();
|
pub static LOG: RoCell<log::Log> = RoCell::new();
|
||||||
pub static MANAGER: RoCell<manager::Manager> = RoCell::new();
|
pub static MANAGER: RoCell<manager::Manager> = RoCell::new();
|
||||||
|
|
@ -32,12 +31,13 @@ pub static PREVIEW: RoCell<preview::Preview> = RoCell::new();
|
||||||
pub static TASKS: RoCell<tasks::Tasks> = RoCell::new();
|
pub static TASKS: RoCell<tasks::Tasks> = RoCell::new();
|
||||||
pub static THEME: RoCell<theme::Theme> = RoCell::new();
|
pub static THEME: RoCell<theme::Theme> = RoCell::new();
|
||||||
|
|
||||||
|
pub static BOOT: RoCell<boot::Boot> = RoCell::new();
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
MERGED_KEYMAP.with(Preset::keymap);
|
MERGED_KEYMAP.with(Preset::keymap);
|
||||||
MERGED_THEME.with(Preset::theme);
|
MERGED_THEME.with(Preset::theme);
|
||||||
MERGED_YAZI.with(Preset::yazi);
|
MERGED_YAZI.with(Preset::yazi);
|
||||||
|
|
||||||
BOOT.with(Default::default);
|
|
||||||
KEYMAP.with(Default::default);
|
KEYMAP.with(Default::default);
|
||||||
LOG.with(Default::default);
|
LOG.with(Default::default);
|
||||||
MANAGER.with(Default::default);
|
MANAGER.with(Default::default);
|
||||||
|
|
@ -45,4 +45,6 @@ pub fn init() {
|
||||||
PREVIEW.with(Default::default);
|
PREVIEW.with(Default::default);
|
||||||
TASKS.with(Default::default);
|
TASKS.with(Default::default);
|
||||||
THEME.with(Default::default);
|
THEME.with(Default::default);
|
||||||
|
|
||||||
|
BOOT.with(Default::default);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,65 @@
|
||||||
|
use std::{path::{Path, PathBuf}, time::{self, SystemTime}};
|
||||||
|
|
||||||
|
use md5::{Digest, Md5};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::PreviewAdaptor;
|
use super::PreviewAdaptor;
|
||||||
use crate::MERGED_YAZI;
|
use crate::{xdg::Xdg, MERGED_YAZI};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug)]
|
||||||
pub struct Preview {
|
pub struct Preview {
|
||||||
#[serde(skip)]
|
pub adaptor: PreviewAdaptor,
|
||||||
pub adaptor: PreviewAdaptor,
|
|
||||||
pub tab_size: u32,
|
|
||||||
|
|
||||||
|
pub tab_size: u32,
|
||||||
pub max_width: u32,
|
pub max_width: u32,
|
||||||
pub max_height: u32,
|
pub max_height: u32,
|
||||||
|
|
||||||
|
pub cache_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Preview {
|
impl Default for Preview {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Outer {
|
struct Outer {
|
||||||
preview: Preview,
|
preview: Shadow,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Shadow {
|
||||||
|
pub tab_size: u32,
|
||||||
|
pub max_width: u32,
|
||||||
|
pub max_height: u32,
|
||||||
|
|
||||||
|
pub cache_dir: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let outer: Outer = toml::from_str(&MERGED_YAZI).unwrap();
|
let preview = toml::from_str::<Outer>(&MERGED_YAZI).unwrap().preview;
|
||||||
outer.preview
|
|
||||||
|
let cache_dir =
|
||||||
|
preview.cache_dir.filter(|p| !p.is_empty()).map_or_else(Xdg::cache_dir, PathBuf::from);
|
||||||
|
|
||||||
|
Preview {
|
||||||
|
adaptor: Default::default(),
|
||||||
|
|
||||||
|
tab_size: preview.tab_size,
|
||||||
|
max_width: preview.max_width,
|
||||||
|
max_height: preview.max_height,
|
||||||
|
|
||||||
|
cache_dir,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Preview {
|
||||||
|
#[inline]
|
||||||
|
pub fn cache(&self, path: &Path, skip: usize) -> PathBuf {
|
||||||
|
self
|
||||||
|
.cache_dir
|
||||||
|
.join(format!("{:x}", Md5::new_with_prefix(format!("{:?}///{}", path, skip)).finalize()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn tmpfile(&self, prefix: &str) -> PathBuf {
|
||||||
|
let nanos = SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos();
|
||||||
|
self.cache_dir.join(format!("{prefix}-{}", nanos / 1000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::path::PathBuf;
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
pub(super) struct Xdg;
|
pub(super) struct Xdg;
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ impl Xdg {
|
||||||
{
|
{
|
||||||
std::env::var_os("XDG_CONFIG_HOME")
|
std::env::var_os("XDG_CONFIG_HOME")
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.and_then(|p| p.is_absolute().then_some(p))
|
.filter(|p| p.is_absolute())
|
||||||
.or_else(|| dirs::home_dir().map(|h| h.join(".config")))
|
.or_else(|| dirs::home_dir().map(|h| h.join(".config")))
|
||||||
.map(|p| p.join("yazi"))
|
.map(|p| p.join("yazi"))
|
||||||
}
|
}
|
||||||
|
|
@ -27,9 +27,12 @@ impl Xdg {
|
||||||
{
|
{
|
||||||
std::env::var_os("XDG_STATE_HOME")
|
std::env::var_os("XDG_STATE_HOME")
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.and_then(|p| p.is_absolute().then_some(p))
|
.filter(|p| p.is_absolute())
|
||||||
.or_else(|| dirs::home_dir().map(|h| h.join(".local/state")))
|
.or_else(|| dirs::home_dir().map(|h| h.join(".local/state")))
|
||||||
.map(|p| p.join("yazi"))
|
.map(|p| p.join("yazi"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn cache_dir() -> PathBuf { env::temp_dir().join("yazi") }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, ffi::OsStr, io::{stdout, BufWriter, Write}, mem, path::{Path, PathBuf}};
|
use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, ffi::OsStr, io::{stdout, BufWriter, Write}, mem, path::{Path, PathBuf}};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Error, Result};
|
use anyhow::{anyhow, bail, Error, Result};
|
||||||
use config::{BOOT, OPEN};
|
use config::{OPEN, PREVIEW};
|
||||||
use shared::{max_common_root, Defer, Term, MIME_DIR};
|
use shared::{max_common_root, Defer, Term, MIME_DIR};
|
||||||
use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
|
use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
|
||||||
|
|
||||||
|
|
@ -222,7 +222,7 @@ impl Manager {
|
||||||
let root = max_common_root(&old);
|
let root = max_common_root(&old);
|
||||||
let old: Vec<_> = old.into_iter().map(|p| p.strip_prefix(&root).unwrap().to_owned()).collect();
|
let old: Vec<_> = old.into_iter().map(|p| p.strip_prefix(&root).unwrap().to_owned()).collect();
|
||||||
|
|
||||||
let tmp = BOOT.tmpfile("bulk");
|
let tmp = PREVIEW.tmpfile("bulk");
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let Some(opener) = OPEN.block_opener("bulk.txt", "text/plain") else {
|
let Some(opener) = OPEN.block_opener("bulk.txt", "text/plain") else {
|
||||||
bail!("No opener for bulk rename");
|
bail!("No opener for bulk rename");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{io::BufRead, path::Path, sync::atomic::{AtomicUsize, Ordering}};
|
||||||
|
|
||||||
use adaptor::Adaptor;
|
use adaptor::Adaptor;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use config::{BOOT, MANAGER, PREVIEW};
|
use config::{MANAGER, PREVIEW};
|
||||||
use shared::{MimeKind, PeekError};
|
use shared::{MimeKind, PeekError};
|
||||||
use syntect::{easy::HighlightFile, util::as_24_bit_terminal_escaped};
|
use syntect::{easy::HighlightFile, util::as_24_bit_terminal_escaped};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
@ -62,7 +62,7 @@ impl Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn video(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
|
pub(super) async fn video(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
|
||||||
let cache = BOOT.cache(path, skip);
|
let cache = PREVIEW.cache(path, skip);
|
||||||
if fs::metadata(&cache).await.is_err() {
|
if fs::metadata(&cache).await.is_err() {
|
||||||
external::ffmpegthumbnailer(path, &cache, skip).await?;
|
external::ffmpegthumbnailer(path, &cache, skip).await?;
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +71,7 @@ impl Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn pdf(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
|
pub(super) async fn pdf(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
|
||||||
let cache = BOOT.cache(path, skip);
|
let cache = PREVIEW.cache(path, skip);
|
||||||
if fs::metadata(&cache).await.is_err() {
|
if fs::metadata(&cache).await.is_err() {
|
||||||
external::pdftoppm(path, &cache, skip).await?;
|
external::pdftoppm(path, &cache, skip).await?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{collections::{BTreeMap, BTreeSet}, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use adaptor::Image;
|
use adaptor::Image;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use config::BOOT;
|
use config::PREVIEW;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use shared::{calculate_size, Throttle};
|
use shared::{calculate_size, Throttle};
|
||||||
use tokio::{fs, sync::mpsc};
|
use tokio::{fs, sync::mpsc};
|
||||||
|
|
@ -74,7 +74,7 @@ impl Precache {
|
||||||
pub(crate) async fn work(&self, task: &mut PrecacheOp) -> Result<()> {
|
pub(crate) async fn work(&self, task: &mut PrecacheOp) -> Result<()> {
|
||||||
match task {
|
match task {
|
||||||
PrecacheOp::Image(task) => {
|
PrecacheOp::Image(task) => {
|
||||||
let cache = BOOT.cache(&task.target, 0);
|
let cache = PREVIEW.cache(&task.target, 0);
|
||||||
if fs::metadata(&cache).await.is_ok() {
|
if fs::metadata(&cache).await.is_ok() {
|
||||||
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +84,7 @@ impl Precache {
|
||||||
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
||||||
}
|
}
|
||||||
PrecacheOp::Video(task) => {
|
PrecacheOp::Video(task) => {
|
||||||
let cache = BOOT.cache(&task.target, 0);
|
let cache = PREVIEW.cache(&task.target, 0);
|
||||||
if fs::metadata(&cache).await.is_ok() {
|
if fs::metadata(&cache).await.is_ok() {
|
||||||
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ impl Precache {
|
||||||
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
||||||
}
|
}
|
||||||
PrecacheOp::Pdf(task) => {
|
PrecacheOp::Pdf(task) => {
|
||||||
let cache = BOOT.cache(&task.target, 0);
|
let cache = PREVIEW.cache(&task.target, 0);
|
||||||
if fs::metadata(&cache).await.is_ok() {
|
if fs::metadata(&cache).await.is_ok() {
|
||||||
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue