keymap.test.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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("returns every formatted command shortcut", async () => {
  73. let read = () => [] as readonly string[]
  74. function Harness() {
  75. const shortcuts = Keymap.useShortcuts()
  76. Keymap.createLayer(() => ({
  77. commands: [{ id: "demo.command", bind: "x,y", run() {} }],
  78. }))
  79. read = () => shortcuts.list("demo.command")
  80. return <box />
  81. }
  82. const app = await testRender(() => (
  83. <ConfigProvider config={createTuiResolvedConfig()}>
  84. <Keymap.Provider>
  85. <Harness />
  86. </Keymap.Provider>
  87. </ConfigProvider>
  88. ))
  89. try {
  90. expect(read()).toEqual(["x", "y"])
  91. } finally {
  92. app.renderer.destroy()
  93. }
  94. })
  95. test("global commands stay reachable when the mode changes", async () => {
  96. const calls: string[] = []
  97. let exercise = () => {}
  98. function Harness() {
  99. const keymap = Keymap.use()
  100. Keymap.createLayer(() => ({
  101. mode: "global",
  102. commands: [{ id: "session.list", run: () => void calls.push("global") }],
  103. }))
  104. Keymap.createLayer(() => ({
  105. commands: [{ id: "model.list", run: () => void calls.push("base") }],
  106. }))
  107. exercise = () => {
  108. keymap.dispatch("session.list")
  109. keymap.dispatch("model.list")
  110. const pop = keymap.mode.push("question")
  111. keymap.dispatch("session.list")
  112. keymap.dispatch("model.list")
  113. pop()
  114. }
  115. return <box />
  116. }
  117. const app = await testRender(() => (
  118. <ConfigProvider config={createTuiResolvedConfig()}>
  119. <Keymap.Provider>
  120. <Harness />
  121. </Keymap.Provider>
  122. </ConfigProvider>
  123. ))
  124. try {
  125. exercise()
  126. expect(calls).toEqual(["global", "base", "global"])
  127. } finally {
  128. app.renderer.destroy()
  129. }
  130. })