Skip to content

Commit 6510a4a

Browse files
committed
Replace curly braces icon with slash icon to open prompt templates quick pick
- when alt/option+x is pressed, should not keep 'edit format' shortcuts toggled, or 'esc' over mode. - when user presses option/alt+x, open the dropdown on key-up, otherwise wait for the number of invocations, e.g. option/alt+x+2 - once user presses alt/option with any other key, hide hints (esc / w s d t) until alt/option is pressed again - once user presses alt/option+esc, hints of edit formats should dissapear - when changing the edit format using keyboard shortcut, should not hide key hints immediately, but wait for updated prop (otherwise we have jank) - should not show invocation count dropdown on alt/option+x press - `apps/editor/src/views/prompt/frontend/Main/MainView/components/Header/hooks/use-keyboard-shortcuts.ts` should use params variable (don't destructure) - 'prompt templates' should use "/" (slash) in its icon and as a shortcut
1 parent 0750e1f commit 6510a4a

10 files changed

Lines changed: 209 additions & 87 deletions

File tree

‎apps/editor/src/views/prompt/backend/message-handlers/handle-show-prompt-template-quick-pick.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,15 @@ export const handle_show_prompt_template_quick_pick = async (
328328
}
329329
}
330330

331-
prompt_view_provider.add_text_at_cursor_position(prompt_text)
331+
const current_text = prompt_view_provider.current_instruction
332+
const is_after_slash = current_text
333+
.slice(0, prompt_view_provider.caret_position)
334+
.endsWith('/')
335+
if (is_after_slash) {
336+
prompt_view_provider.add_text_at_cursor_position(prompt_text, 1)
337+
} else {
338+
prompt_view_provider.add_text_at_cursor_position(prompt_text)
339+
}
332340
prompt_view_provider.send_message({
333341
command: 'FOCUS_PROMPT_FIELD'
334342
})

‎apps/editor/src/views/prompt/frontend/Main/Main.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ export const Main: React.FC<Props> = (props) => {
444444
})
445445
}
446446

