Skip to content

Commit cbfc277

Browse files
committed
Enable hash sign quick pick and symbol insertion in template editor form
- current behavior: in prompt view, user can insert hash sign symbols. expected behavior: such symbols can be idenically inserted in settings>prompt>templates. - place the root logic of `apps/editor/src/views/prompt/backend/message-handlers/handle-hash-sign-quick-pick/handle-hash-sign-quick-pick.ts` and`apps/editor/src/views/settings/backend/message-handlers/handle-hash-sign-quick-pick.ts` in `apps/editor/src/views/shared/utils` ├── apps │ └── editor │ └── src │ ├── i18n │ │ └── translations │ │ └── views │ │ ├── prompt │ │ │ └── handlers │ │ │ ├── handle-template-quick-pick.ts │ │ │ └── index.ts │ │ └── settings │ │ └── handlers │ │ └── index.ts │ ├── migrations │ │ ├── migrate-prompt-templates-suffixes.ts │ │ └── migrate-prompt-templates-to-templates.ts │ └── views │ ├── prompt │ │ ├── backend │ │ │ ├── message-handlers │ │ │ │ ├── handle-hash-sign-quick-pick.ts │ │ │ │ ├── handle-template-quick-pick.ts │ │ │ │ └── index.ts │ │ │ ├── prompt-view-provider.ts │ │ │ └── utils │ │ │ └── symbols │ │ │ ├── replace-symbols.ts │ │ │ └── skill │ │ │ └── replace-skill-symbol.ts │ │ ├── frontend │ │ │ ├── Main │ │ │ │ ├── Main.tsx │ │ │ │ └── MainView │ │ │ │ └── MainView.tsx │ │ │ ├── hooks │ │ │ │ └── use-prompt │ │ │ │ └── use-prompt.ts │ │ │ └── i18n │ │ │ └── translations │ │ │ └── prompt-field.ts │ │ └── types │ │ └── messages.ts │ ├── settings │ │ ├── backend │ │ │ ├── message-handlers │ │ │ │ ├── handle-create-template.ts │ │ │ │ ├── handle-delete-template.ts │ │ │ │ ├── handle-get-templates.ts │ │ │ │ ├── handle-hash-sign-quick-pick.ts │ │ │ │ ├── handle-update-templates.ts │ │ │ │ └── index.ts │ │ │ └── settings-view-provider.ts │ │ ├── frontend │ │ │ ├── Home │ │ │ │ ├── Home.tsx │ │ │ │ └── sections │ │ │ │ └── GeneralSection.tsx │ │ │ ├── Settings.tsx │ │ │ ├── forms │ │ │ │ └── EditTemplateForm │ │ │ │ ├── EditTemplateForm.module.scss │ │ │ │ ├── EditTemplateForm.tsx │ │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ │ └── use-settings.ts │ │ │ └── i18n │ │ │ └── translations │ │ │ ├── edit-template-form.ts │ │ │ ├── general.ts │ │ │ └── index.ts │ │ ├── helpers │ │ │ └── open-settings.ts │ │ └── types │ │ └── messages.ts │ └── shared │ ├── actions │ │ ├── agent │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── pick-agent.ts │ │ │ ├── reorder.ts │ │ │ ├── toggle-pinned.ts │ │ │ └── update.ts │ │ ├── api │ │ │ ├── create │ │ │ │ ├── create.ts │ │ │ │ └── interactions │ │ │ │ ├── index.ts │ │ │ │ ├── initial-select-model.ts │ │ │ │ ├── initial-select-provider.ts │ │ │ │ ├── verify-model.ts │ │ │ │ └── verify-reasoning-effort.ts │ │ │ ├── delete.ts │ │ │ ├── pick-reasoning-effort.ts │ │ │ ├── reorder.ts │ │ │ └── update │ │ │ ├── interactions │ │ │ │ ├── edit-model-for-api-config.ts │ │ │ │ ├── edit-provider-for-api-config.ts │ │ │ │ ├── edit-reasoning-effort-for-api-config.ts │ │ │ │ └── index.ts │ │ │ └── update.ts │ │ └── web │ │ ├── create.ts │ │ ├── delete.ts │ │ ├── pick-chatbot.ts │ │ ├── pick-model.ts │ │ ├── reorder.ts │ │ ├── toggle-pinned.ts │ │ └── update.ts │ ├── forms │ │ ├── EditApiConfigurationForm │ │ │ ├── EditApiConfigurationForm.module.scss │ │ │ ├── EditApiConfigurationForm.tsx │ │ │ └── index.ts │ │ ├── EditCliConfigurationForm │ │ │ ├── EditCliConfigurationForm.module.scss │ │ │ ├── EditCliConfigurationForm.tsx │ │ │ └── index.ts │ │ └── EditWebConfigurationForm │ │ ├── EditWebConfigurationForm.module.scss │ │ ├── EditWebConfigurationForm.tsx │ │ └── index.ts │ ├── hooks │ │ └── use-translation.tsx │ ├── i18n │ │ ├── translations │ │ │ ├── common.ts │ │ │ ├── edit-api-configuration-form.ts │ │ │ ├── edit-cli-configuration-form.ts │ │ │ ├── edit-web-configuration-form.ts │ │ │ └── index.ts │ │ └── use-translation.tsx │ ├── types │ │ └── api-features.ts │ └── utils │ ├── generate-unique-name.ts │ ├── hash-sign-quick-pick │ │ ├── hash-sign-quick-pick.ts │ │ ├── index.ts │ │ └── symbols │ │ ├── changes-symbol.ts │ │ ├── commit-symbol.ts │ │ ├── index.ts │ │ ├── saved-context-symbol.ts │ │ └── skill-symbol.ts │ └── webview-html.ts └── packages └── ui └── src └── components └── editor ├── common │ ├── Icon │ │ └── Icon.tsx │ └── prompts │ ├── PromptField │ │ ├── PromptField.module.scss │ │ ├── PromptField.tsx │ │ ├── components │ │ │ └── Footer │ │ │ └── Footer.tsx │ │ └── hooks │ │ └── use-handlers │ │ ├── handle-input-change.ts │ │ └── handle-input-click.ts │ ├── Template │ │ ├── Template.module.scss │ │ ├── Template.tsx │ │ └── index.ts │ └── shared │ └── symbols │ ├── caret.ts │ ├── get-highlighted-text.tsx │ ├── index.ts │ ├── position-mapping.ts │ ├── prompt-symbols.module.scss │ ├── reconstruct-raw-value.ts │ └── use-symbol-deletion.ts └── settings-view └── Templates ├── Templates.module.scss ├── Templates.tsx └── index.ts
1 parent 2c12397 commit cbfc277

