Skip to content

Commit 41df039

Browse files
authored
fix(tui): preserve Zed context on terminal focus (anomalyco#24662)
1 parent 436d95b commit 41df039

2 files changed

Lines changed: 31 additions & 11 deletions

File tree

packages/opencode/src/cli/cmd/tui/context/editor-zed.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { Filesystem } from "@/util/filesystem"
66
import type { EditorSelection } from "./editor"
77

88
const ZedEditorRowSchema = z.object({
9-
editor_id: z.number(),
9+
item_kind: z.string(),
10+
editor_id: z.number().nullable(),
1011
workspace_id: z.number(),
1112
workspace_paths: z.string().nullable(),
1213
timestamp: z.string(),
@@ -20,6 +21,7 @@ const ZedEditorContentsSchema = z.object({
2021
})
2122

2223
type ZedEditorRow = z.infer<typeof ZedEditorRowSchema>
24+
type ZedActiveEditorRow = ZedEditorRow & { item_kind: "Editor"; editor_id: number }
2325

2426
export type ZedSelectionResult =
2527
| { type: "selection"; selection: EditorSelection }
@@ -64,8 +66,9 @@ function queryZedActiveEditor(dbPath: string, cwd: string) {
6466
const raw = db
6567
.query(
6668
`select
69+
i.kind as item_kind,
6770
e.item_id as editor_id,
68-
e.workspace_id as workspace_id,
71+
i.workspace_id as workspace_id,
6972
w.paths as workspace_paths,
7073
w.timestamp as timestamp,
7174
e.buffer_path as buffer_path,
@@ -74,9 +77,9 @@ function queryZedActiveEditor(dbPath: string, cwd: string) {
7477
from items i
7578
join panes p on p.pane_id = i.pane_id and p.workspace_id = i.workspace_id
7679
join workspaces w on w.workspace_id = i.workspace_id
77-
join editors e on e.item_id = i.item_id and e.workspace_id = i.workspace_id
80+
left join editors e on e.item_id = i.item_id and e.workspace_id = i.workspace_id
7881
left join editor_selections s on s.editor_id = e.item_id and s.workspace_id = e.workspace_id
79-
where i.active = 1 and p.active = 1 and i.kind = 'Editor' and e.buffer_path is not null
82+
where i.active = 1 and p.active = 1
8083
order by w.timestamp desc`,
8184
)
8285
.all()
@@ -93,6 +96,8 @@ function queryZedActiveEditor(dbPath: string, cwd: string) {
9396
.filter((entry) => entry.score > 0)
9497
.sort((left, right) => right.score - left.score || right.row.timestamp.localeCompare(left.row.timestamp))[0]?.row
9598
if (!row) return { type: "empty" as const }
99+
if (row.item_kind !== "Editor") return { type: "unavailable" as const }
100+
if (!isZedActiveEditorRow(row)) return { type: "empty" as const }
96101
return { type: "row" as const, row }
97102
} catch {
98103
return { type: "unavailable" as const }
@@ -101,7 +106,7 @@ function queryZedActiveEditor(dbPath: string, cwd: string) {
101106
}
102107
}
103108

104-
function queryZedEditorContents(dbPath: string, row: ZedEditorRow) {
109+
function queryZedEditorContents(dbPath: string, row: ZedActiveEditorRow) {
105110
let db: Database | undefined
106111
try {
107112
db = new Database(dbPath, { readonly: true })
@@ -123,6 +128,10 @@ function queryZedEditorContents(dbPath: string, row: ZedEditorRow) {
123128
}
124129
}
125130

131+
function isZedActiveEditorRow(row: ZedEditorRow): row is ZedActiveEditorRow {
132+
return row.item_kind === "Editor" && row.editor_id != null
133+
}
134+
126135
export function resolveZedDbPath() {
127136
const candidates = [
128137
process.env.OPENCODE_ZED_DB,

packages/opencode/test/cli/tui/editor-context.test.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { tmpdir } from "../../fixture/fixture"
66

77
type ZedFixtureOptions = {
88
workspacePaths?: string | null
9+
itemKind?: string
10+
editor?: boolean
911
selectionStart?: number | null
1012
selectionEnd?: number | null
1113
}
@@ -23,12 +25,14 @@ async function writeZedFixture(dir: string, options: ZedFixtureOptions = {}) {
2325
db.run("create table editor_selections (editor_id integer, workspace_id integer, start integer, end integer)")
2426
db.run("insert into workspaces values (1, ?, ?)", [options.workspacePaths ?? JSON.stringify([dir]), "2026-04-27"])
2527
db.run("insert into panes values (1, 1, 1)")
26-
db.run("insert into items values (1, 1, 1, 1, 'Editor')")
27-
db.run("insert into editors values (1, 1, ?, ?)", [filePath, "one\ntwo\nthree"])
28-
db.run("insert into editor_selections values (1, 1, ?, ?)", [
29-
options.selectionStart === undefined ? 4 : options.selectionStart,
30-
options.selectionEnd === undefined ? 7 : options.selectionEnd,
31-
])
28+
db.run("insert into items values (1, 1, 1, 1, ?)", [options.itemKind ?? "Editor"])
29+
if (options.editor !== false) {
30+
db.run("insert into editors values (1, 1, ?, ?)", [filePath, "one\ntwo\nthree"])
31+
db.run("insert into editor_selections values (1, 1, ?, ?)", [
32+
options.selectionStart === undefined ? 4 : options.selectionStart,
33+
options.selectionEnd === undefined ? 7 : options.selectionEnd,
34+
])
35+
}
3236
db.close()
3337

3438
return { dbPath, filePath }
@@ -68,6 +72,13 @@ test("resolveZedSelection returns empty when no workspace matches", async () =>
6872
expect(await resolveZedSelection(fixture.dbPath, tmp.path)).toEqual({ type: "empty" })
6973
})
7074

75+
test("resolveZedSelection returns unavailable when a Zed terminal is active", async () => {
76+
await using tmp = await tmpdir()
77+
const fixture = await writeZedFixture(tmp.path, { itemKind: "Terminal", editor: false })
78+
79+
expect(await resolveZedSelection(fixture.dbPath, tmp.path)).toEqual({ type: "unavailable" })
80+
})
81+
7182
test("resolveZedSelection returns unavailable when the database cannot be queried", async () => {
7283
await using tmp = await tmpdir()
7384

0 commit comments

Comments
 (0)