fix(tui): scope Zed editor context to containing workspaces (#25211)

This commit is contained in:
Kit Langton 2026-04-30 22:33:39 -04:00 committed by GitHub
parent 5ba68a28c0
commit 4c70ea28d2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 96 additions and 5 deletions

View file

@ -189,13 +189,20 @@ export function resolveZedDbPath() {
path.join(os.homedir(), ".local", "share", "zed", "db", "0-stable", "db.sqlite"),
].filter((item): item is string => Boolean(item))
return candidates.find((item) => Filesystem.stat(item)?.isFile())
return candidates.find((item) => isFile(item))
}
function isFile(item: string) {
try {
return Filesystem.stat(item)?.isFile() === true
} catch {
return false
}
}
function scoreZedWorkspace(workspacePaths: string | null, cwd: string) {
return zedWorkspacePaths(workspacePaths).reduce((score, item) => {
if (pathContains(item, cwd)) return Math.max(score, 2)
if (pathContains(cwd, item)) return Math.max(score, 1)
if (pathContains(item, cwd)) return Math.max(score, path.resolve(item).length)
return score
}, 0)
}

View file

@ -1,7 +1,9 @@
import { Database } from "bun:sqlite"
import { mkdir, symlink } from "node:fs/promises"
import os from "node:os"
import path from "node:path"
import { expect, test } from "bun:test"
import { offsetToPosition, resolveZedSelection } from "../../../src/cli/cmd/tui/context/editor-zed"
import { expect, spyOn, test } from "bun:test"
import { offsetToPosition, resolveZedDbPath, resolveZedSelection } from "../../../src/cli/cmd/tui/context/editor-zed"
import { tmpdir } from "../../fixture/fixture"
type ZedFixtureOptions = {
@ -66,6 +68,23 @@ test("offsetToPosition converts Zed offsets to 1-based editor positions", () =>
})
})
test("resolveZedDbPath skips candidates that cannot be stated", async () => {
await using tmp = await tmpdir()
const loop = path.join(tmp.path, "loop")
await symlink(loop, loop)
const home = spyOn(os, "homedir").mockImplementation(() => tmp.path)
const previous = process.env.OPENCODE_ZED_DB
process.env.OPENCODE_ZED_DB = loop
try {
expect(resolveZedDbPath()).toBeUndefined()
} finally {
if (previous === undefined) delete process.env.OPENCODE_ZED_DB
else process.env.OPENCODE_ZED_DB = previous
home.mockRestore()
}
})
test("resolveZedSelection returns active editor selection", async () => {
await using tmp = await tmpdir()
const fixture = await writeZedFixture(tmp.path)
@ -251,6 +270,71 @@ test("resolveZedSelection returns empty when no workspace matches", async () =>
expect(await resolveZedSelection(fixture.dbPath, tmp.path)).toEqual({ type: "empty" })
})
test("resolveZedSelection matches a Zed workspace that contains the session directory", async () => {
await using tmp = await tmpdir()
const fixture = await writeZedFixture(tmp.path)
expect(await resolveZedSelection(fixture.dbPath, path.join(tmp.path, "packages", "app"))).toEqual({
type: "selection",
selection: {
filePath: fixture.filePath,
source: "zed",
ranges: [
{
text: "two",
selection: {
start: { line: 2, character: 1 },
end: { line: 2, character: 4 },
},
},
],
},
})
})
test("resolveZedSelection prefers the most specific containing Zed workspace", async () => {
await using tmp = await tmpdir()
const fixture = await writeZedFixture(tmp.path)
const child = path.join(tmp.path, "packages")
const childFile = path.join(child, "child.ts")
await mkdir(child, { recursive: true })
await Bun.write(childFile, "child")
const db = new Database(fixture.dbPath)
db.run("insert into workspaces values (2, ?, ?)", [JSON.stringify([child]), "2026-01-01"])
db.run("insert into panes values (2, 2, 1)")
db.run("insert into items values (2, 2, 2, 1, ?)", ["Editor"])
db.run("insert into editors values (2, 2, ?, ?)", [childFile, "child"])
db.run("insert into editor_selections values (2, 2, 0, 5)")
db.close()
expect(await resolveZedSelection(fixture.dbPath, path.join(child, "app"))).toEqual({
type: "selection",
selection: {
filePath: childFile,
source: "zed",
ranges: [
{
text: "child",
selection: {
start: { line: 1, character: 1 },
end: { line: 1, character: 6 },
},
},
],
},
})
})
test("resolveZedSelection ignores a Zed workspace nested inside the session directory", async () => {
await using tmp = await tmpdir()
const child = path.join(tmp.path, "effect-lab")
await mkdir(child, { recursive: true })
const fixture = await writeZedFixture(child)
expect(await resolveZedSelection(fixture.dbPath, tmp.path)).toEqual({ type: "empty" })
})
test("resolveZedSelection returns unavailable when a Zed terminal is active", async () => {
await using tmp = await tmpdir()
const fixture = await writeZedFixture(tmp.path, { itemKind: "Terminal", editor: false })