perf: introduce copy-on-write for event system to eliminate all memory reallocations

This commit is contained in:
sxyazi 2024-11-28 01:29:50 +08:00
parent 5e48df5126
commit 1f0817080e
No known key found for this signature in database
8 changed files with 37 additions and 37 deletions

View file

@ -21,7 +21,7 @@ impl<'a> Input<'a> {
bail!("Highlighting is disabled"); bail!("Highlighting is disabled");
} }
let (theme, syntaxes) = Highlighter::init(); let (theme, syntaxes) = futures::executor::block_on(Highlighter::init());
if let Some(syntax) = syntaxes.find_syntax_by_name("Bourne Again Shell (bash)") { if let Some(syntax) = syntaxes.find_syntax_by_name("Bourne Again Shell (bash)") {
let mut h = HighlightLines::new(syntax, theme); let mut h = HighlightLines::new(syntax, theme);
let regions = h.highlight_line(self.cx.input.value(), syntaxes)?; let regions = h.highlight_line(self.cx.input.value(), syntaxes)?;

View file

@ -21,7 +21,7 @@ function M:preload()
return 1 return 1
end end
local child, err = Command("magick"):args({ local status, err = Command("magick"):args({
"-size", "-size",
"800x560", "800x560",
"-gravity", "-gravity",
@ -37,15 +37,14 @@ function M:preload()
"+0+0", "+0+0",
TEXT, TEXT,
"JPG:" .. tostring(cache), "JPG:" .. tostring(cache),
}):spawn() }):status()
if not child then if status then
return status.success and 1 or 2
else
ya.err("Failed to start `magick`, error: " .. err) ya.err("Failed to start `magick`, error: " .. err)
return 0 return 0
end end
local status = child:wait()
return status and status.success and 1 or 2
end end
return M return M

View file

@ -19,7 +19,7 @@ function M:preload()
return 1 return 1
end end
local child, err = Command("magick"):args({ local status, err = Command("magick"):args({
"-density", "-density",
"200", "200",
tostring(self.file.url), tostring(self.file.url),
@ -30,15 +30,14 @@ function M:preload()
tostring(PREVIEW.image_quality), tostring(PREVIEW.image_quality),
"-auto-orient", "-auto-orient",
"JPG:" .. tostring(cache), "JPG:" .. tostring(cache),
}):spawn() }):status()
if not child then if status then
return status.success and 1 or 2
else
ya.err("Failed to start `magick`, error: " .. err) ya.err("Failed to start `magick`, error: " .. err)
return 0 return 0
end end
local status = child:wait()
return status and status.success and 1 or 2
end end
function M:spot(job) require("file"):spot(job) end function M:spot(job) require("file"):spot(job) end

View file

@ -49,7 +49,7 @@ function M:preload()
local ss = math.floor(meta.format.duration * percent / 100) local ss = math.floor(meta.format.duration * percent / 100)
local qv = 31 - math.floor(PREVIEW.image_quality * 0.3) local qv = 31 - math.floor(PREVIEW.image_quality * 0.3)
-- stylua: ignore -- stylua: ignore
local child, err = Command("ffmpeg"):args({ local status, err = Command("ffmpeg"):args({
"-v", "quiet", "-hwaccel", "auto", "-v", "quiet", "-hwaccel", "auto",
"-skip_frame", "nokey", "-ss", ss, "-skip_frame", "nokey", "-ss", ss,
"-an", "-sn", "-dn", "-an", "-sn", "-dn",
@ -59,15 +59,14 @@ function M:preload()
"-vf", string.format("scale=%d:-2:flags=fast_bilinear", PREVIEW.max_width), "-vf", string.format("scale=%d:-2:flags=fast_bilinear", PREVIEW.max_width),
"-f", "image2", "-f", "image2",
"-y", tostring(cache), "-y", tostring(cache),
}):spawn() }):status()
if not child then if status then
return status.success and 1 or 2
else
ya.err("Failed to start `ffmpeg`, error: " .. err) ya.err("Failed to start `ffmpeg`, error: " .. err)
return 0 return 0
end end
local status = child:wait()
return status and status.success and 1 or 2
end end
function M:spot(job) function M:spot(job)

View file

@ -1,14 +1,14 @@
use std::{borrow::Cow, io::Cursor, mem, path::{Path, PathBuf}, sync::OnceLock}; use std::{borrow::Cow, io::Cursor, mem, path::{Path, PathBuf}};
use anyhow::{Result, anyhow}; use anyhow::{Result, anyhow};
use ratatui::{layout::Size, text::{Line, Span, Text}}; use ratatui::{layout::Size, text::{Line, Span, Text}};
use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}}; use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}};
use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}}; use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}, sync::OnceCell};
use yazi_config::{PREVIEW, THEME, preview::PreviewWrap}; use yazi_config::{PREVIEW, THEME, preview::PreviewWrap};
use yazi_shared::{Ids, errors::PeekError, replace_to_printable}; use yazi_shared::{Ids, errors::PeekError, replace_to_printable};
static INCR: Ids = Ids::new(); static INCR: Ids = Ids::new();
static SYNTECT: OnceLock<(Theme, SyntaxSet)> = OnceLock::new(); static SYNTECT: OnceCell<(Theme, SyntaxSet)> = OnceCell::const_new();
pub struct Highlighter { pub struct Highlighter {
path: PathBuf, path: PathBuf,
@ -18,19 +18,22 @@ impl Highlighter {
#[inline] #[inline]
pub fn new(path: &Path) -> Self { Self { path: path.to_owned() } } pub fn new(path: &Path) -> Self { Self { path: path.to_owned() } }
pub fn init() -> (&'static Theme, &'static SyntaxSet) { pub async fn init() -> (&'static Theme, &'static SyntaxSet) {
let r = SYNTECT.get_or_init(|| { let f = || {
let theme = std::fs::File::open(&THEME.manager.syntect_theme) tokio::task::spawn_blocking(|| {
.map_err(LoadingError::Io) let theme = std::fs::File::open(&THEME.manager.syntect_theme)
.and_then(|f| ThemeSet::load_from_reader(&mut std::io::BufReader::new(f))) .map_err(LoadingError::Io)
.or_else(|_| ThemeSet::load_from_reader(&mut Cursor::new(yazi_prebuild::ansi_theme()))); .and_then(|f| ThemeSet::load_from_reader(&mut std::io::BufReader::new(f)))
.or_else(|_| ThemeSet::load_from_reader(&mut Cursor::new(yazi_prebuild::ansi_theme())));
let syntaxes = dumps::from_uncompressed_data(yazi_prebuild::syntaxes()); let syntaxes = dumps::from_uncompressed_data(yazi_prebuild::syntaxes());
(theme.unwrap(), syntaxes.unwrap()) (theme.unwrap(), syntaxes.unwrap())
}); })
};
(&r.0, &r.1) let (theme, syntaxes) = SYNTECT.get_or_try_init(f).await.unwrap();
(theme, syntaxes)
} }
#[inline] #[inline]
@ -100,7 +103,7 @@ impl Highlighter {
syntax: &'static SyntaxReference, syntax: &'static SyntaxReference,
) -> Result<Text<'static>, PeekError> { ) -> Result<Text<'static>, PeekError> {
let ticket = INCR.current(); let ticket = INCR.current();
let (theme, syntaxes) = Self::init(); let (theme, syntaxes) = Self::init().await;
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
let mut h = HighlightLines::new(syntax, theme); let mut h = HighlightLines::new(syntax, theme);
@ -128,7 +131,7 @@ impl Highlighter {
} }
async fn find_syntax(path: &Path) -> Result<&'static SyntaxReference> { async fn find_syntax(path: &Path) -> Result<&'static SyntaxReference> {
let (_, syntaxes) = Self::init(); let (_, syntaxes) = Self::init().await;
let name = path.file_name().map(|n| n.to_string_lossy()).unwrap_or_default(); let name = path.file_name().map(|n| n.to_string_lossy()).unwrap_or_default();
if let Some(s) = syntaxes.find_syntax_by_extension(&name) { if let Some(s) = syntaxes.find_syntax_by_extension(&name) {
return Ok(s); return Ok(s);

View file

@ -2,7 +2,7 @@ use anyhow::bail;
use mlua::{Lua, Table}; use mlua::{Lua, Table};
use yazi_shared::event::{Cmd, Data}; use yazi_shared::event::{Cmd, Data};
pub type PluginCallback = Box<dyn FnOnce(&Lua, Table) -> mlua::Result<()> + Send>; pub type PluginCallback = Box<dyn FnOnce(&Lua, Table) -> mlua::Result<()> + Send + Sync>;
#[derive(Default)] #[derive(Default)]
pub struct PluginOpt { pub struct PluginOpt {

View file

@ -49,7 +49,7 @@ impl Cmd {
} }
#[inline] #[inline]
pub fn with_any(mut self, name: impl ToString, data: impl Any + Send) -> Self { pub fn with_any(mut self, name: impl ToString, data: impl Any + Send + Sync) -> Self {
self.args.insert(name.to_string(), Data::Any(Box::new(data))); self.args.insert(name.to_string(), Data::Any(Box::new(data)));
self self
} }

View file

@ -18,7 +18,7 @@ pub enum Data {
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
Url(Url), Url(Url),
#[serde(skip)] #[serde(skip)]
Any(Box<dyn Any + Send>), Any(Box<dyn Any + Send + Sync>),
} }
impl Data { impl Data {