opencode-vim 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
import type { KeyEvent, ParsedKey } from "@opentui/core"
|
|
2
3
|
import { useKeyboard } from "@opentui/solid"
|
|
3
4
|
import { onCleanup } from "solid-js"
|
|
4
5
|
import type { PromptContext, PromptModule } from "../../prompt/types"
|
|
5
|
-
import { applyVimCursorStyle } from "./actions"
|
|
6
|
+
import { applyVimCursorStyle, focusedInput } from "./actions"
|
|
6
7
|
import type { VimConfig } from "./config"
|
|
7
8
|
import { createVimConfig } from "./config"
|
|
8
9
|
import { keyNotation } from "./keys"
|
|
@@ -63,6 +64,19 @@ function VimKeyboard(props: { ctx: PromptContext; config: VimConfig; state: Retu
|
|
|
63
64
|
return
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
if (passThroughKey(event, key, props.state.mode())) {
|
|
68
|
+
preparePassThroughKey(props.ctx, key, props.state.mode())
|
|
69
|
+
syncCursorStyle(true)
|
|
70
|
+
props.ctx.requestRender()
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (sendNavigationKey(event, props.ctx, key, props.state.mode())) {
|
|
75
|
+
syncCursorStyle(true)
|
|
76
|
+
props.ctx.requestRender()
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
const consumed = vimee.handle(event, key, props.ctx)
|
|
67
81
|
if (consumed) {
|
|
68
82
|
event.preventDefault()
|
|
@@ -94,3 +108,74 @@ function readablePending(sequence: string) {
|
|
|
94
108
|
if (!sequence) return undefined
|
|
95
109
|
return sequence.replaceAll("><", " ")
|
|
96
110
|
}
|
|
111
|
+
|
|
112
|
+
function passThroughKey(event: KeyEvent, key: string, mode: string) {
|
|
113
|
+
if (mode !== "normal") return false
|
|
114
|
+
return event.super === true || isArrowKey(key) || key === "<CR>" || key === "<C-c>"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function preparePassThroughKey(ctx: PromptContext, key: string, mode: string) {
|
|
118
|
+
if (mode !== "normal" || key !== "<CR>") return
|
|
119
|
+
const input = focusedInput(ctx)
|
|
120
|
+
if (!input?.plainText || input.cursorOffset === undefined) return
|
|
121
|
+
input.cursorOffset = Math.min(input.cursorOffset + 1, input.plainText.length)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function sendNavigationKey(event: KeyEvent, ctx: PromptContext, key: string, mode: string) {
|
|
125
|
+
if (mode !== "normal") return false
|
|
126
|
+
const forwarded = commandNavigationKey(ctx, key)
|
|
127
|
+
if (!forwarded) return false
|
|
128
|
+
|
|
129
|
+
event.preventDefault()
|
|
130
|
+
event.stopPropagation()
|
|
131
|
+
ctx.api.renderer.keyInput.processParsedKey(forwarded)
|
|
132
|
+
return true
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function commandNavigationKey(ctx: PromptContext, key: string): ParsedKey | undefined {
|
|
136
|
+
if (!isPromptFocused(ctx)) return navigationKey(key)
|
|
137
|
+
if (!isSlashCommandToken(ctx)) return undefined
|
|
138
|
+
if (key === "j") return arrowKey("down", "\u001B[B")
|
|
139
|
+
if (key === "k") return arrowKey("up", "\u001B[A")
|
|
140
|
+
return undefined
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function isPromptFocused(ctx: PromptContext) {
|
|
144
|
+
return ctx.prompt()?.focused === true && !!focusedInput(ctx)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function isSlashCommandToken(ctx: PromptContext) {
|
|
148
|
+
const text = ctx.prompt()?.current.input ?? focusedInput(ctx)?.plainText ?? ""
|
|
149
|
+
if (!text.startsWith("/")) return false
|
|
150
|
+
const input = focusedInput(ctx)
|
|
151
|
+
const offset = Math.max(0, input?.cursorOffset ?? text.length)
|
|
152
|
+
return !/\s/.test(text.slice(0, Math.min(offset + 1, text.length)))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function navigationKey(key: string): ParsedKey | undefined {
|
|
156
|
+
if (key === "h") return arrowKey("left", "\u001B[D")
|
|
157
|
+
if (key === "j") return arrowKey("down", "\u001B[B")
|
|
158
|
+
if (key === "k") return arrowKey("up", "\u001B[A")
|
|
159
|
+
if (key === "l") return arrowKey("right", "\u001B[C")
|
|
160
|
+
return undefined
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function isArrowKey(key: string) {
|
|
164
|
+
return key === "<Left>" || key === "<Down>" || key === "<Up>" || key === "<Right>"
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function arrowKey(name: string, sequence: string): ParsedKey {
|
|
168
|
+
return {
|
|
169
|
+
name,
|
|
170
|
+
ctrl: false,
|
|
171
|
+
meta: false,
|
|
172
|
+
shift: false,
|
|
173
|
+
option: false,
|
|
174
|
+
sequence,
|
|
175
|
+
number: false,
|
|
176
|
+
raw: sequence,
|
|
177
|
+
eventType: "press",
|
|
178
|
+
source: "raw",
|
|
179
|
+
super: false,
|
|
180
|
+
}
|
|
181
|
+
}
|
package/src/modules/vim/vimee.ts
CHANGED
|
@@ -149,7 +149,7 @@ export function createVimeeAdapter(state: VimState, config: VimConfig, log: VimL
|
|
|
149
149
|
|
|
150
150
|
function handleInsertMode(event: KeyEvent, key: string, ctx: PromptContext, map: PromptMap, cursor: CursorPosition, offset: number) {
|
|
151
151
|
if (key === "Escape") {
|
|
152
|
-
cancelPendingInsert(ctx, offset)
|
|
152
|
+
cancelPendingInsert(ctx, offset, false)
|
|
153
153
|
sync(map, cursor)
|
|
154
154
|
const result = processKeystroke(key, vim, buffer, event.ctrl, false)
|
|
155
155
|
vim = result.newCtx
|
|
@@ -221,12 +221,12 @@ export function createVimeeAdapter(state: VimState, config: VimConfig, log: VimL
|
|
|
221
221
|
}, config.keymapTimeout)
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
function cancelPendingInsert(ctx: PromptContext, offset?: number) {
|
|
224
|
+
function cancelPendingInsert(ctx: PromptContext, offset?: number, flush = true) {
|
|
225
225
|
if (!keybinds?.isPending()) return
|
|
226
226
|
if (timer) clearTimeout(timer)
|
|
227
227
|
timer = undefined
|
|
228
228
|
keybinds.cancel()
|
|
229
|
-
flushPendingInsert(ctx, pendingInsert, offset)
|
|
229
|
+
if (flush) flushPendingInsert(ctx, pendingInsert, offset)
|
|
230
230
|
pendingInsert = ""
|
|
231
231
|
state.setPending("")
|
|
232
232
|
}
|