feat: new cache_dir option (#96)

This commit is contained in:
三咲雅 · Misaki Masa 2023-08-31 18:21:06 +08:00 committed by GitHub
parent 4d4586409d
commit c0c1a6cae6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 85 additions and 50 deletions

View file

@ -1,7 +1,7 @@
use std::{path::{Path, PathBuf}, sync::atomic::{AtomicBool, Ordering}};
use anyhow::Result;
use config::{preview::PreviewAdaptor, BOOT, PREVIEW};
use config::{preview::PreviewAdaptor, PREVIEW};
use ratatui::prelude::Rect;
use shared::RoCell;
use tokio::{fs, sync::mpsc::UnboundedSender};
@ -19,7 +19,7 @@ pub struct Adaptor;
impl Adaptor {
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() {
path = cache.as_path();
}

View file

@ -39,6 +39,7 @@
- tab_size: Tab width
- max_width: Maximum preview width 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

View file

@ -10,6 +10,7 @@ show_symlink = true
tab_size = 2
max_width = 600
max_height = 900
cache_dir = ""
[opener]
folder = [

View file

@ -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 md5::{Digest, Md5};
use shared::absolute_path;
use crate::Xdg;
use crate::{Xdg, PREVIEW};
#[derive(Debug)]
pub struct Boot {
pub cwd: PathBuf,
pub cache_dir: PathBuf,
pub state_dir: PathBuf,
pub cwd_file: Option<PathBuf>,
@ -43,46 +41,37 @@ impl Default for Boot {
let cwd = args
.cwd
.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());
let boot = Self {
cwd: cwd.unwrap_or("/".into()),
cache_dir: env::temp_dir().join("yazi"),
state_dir: Xdg::state_dir().unwrap(),
cwd_file: args.cwd_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() {
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 {
println!("Clearing cache directory: {:?}", boot.cache_dir);
fs::remove_dir_all(&boot.cache_dir).unwrap();
if PREVIEW.cache_dir == Xdg::cache_dir() {
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);
}
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))
}
}

View file

@ -23,7 +23,6 @@ static MERGED_KEYMAP: RoCell<String> = RoCell::new();
static MERGED_THEME: 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 LOG: RoCell<log::Log> = 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 THEME: RoCell<theme::Theme> = RoCell::new();
pub static BOOT: RoCell<boot::Boot> = RoCell::new();
pub fn init() {
MERGED_KEYMAP.with(Preset::keymap);
MERGED_THEME.with(Preset::theme);
MERGED_YAZI.with(Preset::yazi);
BOOT.with(Default::default);
KEYMAP.with(Default::default);
LOG.with(Default::default);
MANAGER.with(Default::default);
@ -45,4 +45,6 @@ pub fn init() {
PREVIEW.with(Default::default);
TASKS.with(Default::default);
THEME.with(Default::default);
BOOT.with(Default::default);
}

View file

@ -1,26 +1,65 @@
use std::{path::{Path, PathBuf}, time::{self, SystemTime}};
use md5::{Digest, Md5};
use serde::Deserialize;
use super::PreviewAdaptor;
use crate::MERGED_YAZI;
use crate::{xdg::Xdg, MERGED_YAZI};
#[derive(Debug, Deserialize)]
#[derive(Debug)]
pub struct Preview {
#[serde(skip)]
pub adaptor: PreviewAdaptor,
pub tab_size: u32,
pub adaptor: PreviewAdaptor,
pub tab_size: u32,
pub max_width: u32,
pub max_height: u32,
pub cache_dir: PathBuf,
}
impl Default for Preview {
fn default() -> Self {
#[derive(Deserialize)]
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();
outer.preview
let preview = toml::from_str::<Outer>(&MERGED_YAZI).unwrap().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))
}
}

View file

@ -1,4 +1,4 @@
use std::path::PathBuf;
use std::{env, path::PathBuf};
pub(super) struct Xdg;
@ -12,7 +12,7 @@ impl Xdg {
{
std::env::var_os("XDG_CONFIG_HOME")
.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")))
.map(|p| p.join("yazi"))
}
@ -27,9 +27,12 @@ impl Xdg {
{
std::env::var_os("XDG_STATE_HOME")
.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")))
.map(|p| p.join("yazi"))
}
}
#[inline]
pub(super) fn cache_dir() -> PathBuf { env::temp_dir().join("yazi") }
}

View file

@ -1,7 +1,7 @@
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 config::{BOOT, OPEN};
use config::{OPEN, PREVIEW};
use shared::{max_common_root, Defer, Term, MIME_DIR};
use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
@ -222,7 +222,7 @@ impl Manager {
let root = max_common_root(&old);
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 {
let Some(opener) = OPEN.block_opener("bulk.txt", "text/plain") else {
bail!("No opener for bulk rename");

View file

@ -2,7 +2,7 @@ use std::{io::BufRead, path::Path, sync::atomic::{AtomicUsize, Ordering}};
use adaptor::Adaptor;
use anyhow::anyhow;
use config::{BOOT, MANAGER, PREVIEW};
use config::{MANAGER, PREVIEW};
use shared::{MimeKind, PeekError};
use syntect::{easy::HighlightFile, util::as_24_bit_terminal_escaped};
use tokio::fs;
@ -62,7 +62,7 @@ impl Provider {
}
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() {
external::ffmpegthumbnailer(path, &cache, skip).await?;
}
@ -71,7 +71,7 @@ impl Provider {
}
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() {
external::pdftoppm(path, &cache, skip).await?;
}

View file

@ -2,7 +2,7 @@ use std::{collections::{BTreeMap, BTreeSet}, path::PathBuf, sync::Arc};
use adaptor::Image;
use anyhow::Result;
use config::BOOT;
use config::PREVIEW;
use parking_lot::Mutex;
use shared::{calculate_size, Throttle};
use tokio::{fs, sync::mpsc};
@ -74,7 +74,7 @@ impl Precache {
pub(crate) async fn work(&self, task: &mut PrecacheOp) -> Result<()> {
match 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() {
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))?;
}
PrecacheOp::Video(task) => {
let cache = BOOT.cache(&task.target, 0);
let cache = PREVIEW.cache(&task.target, 0);
if fs::metadata(&cache).await.is_ok() {
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))?;
}
PrecacheOp::Pdf(task) => {
let cache = BOOT.cache(&task.target, 0);
let cache = PREVIEW.cache(&task.target, 0);
if fs::metadata(&cache).await.is_ok() {
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
}