Detailed changes
@@ -9,6 +9,8 @@ disallowed-methods = [
{ path = "std::process::Command::spawn", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::spawn" },
{ path = "std::process::Command::output", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::output" },
{ path = "std::process::Command::status", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::status" },
+ { path = "serde_json::from_reader", reason = "Parsing from a buffer is much slower than first reading the buffer into a Vec/String, see https://github.com/serde-rs/json/issues/160#issuecomment-253446892. Use `serde_json::from_slice` instead." },
+ { path = "serde_json_lenient::from_reader", reason = "Parsing from a buffer is much slower than first reading the buffer into a Vec/String, see https://github.com/serde-rs/json/issues/160#issuecomment-253446892, Use `serde_json_lenient::from_slice` instead." },
]
disallowed-types = [
# { path = "std::collections::HashMap", replacement = "collections::HashMap" },
@@ -965,10 +965,11 @@ async fn heuristic_syntactic_expand(
let row_count = node_end.row - node_start.row + 1;
let mut ancestor_range = None;
let reached_outline_node = cx.background_executor().scoped({
- let node_range = node_range.clone();
- let outline_range = outline_range.clone();
- let ancestor_range = &mut ancestor_range;
- |scope| {scope.spawn(async move {
+ let node_range = node_range.clone();
+ let outline_range = outline_range.clone();
+ let ancestor_range = &mut ancestor_range;
+ |scope| {
+ scope.spawn(async move {
// Stop if we've exceeded the row count or reached an outline node. Then, find the interval
// of node children which contains the query range. For example, this allows just returning
// the header of a declaration rather than the entire declaration.
@@ -980,8 +981,11 @@ async fn heuristic_syntactic_expand(
if cursor.goto_first_child() {
loop {
let child_node = cursor.node();
- let child_range = previous_end..Point::from_ts_point(child_node.end_position());
- if included_child_start.is_none() && child_range.contains(&input_range.start) {
+ let child_range =
+ previous_end..Point::from_ts_point(child_node.end_position());
+ if included_child_start.is_none()
+ && child_range.contains(&input_range.start)
+ {
included_child_start = Some(child_range.start);
}
if child_range.contains(&input_range.end) {
@@ -997,19 +1001,22 @@ async fn heuristic_syntactic_expand(
if let Some(start) = included_child_start {
let row_count = end.row - start.row;
if row_count < max_row_count {
- *ancestor_range = Some(Some(RangeInclusive::new(start.row, end.row)));
+ *ancestor_range =
+ Some(Some(RangeInclusive::new(start.row, end.row)));
return;
}
}
log::info!(
- "Expanding to ancestor started on {} node exceeding row limit of {max_row_count}.",
+ "Expanding to ancestor started on {} node\
+ exceeding row limit of {max_row_count}.",
node.grammar_name()
);
*ancestor_range = Some(None);
}
})
- }});
+ }
+ });
reached_outline_node.await;
if let Some(node) = ancestor_range {
return node;
@@ -408,8 +408,8 @@ impl Theme {
/// Asynchronously reads the user theme from the specified path.
pub async fn read_user_theme(theme_path: &Path, fs: Arc<dyn Fs>) -> Result<ThemeFamilyContent> {
- let reader = fs.open_sync(theme_path).await?;
- let theme_family: ThemeFamilyContent = serde_json_lenient::from_reader(reader)?;
+ let bytes = fs.load_bytes(theme_path).await?;
+ let theme_family: ThemeFamilyContent = serde_json_lenient::from_slice(&bytes)?;
for theme in &theme_family.themes {
if theme
@@ -433,8 +433,8 @@ pub async fn read_icon_theme(
icon_theme_path: &Path,
fs: Arc<dyn Fs>,
) -> Result<IconThemeFamilyContent> {
- let reader = fs.open_sync(icon_theme_path).await?;
- let icon_theme_family: IconThemeFamilyContent = serde_json_lenient::from_reader(reader)?;
+ let bytes = fs.load_bytes(icon_theme_path).await?;
+ let icon_theme_family: IconThemeFamilyContent = serde_json_lenient::from_slice(&bytes)?;
Ok(icon_theme_family)
}
@@ -2,7 +2,7 @@ mod color;
mod vscode;
use std::fs::File;
-use std::io::Write;
+use std::io::{Read, Write};
use std::path::PathBuf;
use anyhow::{Context as _, Result};
@@ -89,15 +89,16 @@ fn main() -> Result<()> {
let theme_file_path = args.theme_path;
- let theme_file = match File::open(&theme_file_path) {
- Ok(file) => file,
+ let mut buffer = Vec::new();
+ match File::open(&theme_file_path).and_then(|mut file| file.read_to_end(&mut buffer)) {
+ Ok(_) => {}
Err(err) => {
log::info!("Failed to open file at path: {:?}", theme_file_path);
return Err(err)?;
}
};
- let vscode_theme: VsCodeTheme = serde_json_lenient::from_reader(theme_file)
+ let vscode_theme: VsCodeTheme = serde_json_lenient::from_slice(&buffer)
.context(format!("failed to parse theme {theme_file_path:?}"))?;
let theme_metadata = ThemeMetadata {
@@ -70,10 +70,7 @@ use std::{
sync::atomic::{self, AtomicBool},
};
use terminal_view::terminal_panel::{self, TerminalPanel};
-use theme::{
- ActiveTheme, GlobalTheme, IconThemeNotFoundError, SystemAppearance, ThemeNotFoundError,
- ThemeRegistry, ThemeSettings,
-};
+use theme::{ActiveTheme, GlobalTheme, SystemAppearance, ThemeRegistry, ThemeSettings};
use ui::{PopoverMenuHandle, prelude::*};
use util::markdown::MarkdownString;
use util::rel_path::RelPath;
@@ -2032,41 +2029,88 @@ pub(crate) fn eager_load_active_theme_and_icon_theme(fs: Arc<dyn Fs>, cx: &mut A
let theme_settings = ThemeSettings::get_global(cx);
let appearance = SystemAppearance::global(cx).0;
- let theme_name = theme_settings.theme.name(appearance);
- if matches!(
- theme_registry.get(&theme_name.0),
- Err(ThemeNotFoundError(_))
- ) && let Some(theme_path) = extension_store
- .read(cx)
- .path_to_extension_theme(&theme_name.0)
- {
- if cx
- .background_executor()
- .block(theme_registry.load_user_theme(&theme_path, fs.clone()))
- .log_err()
- .is_some()
- {
- GlobalTheme::reload_theme(cx);
- }
+ enum LoadTarget {
+ Theme(PathBuf),
+ IconTheme((PathBuf, PathBuf)),
}
- let theme_settings = ThemeSettings::get_global(cx);
+ let theme_name = theme_settings.theme.name(appearance);
let icon_theme_name = theme_settings.icon_theme.name(appearance);
- if matches!(
- theme_registry.get_icon_theme(&icon_theme_name.0),
- Err(IconThemeNotFoundError(_))
- ) && let Some((icon_theme_path, icons_root_path)) = extension_store
- .read(cx)
- .path_to_extension_icon_theme(&icon_theme_name.0)
- {
- if cx
- .background_executor()
- .block(theme_registry.load_icon_theme(&icon_theme_path, &icons_root_path, fs))
- .log_err()
- .is_some()
- {
- GlobalTheme::reload_icon_theme(cx);
+ let themes_to_load = [
+ theme_registry
+ .get(&theme_name.0)
+ .is_err()
+ .then(|| {
+ extension_store
+ .read(cx)
+ .path_to_extension_theme(&theme_name.0)
+ })
+ .flatten()
+ .map(LoadTarget::Theme),
+ theme_registry
+ .get_icon_theme(&icon_theme_name.0)
+ .is_err()
+ .then(|| {
+ extension_store
+ .read(cx)
+ .path_to_extension_icon_theme(&icon_theme_name.0)
+ })
+ .flatten()
+ .map(LoadTarget::IconTheme),
+ ];
+
+ enum ReloadTarget {
+ Theme,
+ IconTheme,
+ }
+
+ let executor = cx.background_executor();
+ let reload_tasks = parking_lot::Mutex::new(Vec::with_capacity(themes_to_load.len()));
+
+ let mut themes_to_load = themes_to_load.into_iter().flatten().peekable();
+
+ if themes_to_load.peek().is_none() {
+ return;
+ }
+
+ executor.block(executor.scoped(|scope| {
+ for load_target in themes_to_load {
+ let theme_registry = &theme_registry;
+ let reload_tasks = &reload_tasks;
+ let fs = fs.clone();
+
+ scope.spawn(async {
+ match load_target {
+ LoadTarget::Theme(theme_path) => {
+ if theme_registry
+ .load_user_theme(&theme_path, fs)
+ .await
+ .log_err()
+ .is_some()
+ {
+ reload_tasks.lock().push(ReloadTarget::Theme);
+ }
+ }
+ LoadTarget::IconTheme((icon_theme_path, icons_root_path)) => {
+ if theme_registry
+ .load_icon_theme(&icon_theme_path, &icons_root_path, fs)
+ .await
+ .log_err()
+ .is_some()
+ {
+ reload_tasks.lock().push(ReloadTarget::IconTheme);
+ }
+ }
+ }
+ });
}
+ }));
+
+ for reload_target in reload_tasks.into_inner() {
+ match reload_target {
+ ReloadTarget::Theme => GlobalTheme::reload_theme(cx),
+ ReloadTarget::IconTheme => GlobalTheme::reload_icon_theme(cx),
+ };
}
}
@@ -50,7 +50,7 @@ use zed_perf::{FailKind, Importance, Output, TestMdata, Timings, consts};
use std::{
fs::OpenOptions,
- io::Write,
+ io::{Read, Write},
num::NonZero,
path::{Path, PathBuf},
process::{Command, Stdio},
@@ -264,8 +264,14 @@ fn compare_profiles(args: &[String]) {
let prefix = elems.next().unwrap();
assert_eq!("json", elems.next().unwrap());
assert!(elems.next().is_none());
- let handle = OpenOptions::new().read(true).open(entry.path()).unwrap();
- let o_other: Output = serde_json::from_reader(handle).unwrap();
+ let mut buffer = Vec::new();
+ let _ = OpenOptions::new()
+ .read(true)
+ .open(entry.path())
+ .unwrap()
+ .read_to_end(&mut buffer)
+ .unwrap();
+ let o_other: Output = serde_json::from_slice(&buffer).unwrap();
output.merge(o_other, prefix);
};