Skip to content
Closed
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { useFrecency } from "./frecency"
import { useBindings } from "../../keymap"
import { Reference } from "@/reference/reference"
import type { Config } from "@/config/config"
import { displayCharAt, mentionTriggerIndex } from "@/cli/cmd/prompt-display"
import { displayCharAt, displaySlice, mentionTriggerIndex } from "@/cli/cmd/prompt-display"

function removeLineRange(input: string) {
const hashIndex = input.lastIndexOf("#")
Expand Down Expand Up @@ -135,7 +135,7 @@ export function Autocomplete(props: {
// Track props.value to make memo reactive to text changes
props.value // <- there surely is a better way to do this, like making .input() reactive

return props.input().getTextRange(store.index + 1, props.input().cursorOffset)
return displaySlice(props.value, store.index + 1, props.input().cursorOffset)
})

// filter() reads reactive props.value plus non-reactive cursor/text state.
Expand Down Expand Up @@ -767,7 +767,7 @@ export function Autocomplete(props: {
// Typed text before the trigger
props.input().cursorOffset <= store.index ||
// There is a space between the trigger and the cursor
props.input().getTextRange(store.index, props.input().cursorOffset).match(/\s/) ||
displaySlice(value, store.index, props.input().cursorOffset).match(/\s/) ||
// "/<command>" is not the sole content
(store.visible === "/" && value.match(/^\S+\s+\S+\s*$/))
) {
Expand All @@ -781,7 +781,7 @@ export function Autocomplete(props: {
if (offset === 0) return

// Check for "/" at position 0 - reopen slash commands
if (value.startsWith("/") && !value.slice(0, offset).match(/\s/)) {
if (value.startsWith("/") && !displaySlice(value, 0, offset).match(/\s/)) {
show("/")
setStore("index", 0)
return
Expand Down
12 changes: 12 additions & 0 deletions packages/opencode/test/cli/run/prompt.shared.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ describe("run prompt shared", () => {
expect(mentionTriggerIndex("中文 @src file")).toBeUndefined()
})

test("keeps autocomplete slicing width-safe after CJK prefixes", () => {
const mention = "中文 @readme"
const mentionStart = mentionTriggerIndex(mention, Bun.stringWidth(mention))
expect(mentionStart).toBe(5)
expect(displaySlice(mention, mentionStart! + 1, Bun.stringWidth(mention))).toBe("readme")
expect(displaySlice(mention, mentionStart!, Bun.stringWidth(mention)).match(/\s/)).toBeNull()

const slash = "/修复 bug"
expect(displaySlice(slash, 0, Bun.stringWidth("/修复")).match(/\s/)).toBeNull()
expect(displaySlice(slash, 0, Bun.stringWidth(slash)).match(/\s/)).not.toBeNull()
})

test("handles direct and leader-based variant cycling", () => {
const keys = promptKeys(keybinds)

Expand Down
Loading