From bfa2407e98ee1343caeefd02b4b69043509baa8c Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 25 Oct 2026 07:11:44 -0400 Subject: [PATCH] [ty] Skip script discovery when uv script environments are disabled (#29697) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary With two files open in Home Assistant, skipping script discovery reduced the language server’s mean time to first diagnostics from 465 ms to 354 ms on Linux (24%). Previously, ty indexed 10,768 files looking for PEP 723 scripts, even though uv integration was off by default and ty had no script environments to prepare. We now scan for scripts to prepare uv environments at startup and on reload only when uv script environments are enabled (`TY_UV=scripts` or `TY_UV=1`). With uv off, ty still reads an open script’s inline settings. The benchmark client doesn’t register file watchers. With dynamic file watching enabled, ty still scans for script-specific import paths; five paired runs showed no startup gain in that configuration. --- crates/ty/src/lib.rs | 4 ++-- crates/ty_project/src/lib.rs | 10 ++++++++++ crates/ty_project/src/uv.rs | 2 +- crates/ty_server/src/session.rs | 4 ++-- .../e2e/snapshots/e2e__commands__debug_command.snap | 5 ----- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/crates/ty/src/lib.rs b/crates/ty/src/lib.rs index 487a8c445f..d194f07e95 100644 --- a/crates/ty/src/lib.rs +++ b/crates/ty/src/lib.rs @@ -351,7 +351,7 @@ impl MainLoop { let (check_sender, check_receiver) = crossbeam_channel::bounded(1); // Initialize the uv environment for all scripts - let scripts: Vec<_> = db.project().script_files(db).iter().collect(); + let scripts = db.project().scripts_to_synchronize(db); self.synchronize_scripts(db, &scripts); request_check(&check_sender); @@ -512,7 +512,7 @@ impl MainLoop { files_changed: true, } ) { - let scripts: Vec<_> = db.project().script_files(db).iter().collect(); + let scripts = db.project().scripts_to_synchronize(db); self.synchronize_scripts(db, &scripts); } } diff --git a/crates/ty_project/src/lib.rs b/crates/ty_project/src/lib.rs index 513bfde3b5..8876cb2909 100644 --- a/crates/ty_project/src/lib.rs +++ b/crates/ty_project/src/lib.rs @@ -826,6 +826,16 @@ impl Project { } } + /// Returns the scripts whose uv environments need preparing at startup or after a reload. + pub fn scripts_to_synchronize(self, db: &dyn Db) -> Vec { + // Discovering scripts reads every project file. Keep the index lazy when + // no environment synchronization will be requested. + if !self.metadata(db).use_uv().script_environments_enabled() { + return Vec::new(); + } + self.script_files(db).iter().collect() + } + fn reload_files(self, db: &mut dyn Db) { tracing::debug!("Reloading files for project `{}`", self.name(db)); diff --git a/crates/ty_project/src/uv.rs b/crates/ty_project/src/uv.rs index 12a7c71837..cf5c5cec38 100644 --- a/crates/ty_project/src/uv.rs +++ b/crates/ty_project/src/uv.rs @@ -59,7 +59,7 @@ impl UseUv { matches!(self, Self::On) } - const fn script_environments_enabled(self) -> bool { + pub(super) const fn script_environments_enabled(self) -> bool { matches!(self, Self::Scripts | Self::On) } } diff --git a/crates/ty_server/src/session.rs b/crates/ty_server/src/session.rs index ba9fcd2f42..0701cabb9b 100644 --- a/crates/ty_server/src/session.rs +++ b/crates/ty_server/src/session.rs @@ -302,7 +302,7 @@ impl Session { files_changed: true, }) ) { - let scripts: Vec<_> = db.project().script_files(db).iter().collect(); + let scripts = db.project().scripts_to_synchronize(db); Self::synchronize_closed_scripts( db, &scripts, @@ -838,7 +838,7 @@ impl Session { let untracked = previous .map(|state| state.untracked_files_with_pushed_diagnostics) .unwrap_or_default(); - let scripts: Vec<_> = db.project().script_files(&db).iter().collect(); + let scripts = db.project().scripts_to_synchronize(&db); Self::synchronize_closed_scripts( &mut db, &scripts, diff --git a/crates/ty_server/tests/e2e/snapshots/e2e__commands__debug_command.snap b/crates/ty_server/tests/e2e/snapshots/e2e__commands__debug_command.snap index c1c1f19d1f..17489c5f94 100644 --- a/crates/ty_server/tests/e2e/snapshots/e2e__commands__debug_command.snap +++ b/crates/ty_server/tests/e2e/snapshots/e2e__commands__debug_command.snap @@ -184,7 +184,6 @@ Settings: Settings { Memory report: =======SALSA STRUCTS======= `FileRoot` metadata=[X.XXMB] fields=[X.XXMB] count=1 -`File` metadata=[X.XXMB] fields=[X.XXMB] count=1 `ModuleResolveModeIngredient` metadata=[X.XXMB] fields=[X.XXMB] count=1 `Program` metadata=[X.XXMB] fields=[X.XXMB] count=1 `Project` metadata=[X.XXMB] fields=[X.XXMB] count=1 @@ -194,12 +193,8 @@ Memory report: metadata=[X.XXMB] fields=[X.XXMB] count=1 `dynamic_resolution_paths -> alloc::boxed::Box<[ty_module_resolver::path::SearchPath]>` metadata=[X.XXMB] fields=[X.XXMB] count=1 -`script_tag -> core::option::Option>` - metadata=[X.XXMB] fields=[X.XXMB] count=1 `site_packages_editables -> alloc::boxed::Box<[ty_module_resolver::resolve::SitePackagesEditables]>` metadata=[X.XXMB] fields=[X.XXMB] count=1 -`source_text -> ruff_db::source::SourceText` - metadata=[X.XXMB] fields=[X.XXMB] count=1 =======SALSA SUMMARY======= TOTAL MEMORY USAGE: [X.XXMB] struct metadata = [X.XXMB]