Compare commits
11 Commits
performanc
...
tracy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3201c4f7f5 | ||
|
|
38e5facb11 | ||
|
|
7a37626258 | ||
|
|
6d925345a5 | ||
|
|
7bef8880b4 | ||
|
|
9b002caa4d | ||
|
|
860bbdbe78 | ||
|
|
1dcc2102eb | ||
|
|
d230a3e199 | ||
|
|
ae7ae96d2e | ||
|
|
10abccbe61 |
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -3131,6 +3131,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"paths",
|
||||
"postage",
|
||||
"profiling",
|
||||
"rand 0.9.1",
|
||||
"regex",
|
||||
"release_channel",
|
||||
@@ -4653,6 +4654,7 @@ dependencies = [
|
||||
"paths",
|
||||
"picker",
|
||||
"pretty_assertions",
|
||||
"profiling",
|
||||
"project",
|
||||
"rpc",
|
||||
"schemars 1.0.1",
|
||||
@@ -5916,6 +5918,7 @@ dependencies = [
|
||||
"menu",
|
||||
"picker",
|
||||
"pretty_assertions",
|
||||
"profiling",
|
||||
"project",
|
||||
"schemars 1.0.1",
|
||||
"search",
|
||||
@@ -6796,6 +6799,7 @@ dependencies = [
|
||||
"log",
|
||||
"parking_lot",
|
||||
"pretty_assertions",
|
||||
"profiling",
|
||||
"rand 0.9.1",
|
||||
"regex",
|
||||
"rope",
|
||||
@@ -6808,6 +6812,7 @@ dependencies = [
|
||||
"text",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
"tracy-client",
|
||||
"unindent",
|
||||
"url",
|
||||
"util",
|
||||
@@ -7107,6 +7112,7 @@ dependencies = [
|
||||
"sum_tree",
|
||||
"taffy",
|
||||
"thiserror 2.0.12",
|
||||
"tracy-client",
|
||||
"unicode-segmentation",
|
||||
"usvg",
|
||||
"util",
|
||||
@@ -12068,18 +12074,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "profiling"
|
||||
version = "1.0.16"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
|
||||
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
|
||||
dependencies = [
|
||||
"profiling-procmacros",
|
||||
"tracy-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiling-procmacros"
|
||||
version = "1.0.16"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
|
||||
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
@@ -12127,6 +12134,7 @@ dependencies = [
|
||||
"postage",
|
||||
"prettier",
|
||||
"pretty_assertions",
|
||||
"profiling",
|
||||
"rand 0.9.1",
|
||||
"regex",
|
||||
"release_channel",
|
||||
@@ -12179,6 +12187,7 @@ dependencies = [
|
||||
"language",
|
||||
"menu",
|
||||
"pretty_assertions",
|
||||
"profiling",
|
||||
"project",
|
||||
"rayon",
|
||||
"schemars 1.0.1",
|
||||
@@ -12189,6 +12198,7 @@ dependencies = [
|
||||
"smallvec",
|
||||
"telemetry",
|
||||
"theme",
|
||||
"tracy-client",
|
||||
"ui",
|
||||
"util",
|
||||
"workspace",
|
||||
@@ -14482,6 +14492,7 @@ dependencies = [
|
||||
"log",
|
||||
"paths",
|
||||
"pretty_assertions",
|
||||
"profiling",
|
||||
"release_channel",
|
||||
"rust-embed",
|
||||
"schemars 1.0.1",
|
||||
@@ -16889,6 +16900,23 @@ dependencies = [
|
||||
"tracing-serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracy-client"
|
||||
version = "0.18.2"
|
||||
dependencies = [
|
||||
"loom",
|
||||
"once_cell",
|
||||
"tracy-client-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracy-client-sys"
|
||||
version = "0.26.1"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trait-variant"
|
||||
version = "0.1.2"
|
||||
@@ -19867,6 +19895,7 @@ dependencies = [
|
||||
"paths",
|
||||
"postage",
|
||||
"pretty_assertions",
|
||||
"profiling",
|
||||
"rand 0.9.1",
|
||||
"rpc",
|
||||
"serde",
|
||||
@@ -19876,6 +19905,7 @@ dependencies = [
|
||||
"smol",
|
||||
"sum_tree",
|
||||
"text",
|
||||
"tracy-client",
|
||||
"util",
|
||||
"workspace-hack",
|
||||
"zlog",
|
||||
@@ -20335,6 +20365,7 @@ dependencies = [
|
||||
"time",
|
||||
"title_bar",
|
||||
"toolchain_selector",
|
||||
"tracy-client",
|
||||
"tree-sitter-md",
|
||||
"tree-sitter-rust",
|
||||
"ui",
|
||||
|
||||
@@ -595,7 +595,7 @@ portable-pty = "0.9.0"
|
||||
postage = { version = "0.5", features = ["futures-traits"] }
|
||||
pretty_assertions = { version = "1.3.0", features = ["unstable"] }
|
||||
proc-macro2 = "1.0.93"
|
||||
profiling = "1"
|
||||
profiling = "1.0.17"
|
||||
prost = "0.9"
|
||||
prost-build = "0.9"
|
||||
prost-types = "0.9"
|
||||
@@ -667,6 +667,7 @@ tokio = { version = "1" }
|
||||
tokio-tungstenite = { version = "0.26", features = ["__rustls-tls"] }
|
||||
toml = "0.8"
|
||||
tower-http = "0.4.4"
|
||||
tracy-client = { version = "0.18.2", features = ["fibers"] }
|
||||
tree-sitter = { version = "0.25.10", features = ["wasm"] }
|
||||
tree-sitter-bash = "0.25.0"
|
||||
tree-sitter-c = "0.23"
|
||||
@@ -772,6 +773,7 @@ features = [
|
||||
[patch.crates-io]
|
||||
notify = { git = "https://github.com/zed-industries/notify.git", rev = "bbb9ea5ae52b253e095737847e367c30653a2e96" }
|
||||
notify-types = { git = "https://github.com/zed-industries/notify.git", rev = "bbb9ea5ae52b253e095737847e367c30653a2e96" }
|
||||
tracy-client = { path = "../rust_tracy_client/tracy-client" }
|
||||
windows-capture = { git = "https://github.com/zed-industries/windows-capture.git", rev = "f0d6c1b6691db75461b732f6d5ff56eed002eeb9" }
|
||||
|
||||
# Makes the workspace hack crate refer to the local one, but only when you're building locally
|
||||
|
||||
@@ -37,6 +37,7 @@ log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
paths.workspace = true
|
||||
postage.workspace = true
|
||||
profiling.workspace = true
|
||||
rand.workspace = true
|
||||
regex.workspace = true
|
||||
release_channel.workspace = true
|
||||
|
||||
@@ -150,6 +150,7 @@ pub fn init_settings(cx: &mut App) {
|
||||
ProxySettings::register(cx);
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
pub fn init(client: &Arc<Client>, cx: &mut App) {
|
||||
let client = Arc::downgrade(client);
|
||||
cx.on_action({
|
||||
|
||||
@@ -53,6 +53,7 @@ parse_int.workspace = true
|
||||
paths.workspace = true
|
||||
picker.workspace = true
|
||||
pretty_assertions.workspace = true
|
||||
profiling.workspace = true
|
||||
project.workspace = true
|
||||
rpc.workspace = true
|
||||
schemars.workspace = true
|
||||
|
||||
@@ -114,6 +114,7 @@ actions!(
|
||||
]
|
||||
);
|
||||
|
||||
#[profiling::function]
|
||||
pub fn init(cx: &mut App) {
|
||||
DebuggerSettings::register(cx);
|
||||
workspace::FollowableViewRegistry::register::<DebugSession>(cx);
|
||||
|
||||
@@ -33,6 +33,7 @@ ui.workspace = true
|
||||
util.workspace = true
|
||||
workspace.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
profiling.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
ctor.workspace = true
|
||||
|
||||
@@ -122,6 +122,7 @@ impl FileFinder {
|
||||
);
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn open(
|
||||
workspace: &mut Workspace,
|
||||
separate_history: bool,
|
||||
|
||||
@@ -40,6 +40,8 @@ util.workspace = true
|
||||
uuid.workspace = true
|
||||
futures.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
profiling.workspace = true
|
||||
tracy-client.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions.workspace = true
|
||||
|
||||
@@ -58,6 +58,7 @@ async fn get_messages_impl(working_directory: &Path, shas: &[Oid]) -> Result<Vec
|
||||
}
|
||||
|
||||
/// Parse the output of `git diff --name-status -z`
|
||||
#[profiling::function]
|
||||
pub fn parse_git_diff_name_status(content: &str) -> impl Iterator<Item = (&str, StatusCode)> {
|
||||
let mut parts = content.split('\0');
|
||||
std::iter::from_fn(move || {
|
||||
|
||||
@@ -681,13 +681,15 @@ impl GitRepository for RealGitRepository {
|
||||
.boxed()
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn load_commit(&self, commit: String, cx: AsyncApp) -> BoxFuture<'_, Result<CommitDiff>> {
|
||||
let Some(working_directory) = self.repository.lock().workdir().map(ToOwned::to_owned)
|
||||
else {
|
||||
return future::ready(Err(anyhow!("no working directory"))).boxed();
|
||||
};
|
||||
let git_binary_path = self.any_git_binary_path.clone();
|
||||
cx.background_spawn(async move {
|
||||
cx.background_spawn(tracy_client::fiber!("load_commit", async move {
|
||||
let _zone = tracy_client::span_unchecked!();
|
||||
let show_output = util::command::new_smol_command(&git_binary_path)
|
||||
.current_dir(&working_directory)
|
||||
.args([
|
||||
@@ -797,7 +799,7 @@ impl GitRepository for RealGitRepository {
|
||||
}
|
||||
|
||||
Ok(CommitDiff { files })
|
||||
})
|
||||
}))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ screen-capture = [
|
||||
"scap",
|
||||
]
|
||||
windows-manifest = []
|
||||
profile-with-tracy = ["dep:tracy-client"]
|
||||
|
||||
[lib]
|
||||
path = "src/gpui.rs"
|
||||
@@ -124,6 +125,7 @@ strum.workspace = true
|
||||
sum_tree.workspace = true
|
||||
taffy = "=0.9.0"
|
||||
thiserror.workspace = true
|
||||
tracy-client = { workspace = true, optional = true }
|
||||
util.workspace = true
|
||||
uuid.workspace = true
|
||||
waker-fn = "1.2.0"
|
||||
|
||||
@@ -129,6 +129,7 @@ pub struct Application(Rc<AppCell>);
|
||||
impl Application {
|
||||
/// Builds an app with the given asset source.
|
||||
#[allow(clippy::new_without_default)]
|
||||
#[profiling::function]
|
||||
pub fn new() -> Self {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
log::info!("GPUI was compiled in test mode");
|
||||
@@ -171,6 +172,7 @@ impl Application {
|
||||
|
||||
/// Start the application. The provided callback will be called once the
|
||||
/// app is fully launched.
|
||||
#[profiling::function]
|
||||
pub fn run<F>(self, on_finish_launching: F)
|
||||
where
|
||||
F: 'static + FnOnce(&mut App),
|
||||
|
||||
@@ -53,6 +53,7 @@ impl WindowsDispatcher {
|
||||
let handler = {
|
||||
let mut task_wrapper = Some(runnable);
|
||||
WorkItemHandler::new(move |_| {
|
||||
profiling::register_thread!();
|
||||
task_wrapper.take().unwrap().run();
|
||||
Ok(())
|
||||
})
|
||||
@@ -64,6 +65,7 @@ impl WindowsDispatcher {
|
||||
let handler = {
|
||||
let mut task_wrapper = Some(runnable);
|
||||
TimerElapsedHandler::new(move |_| {
|
||||
profiling::register_thread!();
|
||||
task_wrapper.take().unwrap().run();
|
||||
Ok(())
|
||||
})
|
||||
|
||||
@@ -246,6 +246,7 @@ impl WindowsPlatform {
|
||||
std::thread::Builder::new()
|
||||
.name("VSyncProvider".to_owned())
|
||||
.spawn(move || {
|
||||
profiling::register_thread!("VSyncProvider");
|
||||
let vsync_provider = VSyncProvider::new();
|
||||
loop {
|
||||
vsync_provider.wait_for_vsync();
|
||||
|
||||
@@ -25,6 +25,7 @@ test-support = [
|
||||
"dap/test-support",
|
||||
"dap_adapters/test-support",
|
||||
]
|
||||
profile-with-tracy = ["worktree/profile-with-tracy"]
|
||||
|
||||
[dependencies]
|
||||
aho-corasick.workspace = true
|
||||
@@ -61,6 +62,7 @@ parking_lot.workspace = true
|
||||
paths.workspace = true
|
||||
postage.workspace = true
|
||||
prettier.workspace = true
|
||||
profiling.workspace = true
|
||||
rand.workspace = true
|
||||
regex.workspace = true
|
||||
remote.workspace = true
|
||||
|
||||
@@ -1000,6 +1000,7 @@ impl Project {
|
||||
AllAgentServersSettings::register(cx);
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
pub fn init(client: &Arc<Client>, cx: &mut App) {
|
||||
connection_manager::init(client.clone(), cx);
|
||||
Self::init_settings(cx);
|
||||
|
||||
@@ -36,6 +36,7 @@ serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
smallvec.workspace = true
|
||||
theme.workspace = true
|
||||
profiling.workspace = true
|
||||
rayon.workspace = true
|
||||
ui.workspace = true
|
||||
util.workspace = true
|
||||
@@ -45,6 +46,7 @@ workspace.workspace = true
|
||||
language.workspace = true
|
||||
zed_actions.workspace = true
|
||||
telemetry.workspace = true
|
||||
tracy-client.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -3175,6 +3175,7 @@ impl ProjectPanel {
|
||||
}
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn update_visible_entries(
|
||||
&mut self,
|
||||
new_selected_entry: Option<(WorktreeId, ProjectEntryId)>,
|
||||
@@ -3206,226 +3207,244 @@ impl ProjectPanel {
|
||||
let hide_root = settings.hide_root && visible_worktrees.len() == 1;
|
||||
self.update_visible_entries_task = cx.spawn_in(window, async move |this, cx| {
|
||||
let new_state = cx
|
||||
.background_spawn(async move {
|
||||
for worktree_snapshot in visible_worktrees {
|
||||
let worktree_id = worktree_snapshot.id();
|
||||
.background_spawn(tracy_client::fiber!(
|
||||
"update_visible_entries_task",
|
||||
async move {
|
||||
let _zone = tracy_client::span_unchecked!();
|
||||
for worktree_snapshot in visible_worktrees {
|
||||
let worktree_id = worktree_snapshot.id();
|
||||
|
||||
let expanded_dir_ids = match new_state.expanded_dir_ids.entry(worktree_id) {
|
||||
hash_map::Entry::Occupied(e) => e.into_mut(),
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
// The first time a worktree's root entry becomes available,
|
||||
// mark that root entry as expanded.
|
||||
if let Some(entry) = worktree_snapshot.root_entry() {
|
||||
e.insert(vec![entry.id]).as_slice()
|
||||
let expanded_dir_ids =
|
||||
match new_state.expanded_dir_ids.entry(worktree_id) {
|
||||
hash_map::Entry::Occupied(e) => e.into_mut(),
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
// The first time a worktree's root entry becomes available,
|
||||
// mark that root entry as expanded.
|
||||
if let Some(entry) = worktree_snapshot.root_entry() {
|
||||
e.insert(vec![entry.id]).as_slice()
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut new_entry_parent_id = None;
|
||||
let mut new_entry_kind = EntryKind::Dir;
|
||||
if let Some(edit_state) = &new_state.edit_state
|
||||
&& edit_state.worktree_id == worktree_id
|
||||
&& edit_state.is_new_entry()
|
||||
{
|
||||
new_entry_parent_id = Some(edit_state.entry_id);
|
||||
new_entry_kind = if edit_state.is_dir {
|
||||
EntryKind::Dir
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
EntryKind::File
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let mut new_entry_parent_id = None;
|
||||
let mut new_entry_kind = EntryKind::Dir;
|
||||
if let Some(edit_state) = &new_state.edit_state
|
||||
&& edit_state.worktree_id == worktree_id
|
||||
&& edit_state.is_new_entry()
|
||||
{
|
||||
new_entry_parent_id = Some(edit_state.entry_id);
|
||||
new_entry_kind = if edit_state.is_dir {
|
||||
EntryKind::Dir
|
||||
} else {
|
||||
EntryKind::File
|
||||
};
|
||||
}
|
||||
let mut visible_worktree_entries = Vec::new();
|
||||
let mut entry_iter = GitTraversal::new(
|
||||
&repo_snapshots,
|
||||
worktree_snapshot.entries(true, 0),
|
||||
);
|
||||
let mut auto_folded_ancestors = vec![];
|
||||
let worktree_abs_path = worktree_snapshot.abs_path();
|
||||
while let Some(entry) = entry_iter.entry() {
|
||||
if hide_root && Some(entry.entry) == worktree_snapshot.root_entry()
|
||||
{
|
||||
if new_entry_parent_id == Some(entry.id) {
|
||||
visible_worktree_entries.push(Self::create_new_git_entry(
|
||||
entry.entry,
|
||||
entry.git_summary,
|
||||
new_entry_kind,
|
||||
));
|
||||
new_entry_parent_id = None;
|
||||
}
|
||||
entry_iter.advance();
|
||||
continue;
|
||||
}
|
||||
if auto_collapse_dirs && entry.kind.is_dir() {
|
||||
auto_folded_ancestors.push(entry.id);
|
||||
if !new_state.unfolded_dir_ids.contains(&entry.id)
|
||||
&& let Some(root_path) = worktree_snapshot.root_entry()
|
||||
{
|
||||
let mut child_entries =
|
||||
worktree_snapshot.child_entries(&entry.path);
|
||||
if let Some(child) = child_entries.next()
|
||||
&& entry.path != root_path.path
|
||||
&& child_entries.next().is_none()
|
||||
&& child.kind.is_dir()
|
||||
{
|
||||
entry_iter.advance();
|
||||
|
||||
let mut visible_worktree_entries = Vec::new();
|
||||
let mut entry_iter =
|
||||
GitTraversal::new(&repo_snapshots, worktree_snapshot.entries(true, 0));
|
||||
let mut auto_folded_ancestors = vec![];
|
||||
let worktree_abs_path = worktree_snapshot.abs_path();
|
||||
while let Some(entry) = entry_iter.entry() {
|
||||
if hide_root && Some(entry.entry) == worktree_snapshot.root_entry() {
|
||||
if new_entry_parent_id == Some(entry.id) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let depth = old_ancestors
|
||||
.get(&entry.id)
|
||||
.map(|ancestor| ancestor.current_ancestor_depth)
|
||||
.unwrap_or_default()
|
||||
.min(auto_folded_ancestors.len());
|
||||
if let Some(edit_state) = &mut new_state.edit_state
|
||||
&& edit_state.entry_id == entry.id
|
||||
{
|
||||
edit_state.depth = depth;
|
||||
}
|
||||
let mut ancestors = std::mem::take(&mut auto_folded_ancestors);
|
||||
if ancestors.len() > 1 {
|
||||
ancestors.reverse();
|
||||
new_state.ancestors.insert(
|
||||
entry.id,
|
||||
FoldedAncestors {
|
||||
current_ancestor_depth: depth,
|
||||
ancestors,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
auto_folded_ancestors.clear();
|
||||
if !hide_gitignore || !entry.is_ignored {
|
||||
visible_worktree_entries.push(entry.to_owned());
|
||||
}
|
||||
let precedes_new_entry =
|
||||
if let Some(new_entry_id) = new_entry_parent_id {
|
||||
entry.id == new_entry_id || {
|
||||
new_state.ancestors.get(&entry.id).is_some_and(
|
||||
|entries| entries.ancestors.contains(&new_entry_id),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if precedes_new_entry && (!hide_gitignore || !entry.is_ignored) {
|
||||
visible_worktree_entries.push(Self::create_new_git_entry(
|
||||
entry.entry,
|
||||
entry.git_summary,
|
||||
new_entry_kind,
|
||||
));
|
||||
new_entry_parent_id = None;
|
||||
}
|
||||
entry_iter.advance();
|
||||
continue;
|
||||
}
|
||||
if auto_collapse_dirs && entry.kind.is_dir() {
|
||||
auto_folded_ancestors.push(entry.id);
|
||||
if !new_state.unfolded_dir_ids.contains(&entry.id)
|
||||
&& let Some(root_path) = worktree_snapshot.root_entry()
|
||||
{
|
||||
let mut child_entries =
|
||||
worktree_snapshot.child_entries(&entry.path);
|
||||
if let Some(child) = child_entries.next()
|
||||
&& entry.path != root_path.path
|
||||
&& child_entries.next().is_none()
|
||||
&& child.kind.is_dir()
|
||||
{
|
||||
entry_iter.advance();
|
||||
|
||||
let (depth, chars) = if Some(entry.entry)
|
||||
== worktree_snapshot.root_entry()
|
||||
{
|
||||
let Some(path_name) = worktree_abs_path.file_name() else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let depth = old_ancestors
|
||||
.get(&entry.id)
|
||||
.map(|ancestor| ancestor.current_ancestor_depth)
|
||||
.unwrap_or_default()
|
||||
.min(auto_folded_ancestors.len());
|
||||
if let Some(edit_state) = &mut new_state.edit_state
|
||||
&& edit_state.entry_id == entry.id
|
||||
{
|
||||
edit_state.depth = depth;
|
||||
}
|
||||
let mut ancestors = std::mem::take(&mut auto_folded_ancestors);
|
||||
if ancestors.len() > 1 {
|
||||
ancestors.reverse();
|
||||
new_state.ancestors.insert(
|
||||
entry.id,
|
||||
FoldedAncestors {
|
||||
current_ancestor_depth: depth,
|
||||
ancestors,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
auto_folded_ancestors.clear();
|
||||
if !hide_gitignore || !entry.is_ignored {
|
||||
visible_worktree_entries.push(entry.to_owned());
|
||||
}
|
||||
let precedes_new_entry = if let Some(new_entry_id) = new_entry_parent_id
|
||||
{
|
||||
entry.id == new_entry_id || {
|
||||
new_state.ancestors.get(&entry.id).is_some_and(|entries| {
|
||||
entries.ancestors.contains(&new_entry_id)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if precedes_new_entry && (!hide_gitignore || !entry.is_ignored) {
|
||||
visible_worktree_entries.push(Self::create_new_git_entry(
|
||||
entry.entry,
|
||||
entry.git_summary,
|
||||
new_entry_kind,
|
||||
));
|
||||
}
|
||||
|
||||
let (depth, chars) = if Some(entry.entry)
|
||||
== worktree_snapshot.root_entry()
|
||||
{
|
||||
let Some(path_name) = worktree_abs_path.file_name() else {
|
||||
continue;
|
||||
};
|
||||
let depth = 0;
|
||||
(depth, path_name.to_string_lossy().chars().count())
|
||||
} else if entry.is_file() {
|
||||
let Some(path_name) = entry
|
||||
.path
|
||||
.file_name()
|
||||
.with_context(|| {
|
||||
format!("Non-root entry has no file name: {entry:?}")
|
||||
})
|
||||
.log_err()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let depth = entry.path.ancestors().count() - 1;
|
||||
(depth, path_name.chars().count())
|
||||
} else {
|
||||
let path = new_state
|
||||
.ancestors
|
||||
.get(&entry.id)
|
||||
.and_then(|ancestors| {
|
||||
let outermost_ancestor = ancestors.ancestors.last()?;
|
||||
let root_folded_entry = worktree_snapshot
|
||||
.entry_for_id(*outermost_ancestor)?
|
||||
.path
|
||||
.as_ref();
|
||||
entry.path.strip_prefix(root_folded_entry).ok().and_then(
|
||||
|suffix| {
|
||||
Some(
|
||||
RelPath::unix(root_folded_entry.file_name()?)
|
||||
};
|
||||
let depth = 0;
|
||||
(depth, path_name.to_string_lossy().chars().count())
|
||||
} else if entry.is_file() {
|
||||
let Some(path_name) = entry
|
||||
.path
|
||||
.file_name()
|
||||
.with_context(|| {
|
||||
format!("Non-root entry has no file name: {entry:?}")
|
||||
})
|
||||
.log_err()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let depth = entry.path.ancestors().count() - 1;
|
||||
(depth, path_name.chars().count())
|
||||
} else {
|
||||
let path = new_state
|
||||
.ancestors
|
||||
.get(&entry.id)
|
||||
.and_then(|ancestors| {
|
||||
let outermost_ancestor = ancestors.ancestors.last()?;
|
||||
let root_folded_entry = worktree_snapshot
|
||||
.entry_for_id(*outermost_ancestor)?
|
||||
.path
|
||||
.as_ref();
|
||||
entry
|
||||
.path
|
||||
.strip_prefix(root_folded_entry)
|
||||
.ok()
|
||||
.and_then(|suffix| {
|
||||
Some(
|
||||
RelPath::unix(
|
||||
root_folded_entry.file_name()?,
|
||||
)
|
||||
.unwrap()
|
||||
.join(suffix),
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
.or_else(|| {
|
||||
entry.path.file_name().map(|file_name| {
|
||||
RelPath::unix(file_name).unwrap().into()
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| entry.path.clone());
|
||||
let depth = path.components().count();
|
||||
(depth, path.as_unix_str().chars().count())
|
||||
};
|
||||
let width_estimate =
|
||||
item_width_estimate(depth, chars, entry.canonical_path.is_some());
|
||||
.or_else(|| {
|
||||
entry.path.file_name().map(|file_name| {
|
||||
RelPath::unix(file_name).unwrap().into()
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| entry.path.clone());
|
||||
let depth = path.components().count();
|
||||
(depth, path.as_unix_str().chars().count())
|
||||
};
|
||||
let width_estimate = item_width_estimate(
|
||||
depth,
|
||||
chars,
|
||||
entry.canonical_path.is_some(),
|
||||
);
|
||||
|
||||
match max_width_item.as_mut() {
|
||||
Some((id, worktree_id, width)) => {
|
||||
if *width < width_estimate {
|
||||
*id = entry.id;
|
||||
*worktree_id = worktree_snapshot.id();
|
||||
*width = width_estimate;
|
||||
match max_width_item.as_mut() {
|
||||
Some((id, worktree_id, width)) => {
|
||||
if *width < width_estimate {
|
||||
*id = entry.id;
|
||||
*worktree_id = worktree_snapshot.id();
|
||||
*width = width_estimate;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
max_width_item =
|
||||
Some((entry.id, worktree_snapshot.id(), width_estimate))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
max_width_item =
|
||||
Some((entry.id, worktree_snapshot.id(), width_estimate))
|
||||
|
||||
if expanded_dir_ids.binary_search(&entry.id).is_err()
|
||||
&& entry_iter.advance_to_sibling()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entry_iter.advance();
|
||||
}
|
||||
|
||||
if expanded_dir_ids.binary_search(&entry.id).is_err()
|
||||
&& entry_iter.advance_to_sibling()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entry_iter.advance();
|
||||
par_sort_worktree_entries(&mut visible_worktree_entries);
|
||||
new_state.visible_entries.push(VisibleEntriesForWorktree {
|
||||
worktree_id,
|
||||
entries: visible_worktree_entries,
|
||||
index: OnceCell::new(),
|
||||
})
|
||||
}
|
||||
|
||||
par_sort_worktree_entries(&mut visible_worktree_entries);
|
||||
new_state.visible_entries.push(VisibleEntriesForWorktree {
|
||||
worktree_id,
|
||||
entries: visible_worktree_entries,
|
||||
index: OnceCell::new(),
|
||||
})
|
||||
}
|
||||
if let Some((project_entry_id, worktree_id, _)) = max_width_item {
|
||||
let mut visited_worktrees_length = 0;
|
||||
let index = new_state
|
||||
.visible_entries
|
||||
.iter()
|
||||
.find_map(|visible_entries| {
|
||||
if worktree_id == visible_entries.worktree_id {
|
||||
visible_entries
|
||||
.entries
|
||||
.iter()
|
||||
.position(|entry| entry.id == project_entry_id)
|
||||
} else {
|
||||
visited_worktrees_length += visible_entries.entries.len();
|
||||
None
|
||||
}
|
||||
if let Some((project_entry_id, worktree_id, _)) = max_width_item {
|
||||
let mut visited_worktrees_length = 0;
|
||||
let index =
|
||||
new_state
|
||||
.visible_entries
|
||||
.iter()
|
||||
.find_map(|visible_entries| {
|
||||
if worktree_id == visible_entries.worktree_id {
|
||||
visible_entries
|
||||
.entries
|
||||
.iter()
|
||||
.position(|entry| entry.id == project_entry_id)
|
||||
} else {
|
||||
visited_worktrees_length +=
|
||||
visible_entries.entries.len();
|
||||
None
|
||||
}
|
||||
});
|
||||
if let Some(index) = index {
|
||||
new_state.max_width_item_index =
|
||||
Some(visited_worktrees_length + index);
|
||||
}
|
||||
}
|
||||
if let Some((worktree_id, entry_id)) = new_selected_entry {
|
||||
new_state.selection = Some(SelectedEntry {
|
||||
worktree_id,
|
||||
entry_id,
|
||||
});
|
||||
if let Some(index) = index {
|
||||
new_state.max_width_item_index = Some(visited_worktrees_length + index);
|
||||
}
|
||||
new_state
|
||||
}
|
||||
if let Some((worktree_id, entry_id)) = new_selected_entry {
|
||||
new_state.selection = Some(SelectedEntry {
|
||||
worktree_id,
|
||||
entry_id,
|
||||
});
|
||||
}
|
||||
new_state
|
||||
})
|
||||
))
|
||||
.await;
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
this.state = new_state;
|
||||
@@ -4227,6 +4246,7 @@ impl ProjectPanel {
|
||||
false
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn render_entry(
|
||||
&self,
|
||||
entry_id: ProjectEntryId,
|
||||
@@ -5152,6 +5172,7 @@ impl ProjectPanel {
|
||||
None
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn render_sticky_entries(
|
||||
&self,
|
||||
child: StickyProjectPanelCandidate,
|
||||
@@ -5288,6 +5309,7 @@ fn item_width_estimate(depth: usize, item_text_chars: usize, is_symlink: bool) -
|
||||
}
|
||||
|
||||
impl Render for ProjectPanel {
|
||||
#[profiling::function]
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let has_worktree = !self.state.visible_entries.is_empty();
|
||||
let project = self.project.read(cx);
|
||||
@@ -6041,6 +6063,7 @@ pub fn sort_worktree_entries(entries: &mut [impl AsRef<Entry>]) {
|
||||
entries.sort_by(|lhs, rhs| cmp(lhs, rhs));
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
pub fn par_sort_worktree_entries(entries: &mut Vec<GitEntry>) {
|
||||
entries.par_sort_by(|lhs, rhs| cmp(lhs, rhs));
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ gpui.workspace = true
|
||||
inventory.workspace = true
|
||||
log.workspace = true
|
||||
paths.workspace = true
|
||||
profiling.workspace = true
|
||||
release_channel.workspace = true
|
||||
rust-embed.workspace = true
|
||||
schemars.workspace = true
|
||||
|
||||
@@ -77,6 +77,7 @@ impl fmt::Display for WorktreeId {
|
||||
#[exclude = "*.DS_Store"]
|
||||
pub struct SettingsAssets;
|
||||
|
||||
#[profiling::function]
|
||||
pub fn init(cx: &mut App) {
|
||||
let settings = SettingsStore::new(cx, &default_settings());
|
||||
cx.set_global(settings);
|
||||
|
||||
@@ -21,6 +21,7 @@ test-support = [
|
||||
"text/test-support",
|
||||
"util/test-support",
|
||||
]
|
||||
profile-with-tracy = ["dep:tracy-client"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
@@ -37,6 +38,7 @@ log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
paths.workspace = true
|
||||
postage.workspace = true
|
||||
profiling.workspace = true
|
||||
rpc = { workspace = true, features = ["gpui"] }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
@@ -45,6 +47,7 @@ smallvec.workspace = true
|
||||
smol.workspace = true
|
||||
sum_tree.workspace = true
|
||||
text.workspace = true
|
||||
tracy-client = { workspace = true, optional = true }
|
||||
util.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
|
||||
|
||||
@@ -3083,18 +3083,25 @@ impl language::LocalFile for File {
|
||||
self.worktree.read(cx).absolutize(&self.path)
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn load(&self, cx: &App) -> Task<Result<String>> {
|
||||
let worktree = self.worktree.read(cx).as_local().unwrap();
|
||||
let abs_path = worktree.absolutize(&self.path);
|
||||
let fs = worktree.fs.clone();
|
||||
cx.background_spawn(async move { fs.load(&abs_path).await })
|
||||
|
||||
cx.background_spawn(tracy_client::fiber!("File::load", async move {
|
||||
fs.load(&abs_path).await
|
||||
}))
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn load_bytes(&self, cx: &App) -> Task<Result<Vec<u8>>> {
|
||||
let worktree = self.worktree.read(cx).as_local().unwrap();
|
||||
let abs_path = worktree.absolutize(&self.path);
|
||||
let fs = worktree.fs.clone();
|
||||
cx.background_spawn(async move { fs.load_bytes(&abs_path).await })
|
||||
cx.background_spawn(tracy_client::fiber!("File::load_bytes", async move {
|
||||
fs.load_bytes(&abs_path).await
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ path = "src/zed-main.rs"
|
||||
name = "zed"
|
||||
path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
profile-with-tracy = ["dep:tracy-client", "profiling/profile-with-tracy", "gpui/profile-with-tracy", "project/profile-with-tracy"]
|
||||
profile-with-tracy-memory = ["profile-with-tracy"]
|
||||
|
||||
[dependencies]
|
||||
acp_tools.workspace = true
|
||||
activity_indicator.workspace = true
|
||||
@@ -146,6 +150,7 @@ theme_selector.workspace = true
|
||||
time.workspace = true
|
||||
title_bar.workspace = true
|
||||
toolchain_selector.workspace = true
|
||||
tracy-client = { workspace = true, optional = true }
|
||||
ui.workspace = true
|
||||
ui_input.workspace = true
|
||||
ui_prompt.workspace = true
|
||||
|
||||
@@ -59,10 +59,20 @@ use zed::{
|
||||
|
||||
use crate::zed::OpenRequestKind;
|
||||
|
||||
#[cfg(feature = "mimalloc")]
|
||||
#[cfg(all(feature = "mimalloc", not(features = "profile-with-tracy-memory")))]
|
||||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
#[cfg(all(feature = "mimalloc", features = "profile-with-tracy-memory"))]
|
||||
#[global_allocator]
|
||||
static GLOBAL: tracy_client::ProfiledAllocator<mimalloc::MiMalloc> =
|
||||
tracy_client::ProfiledAllocator::new(mimalloc::MiMalloc, 100);
|
||||
|
||||
#[cfg(all(not(feature = "mimalloc"), feature = "profile-with-tracy-memory"))]
|
||||
#[global_allocator]
|
||||
static GLOBAL: tracy_client::ProfiledAllocator<std::alloc::System> =
|
||||
tracy_client::ProfiledAllocator::new(std::alloc::System, 100);
|
||||
|
||||
fn files_not_created_on_launch(errors: HashMap<io::ErrorKind, Vec<&Path>>) {
|
||||
let message = "Zed failed to launch";
|
||||
let error_details = errors
|
||||
@@ -164,6 +174,7 @@ fn fail_to_open_window(e: anyhow::Error, _cx: &mut App) {
|
||||
}
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
pub fn main() {
|
||||
#[cfg(unix)]
|
||||
util::prevent_root_execution();
|
||||
@@ -371,6 +382,8 @@ pub fn main() {
|
||||
});
|
||||
|
||||
app.run(move |cx| {
|
||||
profiling::scope!("app_run");
|
||||
|
||||
menu::init();
|
||||
zed_actions::init();
|
||||
|
||||
@@ -1304,6 +1317,7 @@ fn parse_url_arg(arg: &str, cx: &App) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn load_embedded_fonts(cx: &App) {
|
||||
let asset_source = cx.asset_source();
|
||||
let font_paths = asset_source.list("fonts").unwrap();
|
||||
@@ -1386,10 +1400,12 @@ fn eager_load_active_theme_and_icon_theme(fs: Arc<dyn Fs>, cx: &App) {
|
||||
}
|
||||
|
||||
/// Spawns a background task to load the user themes from the themes directory.
|
||||
#[profiling::function]
|
||||
fn load_user_themes_in_background(fs: Arc<dyn fs::Fs>, cx: &mut App) {
|
||||
cx.spawn({
|
||||
let fs = fs.clone();
|
||||
async move |cx| {
|
||||
profiling::scope!("load_user_themes_in_background");
|
||||
if let Some(theme_registry) = cx.update(|cx| ThemeRegistry::global(cx)).log_err() {
|
||||
let themes_dir = paths::themes_dir().as_ref();
|
||||
match fs
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
pub fn main() {
|
||||
#[cfg(feature = "profile-with-tracy")]
|
||||
{
|
||||
tracy_client::Client::start();
|
||||
}
|
||||
|
||||
// separated out so that the file containing the main function can be imported by other crates,
|
||||
// while having all gpui resources that are registered in main (primarily actions) initialized
|
||||
zed::main();
|
||||
|
||||
@@ -137,6 +137,7 @@ actions!(
|
||||
]
|
||||
);
|
||||
|
||||
#[profiling::function]
|
||||
pub fn init(cx: &mut App) {
|
||||
#[cfg(target_os = "macos")]
|
||||
cx.on_action(|_: &Hide, cx| cx.hide());
|
||||
@@ -1222,6 +1223,7 @@ fn open_log_file(workspace: &mut Workspace, window: &mut Window, cx: &mut Contex
|
||||
.detach();
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
pub fn handle_settings_file_changes(
|
||||
mut user_settings_file_rx: mpsc::UnboundedReceiver<String>,
|
||||
mut global_settings_file_rx: mpsc::UnboundedReceiver<String>,
|
||||
@@ -1329,6 +1331,7 @@ pub fn handle_settings_file_changes(
|
||||
.detach();
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
pub fn handle_keymap_file_changes(
|
||||
mut user_keymap_file_rx: mpsc::UnboundedReceiver<String>,
|
||||
cx: &mut App,
|
||||
|
||||
Reference in New Issue
Block a user