Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 53 additions & 3 deletions src/modules/vim/vimee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { createPromptMap, derivePromptMap, hostOffset, hostPosition, type Prompt
import type { createVimState } from "./state"

type VimState = ReturnType<typeof createVimState>
type HostAction = VimeeAction | { type: "submit" }
type HostKeybindAction = "normal" | "submit"
type HostKeybindDefinition = KeybindDefinition & { hostAction?: HostKeybindAction }
type HostAction = VimeeAction | { type: "submit" } | { type: "command"; command: string }
type HostKeybindAction = "normal" | "submit" | "command"
type HostKeybindDefinition = KeybindDefinition & { hostAction?: HostKeybindAction; command?: string }
type HostRange = { start: number; end: number }

const YANK_FLASH_MS = 250
Expand Down Expand Up @@ -164,6 +164,7 @@ export function createVimeeAdapter(state: VimState, config: VimConfig, log: VimL
break
case "cursor-move":
setCursor(input, currentMap, action.position)
syncVisualCursor(input)
break
case "mode-change":
nativeInsertUndoSaved = false
Expand All @@ -175,6 +176,18 @@ export function createVimeeAdapter(state: VimState, config: VimConfig, log: VimL
case "submit":
ref.submit()
break
case "command":
if (input) {
const textLen = input.plainText?.length ?? 0
if (action.command === "prompt.history.previous") {
input.cursorOffset = 0
} else if (action.command === "prompt.history.next") {
input.cursorOffset = textLen
}
syncVisualCursor(input)
}
ctx.api.keymap.dispatchCommand(action.command)
break
}
}

Expand Down Expand Up @@ -228,6 +241,22 @@ export function createVimeeAdapter(state: VimState, config: VimConfig, log: VimL
case "submit":
ctx.prompt()?.submit()
return true
case "command":
{
const input = focusedInput(ctx)
if (input) {
const textLen = input.plainText?.length ?? 0
const cmd = (definition as HostKeybindDefinition).command!
if (cmd === "prompt.history.previous") {
input.cursorOffset = 0
} else if (cmd === "prompt.history.next") {
input.cursorOffset = textLen
}
syncVisualCursor(input)
}
ctx.api.keymap.dispatchCommand((definition as HostKeybindDefinition).command!)
}
return true
default:
return false
}
Expand Down Expand Up @@ -549,6 +578,19 @@ function clampNormalCursor(input: EditBufferLike) {
if (cursor.visualRow === eol.visualRow && (cursor.offset === eol.offset || offset === eol.offset)) input.cursorOffset = Math.max(0, offset - 1)
}

function syncVisualCursor(input: EditBufferLike | undefined) {
if (!input?.visualCursor || input.plainText === undefined) return
const text = input.plainText
const offset = input.cursorOffset ?? 0
const before = text.slice(0, offset)
const row = before.split('\n').length - 1
const lastNewline = before.lastIndexOf('\n')
const col = offset - lastNewline - 1
input.visualCursor.visualRow = row
input.visualCursor.visualCol = col
input.visualCursor.offset = offset
}

function endMotionOffset(text: string, offset: number, count: number) {
let index = offset
for (let step = 0; step < count; step++) {
Expand Down Expand Up @@ -590,6 +632,14 @@ function createKeybinds(config: VimConfig, log: VimLog): KeybindMap | undefined
}

function keybindAction(action: string): HostKeybindDefinition {
if (action.startsWith("command:")) {
const command = action.slice(8)
return {
execute: () => [{ type: "command", command } as unknown as VimeeAction],
hostAction: "command",
command,
}
}
switch (action) {
case "normal":
return { keys: "<Esc>", hostAction: "normal" }
Expand Down