18 files changed

Lines changed: 161 additions & 50 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import * as vscode from 'vscode'
2+
import { PromptViewProvider } from '@/views/prompt/backend/prompt-view-provider'
3+
import { hash_sign_quick_pick } from '@/views/shared/utils/hash-sign-quick-pick'
4+
5+
export const handle_hash_sign_quick_pick = async (
6+
prompt_view_provider: PromptViewProvider,
7+
extension_context: vscode.ExtensionContext
8+
): Promise<void> => {
9+
let first_insert = true
10+
11+
const on_insert = (replacement: string) => {
12+
if (first_insert) {
13+
const current_text = prompt_view_provider.current_instructions
14+
const is_after_hash_sign = current_text
15+
.slice(0, prompt_view_provider.caret_position)
16+
.endsWith('#')
17+
if (is_after_hash_sign) {
18+
prompt_view_provider.add_text_at_cursor_position(replacement, 1)
19+
} else {
20+
prompt_view_provider.add_text_at_cursor_position(replacement)
21+
}
22+
first_insert = false
23+
} else {
24+
prompt_view_provider.add_text_at_cursor_position(replacement)
25+
}
26+
}
27+
28+
const replacement = await hash_sign_quick_pick({
29+
extension_context,
30+
on_insert
31+
})
32+
33+
if (replacement) {
34+
on_insert(replacement)
35+
}
36+
37+
prompt_view_provider.send_message({
38+
command: 'FOCUS_PROMPT_FIELD'
39+
})
40+
}

‎apps/editor/src/views/prompt/backend/message-handlers/handle-hash-sign-quick-pick/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎apps/editor/src/views/prompt/backend/utils/symbols/skill/replace-skill-symbol.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Logger } from '@shared/utils/logger'
44
import {
55
agents,
66
discover_skills
7-
} from '../../../message-handlers/handle-hash-sign-quick-pick/symbols/skill-symbol'
7+
} from '@/views/shared/utils/hash-sign-quick-pick/symbols/skill-symbol'
88
import { normalize_path } from '@/utils/normalize-path'
99
import { SymbolCacheManager } from '../symbol-cache'
1010

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { SettingsViewProvider } from '../settings-view-provider'
2+
import { hash_sign_quick_pick } from '@/views/shared/utils/hash-sign-quick-pick'
3+
4+
export const handle_hash_sign_quick_pick = async (
5+
provider: SettingsViewProvider
6+
): Promise<void> => {
7+
const on_insert = (text: string) => {
8+
provider.postMessage({
9+
command: 'INSERT_SYMBOL',
10+
text
11+
})
12+
}
13+
14+
const replacement = await hash_sign_quick_pick({
15+
extension_context: provider.extension_context,
16+
on_insert
17+
})
18+
19+
if (replacement) {
20+
on_insert(replacement)
21+
}
22+
}

