From 0d1eecc388f552017763ae1719799f4113e72851 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 5 Jun 2026 21:35:47 +0800 Subject: [PATCH] Keep virtualenvs out of project picker results (#1356) * Fix project picker virtualenv suggestions * Ignore more virtualenv names in project picker --- .../src/utils/directory-suggestions.test.ts | 31 +++++++++++++++++++ .../server/src/utils/directory-suggestions.ts | 15 ++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/packages/server/src/utils/directory-suggestions.test.ts b/packages/server/src/utils/directory-suggestions.test.ts index 1fec0afc9..d18cab97f 100644 --- a/packages/server/src/utils/directory-suggestions.test.ts +++ b/packages/server/src/utils/directory-suggestions.test.ts @@ -93,6 +93,37 @@ describe("searchHomeDirectories", () => { expect(exactIndex).toBeLessThan(prefixIndex); }); + it("does not let Python virtual environments crowd out top-level project matches", async () => { + const projectPath = path.join(homeDir, "django-po-merge"); + mkdirSync(projectPath, { recursive: true }); + const dependencyPaths = ["venv", "env", "virtualenv"].map((environmentDirectoryName) => + path.join( + homeDir, + `${environmentDirectoryName}-project`, + environmentDirectoryName, + "Lib", + "site-packages", + "django", + ), + ); + for (const dependencyPath of dependencyPaths) { + mkdirSync(dependencyPath, { recursive: true }); + } + + const results = await searchHomeDirectories({ + homeDir, + query: "~/django", + limit: 30, + }); + + const resolvedResults = results.map((result) => realpathSync.native(result)); + const projectIndex = resolvedResults.indexOf(realpathSync.native(projectPath)); + expect(projectIndex).toBeGreaterThanOrEqual(0); + for (const dependencyPath of dependencyPaths) { + expect(resolvedResults).not.toContain(realpathSync.native(dependencyPath)); + } + }); + it("prioritizes partial matches that appear earlier in the path", async () => { const earlierPath = path.join(homeDir, "farofoo"); const laterPath = path.join(homeDir, "x", "y", "farofoo"); diff --git a/packages/server/src/utils/directory-suggestions.ts b/packages/server/src/utils/directory-suggestions.ts index b889b8f08..c244535a2 100644 --- a/packages/server/src/utils/directory-suggestions.ts +++ b/packages/server/src/utils/directory-suggestions.ts @@ -78,8 +78,11 @@ const NO_SEGMENT_INDEX = Number.MAX_SAFE_INTEGER; const NO_MATCH_OFFSET = Number.MAX_SAFE_INTEGER; const NO_FUZZY_SCORE = Number.MAX_SAFE_INTEGER; const NO_WORKSPACE_MATCH_TIER = 5; -const WORKSPACE_IGNORED_DIRECTORY_NAMES = new Set([ +const IGNORED_SUGGESTION_DIRECTORY_NAMES = new Set([ "node_modules", + "venv", + "env", + "virtualenv", "dist", "build", "target", @@ -824,7 +827,9 @@ async function listChildDirectories(input: { ); const candidates = dirents.filter( (dirent) => - !isHiddenDirectoryName(dirent.name) && (dirent.isDirectory() || dirent.isSymbolicLink()), + !isHiddenDirectoryName(dirent.name) && + !isIgnoredSuggestionDirectoryName(dirent.name) && + (dirent.isDirectory() || dirent.isSymbolicLink()), ); const resolved = await Promise.all( candidates.map(async (dirent) => { @@ -864,7 +869,7 @@ async function listWorkspaceChildEntries(input: { ); const candidates = dirents.filter( (dirent) => - !isHiddenDirectoryName(dirent.name) && !isIgnoredWorkspaceDirectoryName(dirent.name), + !isHiddenDirectoryName(dirent.name) && !isIgnoredSuggestionDirectoryName(dirent.name), ); const resolved = await Promise.all( candidates.map(async (dirent) => { @@ -955,8 +960,8 @@ function isHiddenDirectoryName(name: string): boolean { return name.startsWith("."); } -function isIgnoredWorkspaceDirectoryName(name: string): boolean { - return WORKSPACE_IGNORED_DIRECTORY_NAMES.has(name); +function isIgnoredSuggestionDirectoryName(name: string): boolean { + return IGNORED_SUGGESTION_DIRECTORY_NAMES.has(name); } function setDirectoryListCache(cacheKey: string, entry: DirectoryListCacheEntry): void {