mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-15 20:52:01 +03:00
feat(tui): close tabs with middle click (#43497)
Co-authored-by: kitlangton <7587245+kitlangton@users.noreply.github.com> Co-authored-by: Kit Langton <kit.langton@gmail.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
d4a0f163a9
commit
8fb534d03e
@@ -46,6 +46,7 @@ const ADD_TAB_WIDTH = 3
|
||||
const MARQUEE_DELAY = 600
|
||||
const MARQUEE_INTERVAL = 80
|
||||
const CONTEXT_MENU_WIDTH = 16
|
||||
const MIDDLE_MOUSE_BUTTON = 1
|
||||
const RIGHT_MOUSE_BUTTON = 2
|
||||
|
||||
type TabContextMenuState = {
|
||||
@@ -569,6 +570,14 @@ function VerticalSessionTabs(props: { controller?: SessionTabsController; animat
|
||||
onMouseOver={() => marquee.enter(tab.sessionID, title(), hoveredTitleWidth())}
|
||||
onMouseOut={() => marquee.leave(tab.sessionID)}
|
||||
onMouseDown={(event) => {
|
||||
if (event.button === MIDDLE_MOUSE_BUTTON) {
|
||||
didDrag = false
|
||||
setDragging(undefined)
|
||||
tabs.close(tab.sessionID)
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
}
|
||||
if (event.button === RIGHT_MOUSE_BUTTON) {
|
||||
didDrag = false
|
||||
setDragging(undefined)
|
||||
@@ -1108,6 +1117,14 @@ function HorizontalSessionTabs(props: { controller?: SessionTabsController; anim
|
||||
onMouseOver={() => marquee.enter(tab.sessionID, title(), hoveredTitleWidth())}
|
||||
onMouseOut={() => marquee.leave(tab.sessionID)}
|
||||
onMouseDown={(event) => {
|
||||
if (event.button === MIDDLE_MOUSE_BUTTON) {
|
||||
didDrag = false
|
||||
setDragging(undefined)
|
||||
tabs.close(tab === NEW_SESSION_TAB ? undefined : tab.sessionID)
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
}
|
||||
if (event.button === RIGHT_MOUSE_BUTTON) {
|
||||
didDrag = false
|
||||
setDragging(undefined)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/** @jsxImportSource @opentui/solid */
|
||||
import { testRender } from "@opentui/solid"
|
||||
import { MouseButton } from "@opentui/core"
|
||||
import { expect, test } from "bun:test"
|
||||
import { createSignal } from "solid-js"
|
||||
import { ConfigProvider } from "../../src/config"
|
||||
@@ -60,3 +61,41 @@ test("releasing a transcript selection over tab controls does not activate them"
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("middle-click closes a session tab without selecting it", async () => {
|
||||
const [active, setActive] = createSignal("first")
|
||||
const closed: Array<string | undefined> = []
|
||||
const controller = {
|
||||
tabs: () => [
|
||||
{ sessionID: "first", title: "First" },
|
||||
{ sessionID: "second", title: "Second" },
|
||||
],
|
||||
current: active,
|
||||
select: setActive,
|
||||
close: (sessionID?: string) => closed.push(sessionID),
|
||||
move() {},
|
||||
status: () => EMPTY_SESSION_TAB_STATUS,
|
||||
} satisfies SessionTabsController
|
||||
const app = await testRender(
|
||||
() => (
|
||||
<TestTuiContexts>
|
||||
<ConfigProvider config={createTuiResolvedConfig({ tabs: { enabled: true } })}>
|
||||
<ThemeProvider mode="dark" source={emptyThemeSource}>
|
||||
<SessionTabs controller={controller} animations={false} />
|
||||
</ThemeProvider>
|
||||
</ConfigProvider>
|
||||
</TestTuiContexts>
|
||||
),
|
||||
{ width: 60, height: 8 },
|
||||
)
|
||||
|
||||
try {
|
||||
app.renderer.start()
|
||||
await app.waitForFrame((frame) => frame.includes("Second"))
|
||||
await app.mockMouse.click(40, 0, MouseButton.MIDDLE)
|
||||
expect(closed).toEqual(["second"])
|
||||
expect(active()).toBe("first")
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user