keymap.test.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /** @jsxImportSource @opentui/solid */
  2. import { testRender } from "@opentui/solid"
  3. import { expect, test } from "bun:test"
  4. import { ConfigProvider } from "../src/config"
  5. import { Keymap } from "../src/context/keymap"
  6. import { createTuiResolvedConfig } from "./fixture/tui-runtime"
  7. test("legacy page key aliases compile as page keys", async () => {
  8. let read = () => ({ up: "", down: "" })
  9. function Harness() {
  10. const shortcuts = Keymap.useShortcuts()
  11. Keymap.createLayer(() => ({
  12. commands: [
  13. { id: "session.page.up", run() {} },
  14. { id: "session.page.down", run() {} },
  15. ],
  16. }))
  17. read = () => ({
  18. up: shortcuts.get("session.page.up") ?? "",
  19. down: shortcuts.get("session.page.down") ?? "",
  20. })
  21. return <box />
  22. }
  23. const app = await testRender(() => (
  24. <ConfigProvider
  25. config={createTuiResolvedConfig({
  26. keybinds: {
  27. messages_page_up: "pgup",
  28. messages_page_down: "pgdown",
  29. },
  30. })}
  31. >
  32. <Keymap.Provider>
  33. <Harness />
  34. </Keymap.Provider>
  35. </ConfigProvider>
  36. ))
  37. try {
  38. expect(read()).toEqual({ up: "pgup", down: "pgdn" })
  39. } finally {
  40. app.renderer.destroy()
  41. }
  42. })
  43. test("formats navigation keys as arrows", async () => {
  44. let read = () => ({}) as Record<string, string>
  45. const commands = ["session.parent", "session.child.first", "session.child.previous", "session.child.next"]
  46. function Harness() {
  47. const shortcuts = Keymap.useShortcuts()
  48. Keymap.createLayer(() => ({
  49. commands: commands.map((id) => ({ id, run() {} })),
  50. }))
  51. read = () => Object.fromEntries(commands.map((id) => [id, shortcuts.get(id) ?? ""]))
  52. return <box />
  53. }
  54. const app = await testRender(() => (
  55. <ConfigProvider config={createTuiResolvedConfig()}>
  56. <Keymap.Provider>
  57. <Harness />
  58. </Keymap.Provider>
  59. </ConfigProvider>
  60. ))
  61. try {
  62. expect(read()).toEqual({
  63. "session.parent": "↑",
  64. "session.child.first": "↓",
  65. "session.child.previous": "←",
  66. "session.child.next": "→",
  67. })
  68. } finally {
  69. app.renderer.destroy()
  70. }
  71. })
  72. test("global commands stay reachable when the mode changes", async () => {
  73. const calls: string[] = []
  74. let exercise = () => {}
  75. function Harness() {
  76. const keymap = Keymap.use()
  77. Keymap.createLayer(() => ({
  78. mode: "global",
  79. commands: [{ id: "session.list", run: () => void calls.push("global") }],
  80. }))
  81. Keymap.createLayer(() => ({
  82. commands: [{ id: "model.list", run: () => void calls.push("base") }],
  83. }))
  84. exercise = () => {
  85. keymap.dispatch("session.list")
  86. keymap.dispatch("model.list")
  87. const pop = keymap.mode.push("question")
  88. keymap.dispatch("session.list")
  89. keymap.dispatch("model.list")
  90. pop()
  91. }
  92. return <box />
  93. }
  94. const app = await testRender(() => (
  95. <ConfigProvider config={createTuiResolvedConfig()}>
  96. <Keymap.Provider>
  97. <Harness />
  98. </Keymap.Provider>
  99. </ConfigProvider>
  100. ))
  101. try {
  102. exercise()
  103. expect(calls).toEqual(["global", "base", "global"])
  104. } finally {
  105. app.renderer.destroy()
  106. }
  107. })