‎apps/editor/src/views/settings/backend/message-handlers/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './handle-hash-sign-quick-pick'
12
export * from './handle-get-templates'
23
export * from './handle-update-templates'
34
export * from './handle-create-template'

‎apps/editor/src/views/settings/backend/settings-view-provider.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ import {
6969
handle_get_is_modern_ui,
7070
handle_set_default_cli_configuration,
7171
handle_select_default_cli_configuration,
72-
handle_open_editor_settings
72+
handle_open_editor_settings,
73+
handle_hash_sign_quick_pick
7374
} from './message-handlers'
7475
import { webview_html } from '@/views/shared/utils/webview-html'
7576

@@ -143,6 +144,8 @@ export class SettingsViewProvider {
143144
await handle_delete_provider(this, message)
144145
} else if (message.command == 'UPDATE_PROVIDER') {
145146
await handle_update_provider(this, message)
147+
} else if (message.command == 'SHOW_HASH_SIGN_QUICK_PICK') {
148+
await handle_hash_sign_quick_pick(this)
146149
} else if (message.command == 'GET_TEMPLATES') {
147150
await handle_get_templates(this)
148151
} else if (message.command == 'UPDATE_TEMPLATES') {

‎apps/editor/src/views/settings/frontend/Settings.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ export const Settings = () => {
477477
<EditTemplateForm
478478
template={updating_template.template}
479479
on_update={set_updated_template}
480+
vscode={vscode}
480481
/>
481482
</UiModal.Form>
482483
</UiModal>

‎apps/editor/src/views/settings/frontend/forms/EditTemplateForm/EditTemplateForm.tsx‎

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1-
import { useState, useEffect } from 'react'
1+
import { useState, useEffect, useRef } from 'react'
22
import styles from './EditTemplateForm.module.scss'
33
import { Field as UiField } from '@ui/components/editor/common/Field'
44
import { Input as UiInput } from '@ui/components/editor/common/Input'
5-
import { Textarea as UiTextarea } from '@ui/components/editor/common/Textarea'
5+
import {
6+
Template as UiTemplate,
7+
TemplateHandle
8+
} from '@ui/components/editor/common/prompts/Template'
69
import { Scrollable as UiScrollable } from '@ui/components/editor/common/Scrollable'
710
import { Fieldset as UiFieldset } from '@ui/components/editor/prompt-view/Fieldset'
811
import { use_translation } from '../../i18n/use-translation'
9-
import { Template } from '@/views/settings/types/messages'
12+
import { Template, BackendMessage } from '@/views/settings/types/messages'
13+
import { post_message } from '../../utils/post-message'
1014

1115
type Props = {
1216
template: Template
1317
on_update: (draft: Template) => void
18+
vscode: any
1419
}
1520

1621
export const EditTemplateForm: React.FC<Props> = (props) => {
1722
const { t } = use_translation()
1823
const [name, set_name] = useState(props.template.name || '')
1924
const [template, set_template] = useState(props.template.template)
25+
const template_ref = useRef<TemplateHandle>(null)
26+
const [first_insert, set_first_insert] = useState(true)
2027

2128
useEffect(() => {
2229
props.on_update({
@@ -25,6 +32,39 @@ export const EditTemplateForm: React.FC<Props> = (props) => {
2532
})
2633
}, [name, template, props.on_update])
2734

35+
useEffect(() => {
36+
const handle_message = (event: MessageEvent<BackendMessage>) => {
37+
if (event.data.command == 'INSERT_SYMBOL') {
38+
const text = event.data.text
39+
if (template_ref.current) {
40+
const caret_pos = template_ref.current.get_caret_position()
41+
let new_caret_pos = caret_pos
42+
43+
set_template((prev) => {
44+
let before = prev.slice(0, caret_pos)
45+
const after = prev.slice(caret_pos)
46+
47+
if (first_insert && before.endsWith('#')) {
48+
before = before.slice(0, -1)
49+
}
50+
51+
new_caret_pos = before.length + text.length
52+
set_first_insert(false)
53+
54+
return before + text + after
55+
})
56+
57+
setTimeout(() => {
58+
template_ref.current?.focus()
59+
template_ref.current?.set_caret_position(new_caret_pos)
60+
}, 10)
61+
}
62+
}
63+
}
64+
window.addEventListener('message', handle_message)
65+
return () => window.removeEventListener('message', handle_message)
66+
}, [first_insert])
67+
2868
return (
2969
<UiScrollable top_shadow>
3070
<div className={styles.form}>
@@ -43,12 +83,19 @@ export const EditTemplateForm: React.FC<Props> = (props) => {
4383
label={t('edit-template-form.template.label')}
4484
html_for="template"
4585
>
46-
<UiTextarea
86+
<UiTemplate
4787
id="template"
88+
ref={template_ref}
4889
value={template}
49-
min_rows={3}
50-
on_change={set_template}
5190
placeholder={t('edit-template-form.template.placeholder')}
91+
on_change={set_template}
92+
on_focus={() => {}}
93+
on_insert_symbol_click={() => {
94+
set_first_insert(true)
95+
post_message(props.vscode, {
96+
command: 'SHOW_HASH_SIGN_QUICK_PICK'
97+
})
98+
}}
5299
/>
53100
</UiField>
54101
</UiFieldset>

‎apps/editor/src/views/settings/types/messages.ts‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,10 @@ export interface DeleteTemplateMessage {
356356
index: number
357357
}
358358

359+
export interface ShowHashSignQuickPickMessage {
360+
command: 'SHOW_HASH_SIGN_QUICK_PICK'
361+
}
362+
359363
export interface GetIsModernUiMessage {
360364
command: 'GET_IS_MODERN_UI'
361365
}
@@ -420,6 +424,7 @@ export type FrontendMessage =
420424
| UpdateTemplatesMessage
421425
| CreateTemplateMessage
422426
| DeleteTemplateMessage
427+
| ShowHashSignQuickPickMessage
423428
| GetAgentConfigurationsMessage
424429
| ReorderAgentConfigurationsMessage
425430
| DeleteAgentConfigurationMessage
@@ -623,6 +628,11 @@ export interface StartTemplateCreationMessage {
623628
insertion_index?: number
624629
}
625630

631+
export interface InsertSymbolMessage {
632+
command: 'INSERT_SYMBOL'
633+
text: string
634+
}
635+
626636
export type BackendMessage =
627637
| ProvidersMessage
628638
| ApiConfigurationsMessage
@@ -655,6 +665,7 @@ export type BackendMessage =
655665
| IsModernUiMessage
656666
| TemplatesMessage
657667
| StartTemplateCreationMessage
668+
| InsertSymbolMessage
658669
| AgentConfigurationsMessage
659670
| AgentConfigurationUpdatedMessage
660671
| StartAgentConfigurationCreationMessage

apps/editor/src/views/prompt/backend/message-handlers/handle-hash-sign-quick-pick/handle-hash-sign-quick-pick.ts renamed to apps/editor/src/views/shared/utils/hash-sign-quick-pick/hash-sign-quick-pick.ts

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as vscode from 'vscode'
22
import { t } from '@/i18n'
3-
import { PromptViewProvider } from '@/views/prompt/backend/prompt-view-provider'
43
import { LAST_SELECTED_SYMBOL_STATE_KEY } from '@/constants/state-keys'
54
import {
65
handle_changes_item,
@@ -14,7 +13,7 @@ const commit_label = `$(git-commit) ${t('views.prompt.handlers.handle-hash-sign-
1413
const saved_context_label = `$(checklist) ${t('views.prompt.handlers.handle-hash-sign-quick-pick.quick-pick.saved-context.label')}`
1514
const skill_label = `$(thinking) ${t('views.prompt.handlers.handle-hash-sign-quick-pick.quick-pick.skill.label')}`
1615

17-
const hash_sign_quick_pick = async (params: {
16+
export const hash_sign_quick_pick = async (params: {
1817
extension_context: vscode.ExtensionContext
1918
on_insert: (text: string) => void
2019
}): Promise<string | undefined> => {
@@ -149,40 +148,3 @@ const hash_sign_quick_pick = async (params: {
149148
return result
150149
}
151150
}
152-
153-
export const handle_hash_sign_quick_pick = async (
154-
prompt_view_provider: PromptViewProvider,
155-
extension_context: vscode.ExtensionContext
156-
): Promise<void> => {
157-
let first_insert = true
158-
159-
const on_insert = (replacement: string) => {
160-
if (first_insert) {
161-
const current_text = prompt_view_provider.current_instructions
162-
const is_after_hash_sign = current_text
163-
.slice(0, prompt_view_provider.caret_position)
164-
.endsWith('#')
165-
if (is_after_hash_sign) {
166-
prompt_view_provider.add_text_at_cursor_position(replacement, 1)
167-
} else {
168-
prompt_view_provider.add_text_at_cursor_position(replacement)
169-
}
170-
first_insert = false
171-
} else {
172-
prompt_view_provider.add_text_at_cursor_position(replacement)
173-
}
174-
}
175-
176-
const replacement = await hash_sign_quick_pick({
177-
extension_context,
178-
on_insert
179-
})
180-
181-
if (replacement) {
182-
on_insert(replacement)
183-
}
184-
185-
prompt_view_provider.send_message({
186-
command: 'FOCUS_PROMPT_FIELD'
187-
})
188-
}

0 commit comments

Comments
 (0)