Skip to content

Commit fe554b4

Browse files
✨ Support multiroot workspaces (#23)
1 parent 014c63a commit fe554b4

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

src/appDiscovery.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,18 @@ async function parsePyprojectForEntryPoint(
6262
return null
6363
}
6464

65-
// Parse "my_app.main:app" format (variable name after : is optional)
65+
// Parse "my_app.main:app" or "api.py:app" format (variable name after : is optional)
6666
const colonIndex = entrypointValue.indexOf(":")
6767
const modulePath =
6868
colonIndex === -1 ? entrypointValue : entrypointValue.slice(0, colonIndex)
6969
const variableName =
7070
colonIndex === -1 ? undefined : entrypointValue.slice(colonIndex + 1)
7171

72-
// Convert module path to file path: my_app.main -> my_app/main.py
73-
const relativePath = `${modulePath.replace(/\./g, "/")}.py`
72+
// Handle both module format (api.module) and file format (api.py)
73+
const relativePath =
74+
modulePath.endsWith(".py") && !modulePath.includes("/")
75+
? modulePath // Simple file path: api.py -> api.py
76+
: `${modulePath.replace(/\./g, "/")}.py` // Module path: my_app.main -> my_app/main.py
7477
const fullUri = vscode.Uri.joinPath(folderUri, relativePath)
7578

7679
return (await vscodeFileSystem.exists(fullUri.toString()))

src/extension.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { discoverFastAPIApps } from "./appDiscovery"
77
import { clearImportCache } from "./core/importResolver"
88
import { Parser } from "./core/parser"
99
import { stripLeadingDynamicSegments } from "./core/pathUtils"
10-
import type { SourceLocation } from "./core/types"
10+
import type { AppDefinition, SourceLocation } from "./core/types"
1111
import {
1212
type EndpointTreeItem,
1313
EndpointTreeProvider,
@@ -63,7 +63,31 @@ export async function activate(context: vscode.ExtensionContext) {
6363

6464
// Discover apps and create providers
6565
const apps = await discoverFastAPIApps(parserService)
66-
const endpointProvider = new EndpointTreeProvider(apps)
66+
67+
// Create grouping function that groups by workspace folder if there are multiple folders
68+
const groupApps = (apps: AppDefinition[]) => {
69+
const workspaceFolders = vscode.workspace.workspaceFolders
70+
if (!workspaceFolders || workspaceFolders.length <= 1) {
71+
// Single workspace folder: show apps directly at root
72+
return apps.map((app) => ({ type: "app" as const, app }))
73+
}
74+
75+
// Multi-root workspace: group by workspace folder
76+
const grouped = apps.reduce((acc, app) => {
77+
const existing = acc.get(app.workspaceFolder) ?? []
78+
acc.set(app.workspaceFolder, [...existing, app])
79+
return acc
80+
}, new Map<string, AppDefinition[]>())
81+
82+
// Create workspace items with folder names
83+
return Array.from(grouped.entries()).map(([folderPath, apps]) => {
84+
const folder = workspaceFolders.find((f) => f.uri.fsPath === folderPath)
85+
const label = folder?.name ?? folderPath.split("/").pop() ?? folderPath
86+
return { type: "workspace" as const, label, apps }
87+
})
88+
}
89+
90+
const endpointProvider = new EndpointTreeProvider(apps, groupApps)
6791
const codeLensProvider = new TestCodeLensProvider(parserService, apps)
6892

6993
// File watcher for auto-refresh
@@ -73,7 +97,7 @@ export async function activate(context: vscode.ExtensionContext) {
7397
refreshTimeout = setTimeout(async () => {
7498
if (!parserService) return
7599
const newApps = await discoverFastAPIApps(parserService)
76-
endpointProvider.setApps(newApps)
100+
endpointProvider.setApps(newApps, groupApps)
77101
codeLensProvider.setApps(newApps)
78102
}, 300)
79103
}

0 commit comments

Comments
 (0)