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 @@ -78,7 +78,10 @@ export function serializeChatComposerContent(content: JSONContent): ChatComposer
}

export function findChatComposerTrigger(textBeforeCursor: string): ChatComposerTrigger | null {
const candidateSlashIndex = findTriggerStart(textBeforeCursor, '/')
const candidateSlashIndex = Math.max(
findTriggerStart(textBeforeCursor, '/'),
findTriggerStart(textBeforeCursor, '、'),
)
const slashIndex = candidateSlashIndex >= 0
&& textBeforeCursor.slice(0, candidateSlashIndex).trim().length === 0
? candidateSlashIndex
Expand All @@ -103,7 +106,7 @@ export function findChatComposerTrigger(textBeforeCursor: string): ChatComposerT
if (/\s/u.test(query))
return null
return {
kind: trigger === '/' ? 'slash' : trigger === '$' ? 'skill' : 'mention',
kind: trigger === '/' || trigger === '、' ? 'slash' : trigger === '$' ? 'skill' : 'mention',
query,
}
}
Expand Down Expand Up @@ -148,7 +151,7 @@ export function shouldSubmitChatComposerKey(
&& !event.metaKey
}

function findTriggerStart(value: string, trigger: '/' | '$' | '@'): number {
function findTriggerStart(value: string, trigger: '/' | '、' | '$' | '@'): number {
const index = value.lastIndexOf(trigger)
if (index < 0 || (index > 0 && !TRIGGER_BOUNDARY_PATTERN.test(value[index - 1] ?? '')))
return -1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,21 @@ async function mountComposer(options: {
}

describe('chat composer editing', () => {
it('opens slash command suggestions with the Chinese ideographic comma and replaces the trigger on selection', async () => {
const flow = await mountComposer()
flow.editor.view.dom.focus()
flow.editor.commands.insertContent('、rev')

await expect.poll(() => flow.composer.activeTrigger.value).toEqual({ kind: 'slash', query: 'rev' })
const review = flow.composer.suggestions.value.find(({ option }) => option.value === '/review')?.option
expect(review).toBeDefined()
flow.composer.selectSuggestion(review)

const content = chatComposerDocumentToUserContent(flow.editor.getJSON())
expect(content.body[0]?.content[0]).toMatchObject({ type: 'prompt_directive', directive: 'slash_command', commandMode: 'prompt', value: '/review' })
expect(JSON.stringify(content)).not.toContain('、')
})

it.each(['select', 'submit'] as const)('submits a run action with its arguments through %s', async (source) => {
const flow = await mountComposer()
const prefix = source === 'select' ? '/com' : '/compact'
Expand Down