mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-05 20:04:49 +00:00
115 lines
3.6 KiB
TypeScript
115 lines
3.6 KiB
TypeScript
import { expect, test } from "bun:test"
|
|
import type { SelectionBehavior } from "@opentui/core"
|
|
import type { ClipboardService } from "../../src/context/clipboard"
|
|
import { Selection, copy, copyOnSelectRelease } from "../../src/util/selection"
|
|
|
|
function renderer() {
|
|
return {
|
|
getSelection: () => ({
|
|
getSelectedText: () => "beta",
|
|
selectedRenderables: [],
|
|
isStart: false,
|
|
behavior: "cell" as const,
|
|
}),
|
|
clearSelection: () => {},
|
|
}
|
|
}
|
|
|
|
function setup(text: string, isStart: boolean, behavior: SelectionBehavior = "cell") {
|
|
const writes: string[] = []
|
|
let clears = 0
|
|
const clipboard: ClipboardService = {
|
|
read: async () => undefined,
|
|
write: async (value) => {
|
|
writes.push(value)
|
|
},
|
|
}
|
|
const renderer = {
|
|
getSelection: () => ({ getSelectedText: () => text, selectedRenderables: [], isStart, behavior }),
|
|
clearSelection: () => {
|
|
clears++
|
|
},
|
|
currentFocusedRenderable: null,
|
|
}
|
|
const toast = { show: () => {}, error: () => {} }
|
|
return { clipboard, renderer, toast, writes, clears: () => clears }
|
|
}
|
|
|
|
test("copy writes selected text without clearing the highlight", () => {
|
|
let cleared = false
|
|
const copied = copy(
|
|
{
|
|
getSelection: () => ({
|
|
getSelectedText: () => "beta",
|
|
selectedRenderables: [],
|
|
isStart: false,
|
|
behavior: "cell",
|
|
}),
|
|
clearSelection: () => {
|
|
cleared = true
|
|
},
|
|
},
|
|
{ show: () => {}, error: () => {} },
|
|
{
|
|
async read() {
|
|
return undefined
|
|
},
|
|
async write() {},
|
|
},
|
|
)
|
|
expect(copied).toBe(true)
|
|
expect(cleared).toBe(false)
|
|
})
|
|
|
|
test("copy-on-select ignores a later non-drag release", () => {
|
|
const writes: string[] = []
|
|
const clipboard = {
|
|
async read() {
|
|
return undefined
|
|
},
|
|
async write(value: string) {
|
|
writes.push(value)
|
|
},
|
|
}
|
|
const toast = { show: () => {}, error: () => {} }
|
|
expect(copyOnSelectRelease({}, renderer(), toast, clipboard)).toBe(false)
|
|
expect(copyOnSelectRelease({ isDragging: false }, renderer(), toast, clipboard)).toBe(false)
|
|
expect(copyOnSelectRelease({ isDragging: true }, renderer(), toast, clipboard)).toBe(true)
|
|
expect(writes).toEqual(["beta"])
|
|
})
|
|
|
|
test("copy-on-select preserves a click-only selection for subsequent clicks", () => {
|
|
const value = setup("", true)
|
|
expect(copyOnSelectRelease({ isDragging: true }, value.renderer, value.toast, value.clipboard)).toBeFalse()
|
|
expect(value.clears()).toBe(0)
|
|
expect(value.writes).toEqual([])
|
|
})
|
|
|
|
test.each(["word", "line"] as const)("copy-on-select copies a %s selection without pointer movement", (behavior) => {
|
|
const value = setup("selected", true, behavior)
|
|
expect(copyOnSelectRelease({ isDragging: true }, value.renderer, value.toast, value.clipboard)).toBeTrue()
|
|
expect(value.clears()).toBe(0)
|
|
expect(value.writes).toEqual(["selected"])
|
|
})
|
|
|
|
test("ignores a click-only selection without copying or clearing", () => {
|
|
const value = setup("x", true)
|
|
expect(Selection.copy(value.renderer, value.toast, value.clipboard)).toBeFalse()
|
|
expect(value.clears()).toBe(0)
|
|
expect(value.writes).toEqual([])
|
|
})
|
|
|
|
test("ignores an empty dragged selection without copying or clearing", () => {
|
|
const value = setup("", false)
|
|
expect(Selection.copy(value.renderer, value.toast, value.clipboard)).toBeFalse()
|
|
expect(value.clears()).toBe(0)
|
|
expect(value.writes).toEqual([])
|
|
})
|
|
|
|
test("copies a non-empty dragged selection without clearing its highlight", async () => {
|
|
const value = setup("selected", false)
|
|
expect(Selection.copy(value.renderer, value.toast, value.clipboard)).toBeTrue()
|
|
await Promise.resolve()
|
|
expect(value.clears()).toBe(0)
|
|
expect(value.writes).toEqual(["selected"])
|
|
})
|