447-
const handle_curly_braces_click = () => {
447+
const handle_slash_click = () => {
448448
post_message(props.vscode, {
449449
command: 'SHOW_PROMPT_TEMPLATE_QUICK_PICK'
450450
})
@@ -548,7 +548,7 @@ export const Main: React.FC<Props> = (props) => {
548548
on_create_api_configuration={handle_create_api_configuration}
549549
on_at_sign_click={handle_at_sign_click}
550550
on_hash_sign_click={handle_hash_sign_click}
551-
on_curly_braces_click={handle_curly_braces_click}
551+
on_slash_click={handle_slash_click}
552552
is_connected={props.is_connected}
553553
web_configurations={all_web_configurations || []}
554554
on_create_web_configuration={handle_create_web_configuration}

‎apps/editor/src/views/prompt/frontend/Main/MainView/MainView.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type Props = {
3636
) => void
3737
on_at_sign_click: (search_value?: string) => void
3838
on_hash_sign_click: () => void
39-
on_curly_braces_click: () => void
39+
on_slash_click: () => void
4040
on_quick_action_click: (command: string) => void
4141
is_connected: boolean
4242
web_configurations: WebConfiguration[]
@@ -352,7 +352,7 @@ export const MainView: React.FC<Props> = (props) => {
352352
on_copy={props.copy_to_clipboard}
353353
on_at_sign_click={props.on_at_sign_click}
354354
on_hash_sign_click={props.on_hash_sign_click}
355-
on_curly_braces_click={props.on_curly_braces_click}
355+
on_slash_click={props.on_slash_click}
356356
is_web_mode={props.mode == MODE.WEB}
357357
is_connected={props.is_connected}
358358
prompt_type={
Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from 'react'
1+
import { useEffect, useState, useRef } from 'react'
22
import { use_is_mac } from '@shared/hooks'
33
import { MODE, Mode } from '@/views/prompt/types/main-view-mode'
44
import { ApiPromptType, WebPromptType } from '@shared/types/prompt-types'
@@ -7,33 +7,37 @@ import {
77
web_prompt_type_labels
88
} from '../../../prompt-type-labels'
99

10-
type UseKeyboardShortcutsParams = {
10+
export const use_keyboard_shortcuts = (params: {
1111
mode: Mode
1212
handle_heading_click: () => void
1313
on_web_prompt_type_change: (prompt_type: WebPromptType) => void
1414
on_api_prompt_type_change: (prompt_type: ApiPromptType) => void
1515
on_show_home: () => void
1616
is_disabled: boolean
17-
}
18-
19-
export const use_keyboard_shortcuts = ({
20-
mode,
21-
handle_heading_click,
22-
on_web_prompt_type_change,
23-
on_api_prompt_type_change,
24-
on_show_home,
25-
is_disabled
26-
}: UseKeyboardShortcutsParams) => {
17+
}) => {
2718
const is_mac = use_is_mac()
2819
const [is_alt_pressed, set_is_alt_pressed] = useState(false)
20+
const alt_interrupted_ref = useRef(false)
2921

3022
useEffect(() => {
3123
const handle_key_down = (event: KeyboardEvent) => {
32-
set_is_alt_pressed(
33-
event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey
34-
)
24+
if (
25+
event.key == 'Alt' &&
26+
!event.shiftKey &&
27+
!event.ctrlKey &&
28+
!event.metaKey
29+
) {
30+
if (!alt_interrupted_ref.current) {
31+
set_is_alt_pressed(true)
32+
}
33+
} else {
34+
if (event.altKey) {
35+
alt_interrupted_ref.current = true
36+
}
37+
set_is_alt_pressed(false)
38+
}
3539

36-
if (is_disabled) return
40+
if (params.is_disabled) return
3741

3842
if (
3943
event.key == 'Escape' &&
@@ -42,7 +46,7 @@ export const use_keyboard_shortcuts = ({
4246
!event.altKey &&
4347
!event.shiftKey
4448
) {
45-
on_show_home()
49+
params.on_show_home()
4650
} else if (
4751
event.key == 'Escape' &&
4852
event.altKey &&
@@ -51,25 +55,35 @@ export const use_keyboard_shortcuts = ({
5155
!event.shiftKey
5256
) {
5357
event.preventDefault()
54-
handle_heading_click()
58+
params.handle_heading_click()
5559
}
5660
}
5761

5862
const handle_key_up = (event: KeyboardEvent) => {
63+
if (!event.altKey) {
64+
alt_interrupted_ref.current = false
65+
} else if (event.key != 'Alt') {
66+
alt_interrupted_ref.current = true
67+
}
5968
set_is_alt_pressed(
60-
event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey
69+
event.altKey &&
70+
!alt_interrupted_ref.current &&
71+
!event.shiftKey &&
72+
!event.ctrlKey &&
73+
!event.metaKey
6174
)
6275
}
6376

6477
const handle_blur = () => {
6578
set_is_alt_pressed(false)
79+
alt_interrupted_ref.current = false
6680
}
6781

6882
const handle_mouse_up = (event: MouseEvent) => {
69-
if (is_disabled) return
83+
if (params.is_disabled) return
7084

7185
if (event.button == 3) {
72-
on_show_home()
86+
params.on_show_home()
7387
}
7488
}
7589

@@ -84,11 +98,16 @@ export const use_keyboard_shortcuts = ({
8498
window.removeEventListener('blur', handle_blur)
8599
window.removeEventListener('mouseup', handle_mouse_up)
86100
}
87-
}, [is_disabled, on_show_home, is_mac, handle_heading_click])
101+
}, [
102+
params.is_disabled,
103+
params.on_show_home,
104+
is_mac,
105+
params.handle_heading_click
106+
])
88107

89108
useEffect(() => {
90109
const handle_key_down = (event: KeyboardEvent) => {
91-
if (is_disabled) return
110+
if (params.is_disabled) return
92111

93112
if (!event.altKey || !event.shiftKey || event.metaKey || event.ctrlKey) {
94113
return
@@ -100,18 +119,18 @@ export const use_keyboard_shortcuts = ({
100119

101120
const key = event.code.replace('Key', '').toLowerCase()
102121

103-
if (mode == MODE.WEB) {
122+
if (params.mode == MODE.WEB) {
104123
for (const [value, label] of Object.entries(web_prompt_type_labels)) {
105124
if (label.toLowerCase().startsWith(key)) {
106-
on_web_prompt_type_change(value as WebPromptType)
125+
params.on_web_prompt_type_change(value as WebPromptType)
107126
event.preventDefault()
108127
return
109128
}
110129
}
111-
} else if (mode == MODE.API) {
130+
} else if (params.mode == MODE.API) {
112131
for (const [value, label] of Object.entries(api_prompt_type_labels)) {
113132
if (label.toLowerCase().startsWith(key)) {
114-
on_api_prompt_type_change(value as ApiPromptType)
133+
params.on_api_prompt_type_change(value as ApiPromptType)
115134
event.preventDefault()
116135
return
117136
}
@@ -124,7 +143,12 @@ export const use_keyboard_shortcuts = ({
124143
return () => {
125144
window.removeEventListener('keydown', handle_key_down)
126145
}
127-
}, [mode, on_web_prompt_type_change, on_api_prompt_type_change, is_disabled])
146+
}, [
147+
params.mode,
148+
params.on_web_prompt_type_change,
149+
params.on_api_prompt_type_change,
150+
params.is_disabled
151+
])
128152

129153
return { is_alt_pressed }
130154
}
Lines changed: 5 additions & 0 deletions
Loading

‎packages/ui/src/components/editor/common/Icon/Icon.tsx‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Claude from '../../../../assets/icons/claude.svg'
66
import CodeWebChatLogo from '../../../../assets/icons/code-web-chat-logo.svg'
77
import CodeWebChatText from '../../../../assets/icons/code-web-chat-text.svg'
88
import Copilot from '../../../../assets/icons/copilot.svg'
9-
import CurlyBraces from '../../../../assets/icons/curly-braces.svg'
9+
import Slash from '../../../../assets/icons/slash.svg'
1010
import DeepSeek from '../../../../assets/icons/deepseek.svg'
1111
import GithubCopilot from '../../../../assets/icons/github-copilot.svg'
1212
import DiscordLogo from '../../../../assets/icons/discord-logo.svg'
@@ -35,7 +35,7 @@ export namespace Icon {
3535
| 'CODE_WEB_CHAT_LOGO'
3636
| 'CODE_WEB_CHAT_TEXT'
3737
| 'COPILOT'
38-
| 'CURLY_BRACES'
38+
| 'SLASH'
3939
| 'DEEPSEEK'
4040
| 'DISCORD'
4141
| 'DOUBAO'
@@ -86,8 +86,8 @@ export const Icon: React.FC<Icon.Props> = ({ variant }) => {
8686
case 'COPILOT':
8787
icon = <Copilot />
8888
break
89-
case 'CURLY_BRACES':
90-
icon = <CurlyBraces />
89+
case 'SLASH':
90+
icon = <Slash />
9191
break
9292
case 'DEEPSEEK':
9393
icon = <DeepSeek />

‎packages/ui/src/components/editor/prompt/prompts/PromptField/PromptField.stories.tsx‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const Empty = () => (
2222
on_hash_sign_click={() => console.log('# clicked')}
2323
on_submit_with_control={() => console.log('Submitted with control')}
2424
selected_files={[]}
25-
on_curly_braces_click={() => {}}
25+
on_slash_click={() => {}}
2626
invocation_count={1}
2727
on_invocation_count_change={(count) =>
2828
console.log('Invocation count changed:', count)
@@ -88,7 +88,7 @@ export const WithText = () => (
8888
on_hash_sign_click={() => console.log('# clicked')}
8989
on_submit_with_control={() => console.log('Submitted with control')}
9090
selected_files={[]}
91-
on_curly_braces_click={() => {}}
91+
on_slash_click={() => {}}
9292
invocation_count={1}
9393
on_invocation_count_change={(count) =>
9494
console.log('Invocation count changed:', count)
@@ -154,7 +154,7 @@ export const LongText = () => (
154154
on_hash_sign_click={() => console.log('# clicked')}
155155
on_submit_with_control={() => console.log('Submitted with control')}
156156
selected_files={[]}
157-
on_curly_braces_click={() => {}}
157+
on_slash_click={() => {}}
158158
invocation_count={1}
159159
on_invocation_count_change={(count) =>
160160
console.log('Invocation count changed:', count)
@@ -225,7 +225,7 @@ export const WithPlaceholderSavedContext = () => (
225225
console.log('Invocation count changed:', count)
226226
}
227227
on_go_to_file={(path) => console.log('Go to file:', path)}
228-
on_curly_braces_click={() => {}}
228+
on_slash_click={() => {}}
229229
on_pasted_lines_click={(path, start, end) =>
230230
console.log('Pasted lines clicked:', path, start, end)
231231
}
@@ -297,7 +297,7 @@ export const WithPlaceholderSelection = () => (
297297
console.log('Invocation count changed:', count)
298298
}
299299
on_go_to_file={(path) => console.log('Go to file:', path)}
300-
on_curly_braces_click={() => {}}
300+
on_slash_click={() => {}}
301301
on_pasted_lines_click={(path, start, end) =>
302302
console.log('Pasted lines clicked:', path, start, end)
303303
}
@@ -363,7 +363,7 @@ export const WithCommit = () => (
363363
console.log('Invocation count changed:', count)
364364
}
365365
on_go_to_file={(path) => console.log('Go to file:', path)}
366-
on_curly_braces_click={() => {}}
366+
on_slash_click={() => {}}
367367
on_pasted_lines_click={(path, start, end) =>
368368
console.log('Pasted lines clicked:', path, start, end)
369369
}
@@ -429,7 +429,7 @@ export const WithCommitWithQuotes = () => (
429429
console.log('Invocation count changed:', count)
430430
}
431431
on_go_to_file={(path) => console.log('Go to file:', path)}
432-
on_curly_braces_click={() => {}}
432+
on_slash_click={() => {}}
433433
on_pasted_lines_click={(path, start, end) =>
434434
console.log('Pasted lines clicked:', path, start, end)
435435
}
@@ -494,7 +494,7 @@ export const WithContextAtCommit = () => (
494494
console.log('Invocation count changed:', count)
495495
}
496496
on_go_to_file={(path) => console.log('Go to file:', path)}
497-
on_curly_braces_click={() => {}}
497+
on_slash_click={() => {}}
498498
on_pasted_lines_click={(path, start, end) =>
499499
console.log('Pasted lines clicked:', path, start, end)
500500
}
@@ -557,7 +557,7 @@ export const WithEditFormatSelector = () => {
557557
on_at_sign_click={() => console.log('@ clicked')}
558558
on_hash_sign_click={() => console.log('# clicked')}
559559
on_submit_with_control={() => console.log('Submitted with control')}
560-
on_curly_braces_click={() => {}}
560+
on_slash_click={() => {}}
561561
show_edit_format_selector={true}
562562
edit_format={edit_format}
563563
on_edit_format_change={(f) => {
@@ -627,7 +627,7 @@ export const WithFilePaths = () => (
627627
on_at_sign_click={() => console.log('@ clicked')}
628628
on_hash_sign_click={() => console.log('# clicked')}
629629
on_submit_with_control={() => console.log('Submitted with control')}
630-
on_curly_braces_click={() => {}}
630+
on_slash_click={() => {}}
631631
on_go_to_file={(path) => console.log('Go to file:', path)}
632632
selected_files={['path/to/my/file.ts']}
633633
invocation_count={1}
@@ -721,7 +721,7 @@ export const WithTabs = () => {
721721
on_at_sign_click={() => console.log('@ clicked')}
722722
on_hash_sign_click={() => console.log('# clicked')}
723723
on_submit_with_control={() => console.log('Submitted with control')}
724-
on_curly_braces_click={() => {}}
724+
on_slash_click={() => {}}
725725
on_go_to_file={(path) => console.log('Go to file:', path)}
726726
selected_files={['path/to/my/file.ts']}
727727
invocation_count={1}
@@ -789,7 +789,7 @@ export const WithWarning = () => (
789789
on_hash_sign_click={() => console.log('# clicked')}
790790
on_submit_with_control={() => console.log('Submitted with control')}
791791
selected_files={[]}
792-
on_curly_braces_click={() => {}}
792+
on_slash_click={() => {}}
793793
invocation_count={1}
794794
on_invocation_count_change={(count) =>
795795
console.log('Invocation count changed:', count)

0 commit comments

Comments
 (0)