fix(lsp): included ruff-only roots for venv lookup

Extended Python local-bin gating to Ruff-only root marker files so Windows virtualenv Scripts launchers are found before PATH fallback.

Fixes #3916
This commit is contained in:
roboomp
2026-06-30 20:21:10 +00:00
parent 15c889941c
commit ae0ae68e14
2 changed files with 29 additions and 1 deletions
+1 -1
View File
@@ -209,7 +209,7 @@ export function hasRootMarkers(cwd: string, markers: string[]): boolean {
* Local bin directories to check before $PATH, ordered by priority.
* Each entry maps a root marker to the bin directory to check.
*/
const PYTHON_ROOT_MARKERS = ["pyproject.toml", "requirements.txt", "setup.py", "Pipfile"];
const PYTHON_ROOT_MARKERS = ["pyproject.toml", "requirements.txt", "setup.py", "Pipfile", "ruff.toml", ".ruff.toml"];
const LOCAL_BIN_PATHS: Array<{ markers: string[]; binDir: string }> = [
// Node.js - check node_modules/.bin/
@@ -1101,6 +1101,34 @@ describe("lsp regressions", () => {
}
});
it("detects Ruff in Windows virtualenv Scripts directories for Ruff-only roots", async () => {
const originalPlatform = process.platform;
Object.defineProperty(process, "platform", { value: "win32", configurable: true, writable: true });
const whichSpy = vi.spyOn(Bun, "which").mockReturnValue(null);
try {
for (const marker of ["ruff.toml", ".ruff.toml"] as const) {
const tempDir = TempDir.createSync("@omp-lsp-win32-ruff-marker-");
try {
await Bun.write(path.join(tempDir.path(), marker), "");
const scriptsDir = path.join(tempDir.path(), ".venv", "Scripts");
await fs.promises.mkdir(scriptsDir, { recursive: true });
const localRuff = path.join(scriptsDir, "ruff.exe");
await Bun.write(localRuff, "");
const config = loadConfig(tempDir.path());
expect(config.servers.ruff?.resolvedCommand).toBe(localRuff);
} finally {
tempDir.removeSync();
}
}
expect(whichSpy).not.toHaveBeenCalledWith("ruff");
} finally {
Object.defineProperty(process, "platform", { value: originalPlatform, configurable: true, writable: true });
vi.restoreAllMocks();
}
});
it("detects tlaplus files for LSP startup and language ids", async () => {
const tempDir = TempDir.createSync("@omp-lsp-tlaplus-");
const specPath = path.join(tempDir.path(), "Spec.tla");