mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
c4f76bd778
commit
a7e8567e81
10 changed files with 55 additions and 43 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{env, fs, path::{Path, PathBuf}, time::{self, SystemTime}};
|
use std::{env, fs, path::{Path, PathBuf}, process, time::{self, SystemTime}};
|
||||||
|
|
||||||
use clap::{command, Parser};
|
use clap::{command, Parser};
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
|
|
@ -30,6 +30,10 @@ struct Args {
|
||||||
/// Write the selected files on open emitted by the chooser mode
|
/// Write the selected files on open emitted by the chooser mode
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
chooser_file: Option<PathBuf>,
|
chooser_file: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Clear the cache directory
|
||||||
|
#[arg(long, action)]
|
||||||
|
clear_cache: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Boot {
|
impl Default for Boot {
|
||||||
|
|
@ -58,6 +62,12 @@ impl Default for Boot {
|
||||||
fs::create_dir_all(&boot.state_dir).unwrap();
|
fs::create_dir_all(&boot.state_dir).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.clear_cache {
|
||||||
|
println!("Clearing cache directory: {:?}", boot.cache_dir);
|
||||||
|
fs::remove_dir_all(&boot.cache_dir).unwrap();
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
boot
|
boot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
core/src/external/ffmpegthumbnailer.rs
vendored
8
core/src/external/ffmpegthumbnailer.rs
vendored
|
|
@ -1,13 +1,13 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use config::PREVIEW;
|
use config::PREVIEW;
|
||||||
use shared::PagedError;
|
use shared::PeekError;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
|
||||||
pub async fn ffmpegthumbnailer(src: &Path, dest: &Path, skip: usize) -> Result<(), PagedError> {
|
pub async fn ffmpegthumbnailer(src: &Path, dest: &Path, skip: usize) -> Result<(), PeekError> {
|
||||||
let percentage = 5 + skip;
|
let percentage = 5 + skip;
|
||||||
if percentage >= 100 {
|
if percentage > 95 {
|
||||||
return Err(PagedError::Exceed(94));
|
return Err(PeekError::Exceed(95 - 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = Command::new("ffmpegthumbnailer")
|
let output = Command::new("ffmpegthumbnailer")
|
||||||
|
|
|
||||||
6
core/src/external/jq.rs
vendored
6
core/src/external/jq.rs
vendored
|
|
@ -2,10 +2,10 @@ use std::{path::Path, process::Stdio};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use config::PREVIEW;
|
use config::PREVIEW;
|
||||||
use shared::PagedError;
|
use shared::PeekError;
|
||||||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command};
|
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command};
|
||||||
|
|
||||||
pub async fn jq(path: &Path, skip: usize, limit: usize) -> Result<String, PagedError> {
|
pub async fn jq(path: &Path, skip: usize, limit: usize) -> Result<String, PeekError> {
|
||||||
let mut child = Command::new("jq")
|
let mut child = Command::new("jq")
|
||||||
.args(["-C", "--indent", &PREVIEW.tab_size.to_string(), "."])
|
.args(["-C", "--indent", &PREVIEW.tab_size.to_string(), "."])
|
||||||
.arg(path)
|
.arg(path)
|
||||||
|
|
@ -30,7 +30,7 @@ pub async fn jq(path: &Path, skip: usize, limit: usize) -> Result<String, PagedE
|
||||||
}
|
}
|
||||||
|
|
||||||
if skip > 0 && i < skip + limit {
|
if skip > 0 && i < skip + limit {
|
||||||
Err(PagedError::Exceed(i.saturating_sub(limit)))
|
Err(PeekError::Exceed(i.saturating_sub(limit)))
|
||||||
} else {
|
} else {
|
||||||
Ok(lines)
|
Ok(lines)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
core/src/external/lsar.rs
vendored
6
core/src/external/lsar.rs
vendored
|
|
@ -3,7 +3,7 @@ use std::path::Path;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use shared::PagedError;
|
use shared::PeekError;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -31,7 +31,7 @@ pub struct LsarFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::manual_map)]
|
#[allow(clippy::manual_map)]
|
||||||
pub async fn lsar(path: &Path, skip: usize, limit: usize) -> Result<Vec<LsarFile>, PagedError> {
|
pub async fn lsar(path: &Path, skip: usize, limit: usize) -> Result<Vec<LsarFile>, PeekError> {
|
||||||
let output =
|
let output =
|
||||||
Command::new("lsar").args(["-j", "-jss"]).arg(path).kill_on_drop(true).output().await?;
|
Command::new("lsar").args(["-j", "-jss"]).arg(path).kill_on_drop(true).output().await?;
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ pub async fn lsar(path: &Path, skip: usize, limit: usize) -> Result<Vec<LsarFile
|
||||||
}
|
}
|
||||||
|
|
||||||
if skip > 0 && files.len() < limit {
|
if skip > 0 && files.len() < limit {
|
||||||
Err(PagedError::Exceed(i.saturating_sub(limit)))
|
Err(PeekError::Exceed(i.saturating_sub(limit)))
|
||||||
} else {
|
} else {
|
||||||
Ok(files)
|
Ok(files)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
core/src/external/pdftoppm.rs
vendored
6
core/src/external/pdftoppm.rs
vendored
|
|
@ -2,10 +2,10 @@ use std::path::Path;
|
||||||
|
|
||||||
use adaptor::Image;
|
use adaptor::Image;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use shared::PagedError;
|
use shared::PeekError;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
|
||||||
pub async fn pdftoppm(src: &Path, dest: impl AsRef<Path>, skip: usize) -> Result<(), PagedError> {
|
pub async fn pdftoppm(src: &Path, dest: impl AsRef<Path>, skip: usize) -> Result<(), PeekError> {
|
||||||
let output = Command::new("pdftoppm")
|
let output = Command::new("pdftoppm")
|
||||||
.args(["-singlefile", "-jpeg", "-jpegopt", "quality=75", "-f"])
|
.args(["-singlefile", "-jpeg", "-jpegopt", "quality=75", "-f"])
|
||||||
.arg((skip + 1).to_string())
|
.arg((skip + 1).to_string())
|
||||||
|
|
@ -22,7 +22,7 @@ pub async fn pdftoppm(src: &Path, dest: impl AsRef<Path>, skip: usize) -> Result
|
||||||
.map(|cap| cap[1].parse().unwrap())
|
.map(|cap| cap[1].parse().unwrap())
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
return if pages > 0 { Err(PagedError::Exceed(pages - 1)) } else { Err(s.to_string().into()) };
|
return if pages > 0 { Err(PeekError::Exceed(pages - 1)) } else { Err(s.to_string().into()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Image::precache_anyway(output.stdout.into(), dest).await?)
|
Ok(Image::precache_anyway(output.stdout.into(), dest).await?)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{mem, path::{Path, PathBuf}, sync::atomic::Ordering};
|
||||||
|
|
||||||
use adaptor::Adaptor;
|
use adaptor::Adaptor;
|
||||||
use config::MANAGER;
|
use config::MANAGER;
|
||||||
use shared::{MimeKind, PagedError};
|
use shared::{MimeKind, PeekError};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
use super::{provider::INCR, Provider};
|
use super::{provider::INCR, Provider};
|
||||||
|
|
@ -51,7 +51,6 @@ impl Preview {
|
||||||
|
|
||||||
self.handle.take().map(|h| h.abort());
|
self.handle.take().map(|h| h.abort());
|
||||||
INCR.fetch_add(1, Ordering::Relaxed);
|
INCR.fetch_add(1, Ordering::Relaxed);
|
||||||
Adaptor::image_hide(MANAGER.layout.preview_rect()).ok();
|
|
||||||
|
|
||||||
self.skip = skip;
|
self.skip = skip;
|
||||||
self.handle = Some(tokio::spawn(async move {
|
self.handle = Some(tokio::spawn(async move {
|
||||||
|
|
@ -59,7 +58,7 @@ impl Preview {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
emit!(Preview(path, mime, result));
|
emit!(Preview(path, mime, result));
|
||||||
}
|
}
|
||||||
Err(PagedError::Exceed(max)) => {
|
Err(PeekError::Exceed(max)) => {
|
||||||
emit!(Peek(path, max));
|
emit!(Peek(path, max));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,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::{BOOT, MANAGER, PREVIEW};
|
||||||
use shared::{MimeKind, PagedError};
|
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;
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ impl Provider {
|
||||||
kind: MimeKind,
|
kind: MimeKind,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
skip: usize,
|
skip: usize,
|
||||||
) -> Result<PreviewData, PagedError> {
|
) -> Result<PreviewData, PeekError> {
|
||||||
match kind {
|
match kind {
|
||||||
MimeKind::Empty => Ok(PreviewData::None),
|
MimeKind::Empty => Ok(PreviewData::None),
|
||||||
MimeKind::Archive => Provider::archive(path, skip).await.map(PreviewData::Text),
|
MimeKind::Archive => Provider::archive(path, skip).await.map(PreviewData::Text),
|
||||||
|
|
@ -47,7 +47,7 @@ impl Provider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn folder(path: &Path) -> Result<PreviewData, PagedError> {
|
pub(super) async fn folder(path: &Path) -> Result<PreviewData, PeekError> {
|
||||||
emit!(Files(match Files::read_dir(path).await {
|
emit!(Files(match Files::read_dir(path).await {
|
||||||
Ok(items) => FilesOp::Read(path.to_path_buf(), items),
|
Ok(items) => FilesOp::Read(path.to_path_buf(), items),
|
||||||
Err(_) => FilesOp::IOErr(path.to_path_buf()),
|
Err(_) => FilesOp::IOErr(path.to_path_buf()),
|
||||||
|
|
@ -56,12 +56,12 @@ impl Provider {
|
||||||
Ok(PreviewData::Folder)
|
Ok(PreviewData::Folder)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn image(path: &Path) -> Result<PreviewData, PagedError> {
|
pub(super) async fn image(path: &Path) -> Result<PreviewData, PeekError> {
|
||||||
Adaptor::image_show(path, MANAGER.layout.preview_rect()).await?;
|
Adaptor::image_show(path, MANAGER.layout.preview_rect()).await?;
|
||||||
Ok(PreviewData::Image)
|
Ok(PreviewData::Image)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn video(path: &Path, skip: usize) -> Result<PreviewData, PagedError> {
|
pub(super) async fn video(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
|
||||||
let cache = BOOT.cache(path, skip);
|
let cache = BOOT.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?;
|
||||||
|
|
@ -70,7 +70,7 @@ impl Provider {
|
||||||
Self::image(&cache).await
|
Self::image(&cache).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn pdf(path: &Path, skip: usize) -> Result<PreviewData, PagedError> {
|
pub(super) async fn pdf(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
|
||||||
let cache = BOOT.cache(path, skip);
|
let cache = BOOT.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?;
|
||||||
|
|
@ -79,11 +79,11 @@ impl Provider {
|
||||||
Self::image(&cache).await
|
Self::image(&cache).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn json(path: &Path, skip: usize) -> Result<String, PagedError> {
|
pub(super) async fn json(path: &Path, skip: usize) -> Result<String, PeekError> {
|
||||||
external::jq(path, skip, MANAGER.layout.preview_height()).await
|
external::jq(path, skip, MANAGER.layout.preview_height()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn archive(path: &Path, skip: usize) -> Result<String, PagedError> {
|
pub(super) async fn archive(path: &Path, skip: usize) -> Result<String, PeekError> {
|
||||||
Ok(
|
Ok(
|
||||||
external::lsar(path, skip, MANAGER.layout.preview_height())
|
external::lsar(path, skip, MANAGER.layout.preview_height())
|
||||||
.await?
|
.await?
|
||||||
|
|
@ -94,13 +94,13 @@ impl Provider {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn highlight(path: &Path, skip: usize) -> Result<String, PagedError> {
|
pub(super) async fn highlight(path: &Path, skip: usize) -> Result<String, PeekError> {
|
||||||
let tick = INCR.load(Ordering::Relaxed);
|
let tick = INCR.load(Ordering::Relaxed);
|
||||||
let path = path.to_path_buf();
|
let path = path.to_path_buf();
|
||||||
let spaces = " ".repeat(PREVIEW.tab_size as usize);
|
let spaces = " ".repeat(PREVIEW.tab_size as usize);
|
||||||
|
|
||||||
let (syntaxes, theme) = highlighter();
|
let (syntaxes, theme) = highlighter();
|
||||||
tokio::task::spawn_blocking(move || -> Result<String, PagedError> {
|
tokio::task::spawn_blocking(move || -> Result<String, PeekError> {
|
||||||
let mut h = HighlightFile::new(path, syntaxes, theme)?;
|
let mut h = HighlightFile::new(path, syntaxes, theme)?;
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
|
@ -109,25 +109,25 @@ impl Provider {
|
||||||
let limit = MANAGER.layout.preview_height();
|
let limit = MANAGER.layout.preview_height();
|
||||||
while h.reader.read_line(&mut line)? > 0 {
|
while h.reader.read_line(&mut line)? > 0 {
|
||||||
if tick != INCR.load(Ordering::Relaxed) {
|
if tick != INCR.load(Ordering::Relaxed) {
|
||||||
return Err("Preview cancelled".into());
|
return Err("Highlighting cancelled".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
if i > skip + limit {
|
if i > skip + limit {
|
||||||
break;
|
break;
|
||||||
} else if i <= skip {
|
|
||||||
line.clear();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
line = line.replace('\t', &spaces);
|
line = line.replace('\t', &spaces);
|
||||||
let regions = h.highlight_lines.highlight_line(&line, syntaxes).map_err(|e| anyhow!(e))?;
|
let regions = h.highlight_lines.highlight_line(&line, syntaxes).map_err(|e| anyhow!(e))?;
|
||||||
|
|
||||||
|
if i > skip {
|
||||||
buf.push_str(&as_24_bit_terminal_escaped(®ions, false));
|
buf.push_str(&as_24_bit_terminal_escaped(®ions, false));
|
||||||
|
}
|
||||||
line.clear();
|
line.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if skip > 0 && i < skip + limit {
|
if skip > 0 && i < skip + limit {
|
||||||
return Err(PagedError::Exceed(i.saturating_sub(limit)));
|
return Err(PeekError::Exceed(i.saturating_sub(limit)));
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push_str("\x1b[0m");
|
buf.push_str("\x1b[0m");
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,8 @@ impl Tab {
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = self.preview.lock.as_ref().unwrap().0.clone();
|
let path = self.preview.lock.as_ref().unwrap().0.clone();
|
||||||
if let Some(dir) = self.history(&path) {
|
if let Some(folder) = self.history(&path) {
|
||||||
let max = dir.files.len().saturating_sub(MANAGER.layout.preview_height());
|
let max = folder.files.len().saturating_sub(MANAGER.layout.preview_height());
|
||||||
if new > max {
|
if new > max {
|
||||||
emit!(Peek(path, max));
|
emit!(Peek(path, max));
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
3
shared/src/errors/mod.rs
Normal file
3
shared/src/errors/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
mod peek;
|
||||||
|
|
||||||
|
pub use peek::*;
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use std::{error::Error, fmt::{self, Display}};
|
use std::{error::Error, fmt::{self, Display}};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PagedError {
|
pub enum PeekError {
|
||||||
Exceed(usize),
|
Exceed(usize),
|
||||||
Unexpected(String),
|
Unexpected(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for PagedError {
|
impl Display for PeekError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Exceed(lines) => write!(f, "Exceed: {lines}"),
|
Self::Exceed(lines) => write!(f, "Exceed: {lines}"),
|
||||||
|
|
@ -15,20 +15,20 @@ impl Display for PagedError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for PagedError {}
|
impl Error for PeekError {}
|
||||||
|
|
||||||
impl From<String> for PagedError {
|
impl From<String> for PeekError {
|
||||||
fn from(error: String) -> Self { Self::Unexpected(error) }
|
fn from(error: String) -> Self { Self::Unexpected(error) }
|
||||||
}
|
}
|
||||||
impl From<&str> for PagedError {
|
impl From<&str> for PeekError {
|
||||||
fn from(error: &str) -> Self { Self::from(error.to_owned()) }
|
fn from(error: &str) -> Self { Self::from(error.to_owned()) }
|
||||||
}
|
}
|
||||||
impl From<anyhow::Error> for PagedError {
|
impl From<anyhow::Error> for PeekError {
|
||||||
fn from(error: anyhow::Error) -> Self { Self::from(error.to_string()) }
|
fn from(error: anyhow::Error) -> Self { Self::from(error.to_string()) }
|
||||||
}
|
}
|
||||||
impl From<std::io::Error> for PagedError {
|
impl From<std::io::Error> for PeekError {
|
||||||
fn from(error: std::io::Error) -> Self { Self::from(error.to_string()) }
|
fn from(error: std::io::Error) -> Self { Self::from(error.to_string()) }
|
||||||
}
|
}
|
||||||
impl From<tokio::task::JoinError> for PagedError {
|
impl From<tokio::task::JoinError> for PeekError {
|
||||||
fn from(error: tokio::task::JoinError) -> Self { Self::from(error.to_string()) }
|
fn from(error: tokio::task::JoinError) -> Self { Self::from(error.to_string()) }
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue