Skip to content

Commit 50da87a

Browse files
committed
Improve URL and document paste handling with user confirmation and token count display
1 parent ef3fe0e commit 50da87a

8 files changed

Lines changed: 58 additions & 32 deletions

File tree

‎apps/editor/src/views/panel/backend/message-handlers/handle-paste-url.ts‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as vscode from 'vscode'
12
import { PasteUrlMessage } from '../../types/messages'
23
import { PanelProvider } from '../panel-provider'
34
import * as fs from 'fs'
@@ -10,6 +11,17 @@ export const handle_paste_url = async (
1011
panel_provider: PanelProvider,
1112
message: PasteUrlMessage
1213
) => {
14+
const paste_as_text = async () => {
15+
const selection = await vscode.window.showInformationMessage(
16+
'Failed to parse the website. Place URL instead?',
17+
{ modal: true },
18+
'Yes'
19+
)
20+
if (selection == 'Yes') {
21+
panel_provider.add_text_at_cursor_position(message.url)
22+
}
23+
}
24+
1325
try {
1426
const url = message.url
1527
const file_path = get_website_file_path(url)
@@ -24,9 +36,9 @@ export const handle_paste_url = async (
2436
if (content) {
2537
panel_provider.add_text_at_cursor_position(`#Website(${url})`)
2638
} else {
27-
panel_provider.add_text_at_cursor_position(url)
39+
await paste_as_text()
2840
}
2941
} catch (error) {
30-
panel_provider.add_text_at_cursor_position(message.url)
42+
await paste_as_text()
3143
}
3244
}

‎apps/editor/src/views/panel/backend/message-handlers/handle-save-prompt-document.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ export const handle_save_prompt_document = async (
1515
const filename = `cwc-document-${hash}.txt`
1616
const file_path = path.join(os.tmpdir(), filename)
1717
await fs.promises.writeFile(file_path, message.text, 'utf-8')
18-
panel_provider.add_text_at_cursor_position(`#Document(${hash})`)
18+
const token_count = Math.ceil(message.text.length / 4)
19+
panel_provider.add_text_at_cursor_position(
20+
`#Document(${hash}:${token_count})`
21+
)
1922
} catch (error) {
2023
vscode.window.showErrorMessage(`Failed to save document: ${error}`)
2124
}

‎apps/editor/src/views/panel/backend/panel-provider.ts‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -758,14 +758,9 @@ export class PanelProvider implements vscode.WebviewViewProvider {
758758
) {
759759
await handle_save_prune_context_instructions_prefix(message.prefix)
760760
} else if (message.command == 'UPSERT_CONFIGURATION') {
761-
const tool_type_map: Record<string, string> = {
762-
'edit-context': 'edit-context',
763-
'code-at-cursor': 'code-at-cursor',
764-
'prune-context': 'prune-context'
765-
}
766761
await upsert_configuration({
767762
context: this.context,
768-
tool_type: tool_type_map[message.tool_type] || message.tool_type,
763+
tool_type: message.tool_type,
769764
configuration_id: message.configuration_id,
770765
create_on_top: message.create_on_top,
771766
insertion_index: message.insertion_index

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Preset } from '@shared/types/preset'
55
import { Task } from '@shared/types/task'
66
import { Mode } from './main-view-mode'
77
import { ApiPromptType, WebPromptType } from '@shared/types/prompt-types'
8+
import { ToolType } from '@/views/settings/types/tools'
89

910
export interface BaseMessage {
1011
command: string
@@ -468,7 +469,7 @@ export interface OpenExternalUrlMessage extends BaseMessage {
468469

469470
export interface UpsertConfigurationMessage extends BaseMessage {
470471
command: 'UPSERT_CONFIGURATION'
471-
tool_type: string
472+
tool_type: ToolType
472473
configuration_id?: string
473474
create_on_top?: boolean
474475
insertion_index?: number

‎packages/ui/src/components/editor/panel/PromptField/PromptField.module.scss‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@
265265
}
266266

267267
&--document &__icon::before {
268-
content: '\ec5e';
268+
content: '\eac0';
269269
}
270270

271271
&--document &__text {
@@ -305,7 +305,7 @@
305305
}
306306

307307
&--pasted-lines &__icon::before {
308-
content: '\eb84';
308+
content: '\eac0';
309309
}
310310

311311
&--pasted-lines &__text {

‎packages/ui/src/components/editor/panel/PromptField/hooks/use-handlers.ts‎

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const get_symbol_ranges = (
2121
const ranges: { start: number; end: number }[] = []
2222
// This regex is a combination of all symbol types
2323
const regex =
24-
/`([^\s`]*\.[^\s`]+)`|(#Changes\([^)]+\))|(#Selection)|(#SavedContext\((?:WorkspaceState|JSON) "(?:\\.|[^"\\])*"\))|(#(?:Commit|ContextAtCommit)\([^:]+:[^\s"]+ "(?:\\.|[^"\\])*"\))|(<fragment path="[^"]+"(?: [^>]+)?>[\s\S]*?<\/fragment>)|(#Skill\([^)]+\))|(#Image\([a-fA-F0-9]+\))|(#Document\([a-fA-F0-9]+\))|(#Website\([^)]+\))/g
24+
/`([^\s`]*\.[^\s`]+)`|(#Changes\([^)]+\))|(#Selection)|(#SavedContext\((?:WorkspaceState|JSON) "(?:\\.|[^"\\])*"\))|(#(?:Commit|ContextAtCommit)\([^:]+:[^\s"]+ "(?:\\.|[^"\\])*"\))|(<fragment path="[^"]+"(?: [^>]+)?>[\s\S]*?<\/fragment>)|(#Skill\([^)]+\))|(#Image\([a-fA-F0-9]+\))|(#Document\([a-fA-F0-9]+:\d+\))|(#Website\([^)]+\))/g
2525

2626
let match
2727
while ((match = regex.exec(text)) !== null) {
@@ -77,7 +77,7 @@ const reconstruct_raw_value_from_node = (node: Node): string => {
7777
const contextType = el.dataset.contextType
7878
const contextName = el.dataset.contextName
7979
if (!contextType || !contextName) return ''
80-
const expected_text = `Context "${contextName}"`
80+
const expected_text = `Context "${contextName}`
8181
const index = inner_content.indexOf(expected_text)
8282
if (index != -1) {
8383
const prefix = inner_content.substring(0, index)
@@ -178,14 +178,15 @@ const reconstruct_raw_value_from_node = (node: Node): string => {
178178
}
179179
} else if (el.dataset.type == 'document-symbol') {
180180
const hash = el.dataset.hash
181-
if (!hash) return ''
181+
const token_count = el.dataset.tokenCount
182+
if (!hash || !token_count) return ''
182183

183-
const expected_text = `Document`
184+
const expected_text = `Pasted ${token_count} tokens`
184185
const index = inner_content.indexOf(expected_text)
185186
if (index != -1) {
186187
const prefix = inner_content.substring(0, index)
187188
const suffix = inner_content.substring(index + expected_text.length)
188-
return `${prefix}#Document(${hash})${suffix}`
189+
return `${prefix}#Document(${hash}:${token_count})${suffix}`
189190
}
190191
} else if (el.dataset.type == 'website-symbol') {
191192
const url = el.dataset.url
@@ -456,9 +457,10 @@ export const use_handlers = (
456457
}
457458
} else if (symbol_type == 'document-symbol') {
458459
const hash = symbol_element.dataset.hash
459-
if (!hash) return
460+
const token_count = symbol_element.dataset.tokenCount
461+
if (!hash || !token_count) return
460462

461-
const search_pattern = `#Document(${hash})`
463+
const search_pattern = `#Document(${hash}:${token_count})`
462464
const start_index = props.value.indexOf(search_pattern)
463465

464466
if (start_index != -1) {
@@ -640,14 +642,15 @@ export const use_handlers = (
640642

641643
const text = e.clipboardData.getData('text/plain')
642644

643-
if (/^https?:\/\/[^\s]+$/.test(text.trim())) {
644-
e.preventDefault()
645+
if (
646+
!is_shift_pressed_ref.current &&
647+
/^https?:\/\/[^\s]+$/.test(text.trim())
648+
) {
645649
props.on_paste_url(text.trim())
646650
return
647651
}
648652

649-
if (text.length > 1000) {
650-
e.preventDefault()
653+
if (!is_shift_pressed_ref.current && text.length > 1000) {
651654
props.on_paste_document(text)
652655
return
653656
}
@@ -993,7 +996,9 @@ export const use_handlers = (
993996

994997
const handle_document_symbol_deletion = (raw_pos: number): boolean => {
995998
const text_before_cursor = props.value.substring(0, raw_pos)
996-
const match = text_before_cursor.match(/#Document\(([a-fA-F0-9]+)\)$/)
999+
const match = text_before_cursor.match(
1000+
/#Document\(([a-fA-F0-9]+)(?: (\d+))?\)$/
1001+
)
9971002

9981003
if (match) {
9991004
const start_of_match = raw_pos - match[0].length

‎packages/ui/src/components/editor/panel/PromptField/utils/get-highlighted-text.tsx‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const get_highlighted_text = (params: {
6666

6767
const website_regex_part = '#Website\\([^)]+\\)'
6868

69-
const document_regex_part = '#Document\\([a-fA-F0-9]+\\)'
69+
const document_regex_part = '#Document\\([a-fA-F0-9]+:\\d+\\)'
7070

7171
const regex = new RegExp(
7272
`(${fragment_regex_part}|#Selection|#Changes\\([^)]+\\)|${saved_context_regex_part}|${commit_regex_part}|${skill_regex_part}|${image_regex_part}|${document_regex_part}|${website_regex_part})`,
@@ -243,17 +243,19 @@ export const get_highlighted_text = (params: {
243243
return `<span class="${cn(styles['symbol'], styles['symbol--website'])}" data-type="website-symbol" data-url="${escape_html(url)}" title="${escape_html(url)}"><span class="${styles['symbol__icon']}" data-role="symbol-icon"></span><span class="${styles['symbol__text']}" data-role="symbol-text">${escape_html(label)}</span></span>`
244244
}
245245

246-
const document_match = part.match(/^#Document\(([a-fA-F0-9]+)\)$/)
246+
const document_match = part.match(/^#Document\(([a-fA-F0-9]+):(\d+)\)$/)
247247
if (part && document_match) {
248248
const hash = document_match[1]
249+
const token_count = document_match[2]
250+
const label = `Pasted ${token_count} tokens`
249251
return `<span class="${cn(
250252
styles['symbol'],
251253
styles['symbol--document']
252-
)}" data-type="document-symbol" data-hash="${hash}"><span class="${
254+
)}" data-type="document-symbol" data-hash="${hash}" data-token-count="${token_count}"><span class="${
253255
styles['symbol__icon']
254256
}" data-role="symbol-icon"></span><span class="${
255257
styles['symbol__text']
256-
}" data-role="symbol-text">Document</span></span>`
258+
}" data-role="symbol-text">${escape_html(label)}</span></span>`
257259
}
258260

259261
return process_text_part_for_files({

‎packages/ui/src/components/editor/panel/PromptField/utils/position-mapping.ts‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const map_display_pos_to_raw_pos = (
88
let last_raw_index = 0
99

1010
const regex =
11-
/`([^\s`]*\.[^\s`]+)`|(#Changes\([^)]+\))|(#Selection)|(#SavedContext\((?:WorkspaceState|JSON) "((?:\\.|[^"\\])*)"\))|(#(?:Commit|ContextAtCommit)\([^:]+:([^\s"]+) "(?:\\.|[^"\\])*"\))|(<fragment path="[^"]+"(?: [^>]+)?>([\s\S]*?)<\/fragment>)|(#Skill\([^)]+\))|(#Image\([a-fA-F0-9]+\))|(#Document\([a-fA-F0-9]+\))|(#Website\([^)]+\))/g
11+
/`([^\s`]*\.[^\s`]+)`|(#Changes\([^)]+\))|(#Selection)|(#SavedContext\((?:WorkspaceState|JSON) "((?:\\.|[^"\\])*)"\))|(#(?:Commit|ContextAtCommit)\([^:]+:([^\s"]+) "(?:\\.|[^"\\])*"\))|(<fragment path="[^"]+"(?: [^>]+)?>([\s\S]*?)<\/fragment>)|(#Skill\([^)]+\))|(#Image\([a-fA-F0-9]+\))|(#Document\([a-fA-F0-9]+:\d+\))|(#Website\([^)]+\))/g
1212
let match
1313

1414
while ((match = regex.exec(raw_text)) !== null) {
@@ -81,7 +81,11 @@ export const map_display_pos_to_raw_pos = (
8181
display_match_length = 'Image'.length
8282
is_replacement_match = true
8383
} else if (document_symbol) {
84-
display_match_length = 'Document'.length
84+
const match = document_symbol.match(/^#Document\(([a-fA-F0-9]+):(\d+)\)$/)
85+
const token_count = match ? match[2] : null
86+
display_match_length = token_count
87+
? `Pasted ${token_count} tokens`.length
88+
: 0
8589
is_replacement_match = true
8690
} else if (website_symbol) {
8791
const url = website_symbol.slice(9, -1)
@@ -137,7 +141,7 @@ export const map_raw_pos_to_display_pos = (
137141
let last_raw_index = 0
138142

139143
const regex =
140-
/`([^\s`]*\.[^\s`]+)`|(#Changes\([^)]+\))|(#Selection)|(#SavedContext\((?:WorkspaceState|JSON) "((?:\\.|[^"\\])*)"\))|(#(?:Commit|ContextAtCommit)\([^:]+:([^\s"]+) "(?:\\.|[^"\\])*"\))|(<fragment path="[^"]+"(?: [^>]+)?>([\s\S]*?)<\/fragment>)|(#Skill\([^)]+\))|(#Image\([a-fA-F0-9]+\))|(#Document\([a-fA-F0-9]+\))|(#Website\([^)]+\))/g
144+
/`([^\s`]*\.[^\s`]+)`|(#Changes\([^)]+\))|(#Selection)|(#SavedContext\((?:WorkspaceState|JSON) "((?:\\.|[^"\\])*)"\))|(#(?:Commit|ContextAtCommit)\([^:]+:([^\s"]+) "(?:\\.|[^"\\])*"\))|(<fragment path="[^"]+"(?: [^>]+)?>([\s\S]*?)<\/fragment>)|(#Skill\([^)]+\))|(#Image\([a-fA-F0-9]+\))|(#Document\([a-fA-F0-9]+:\d+\))|(#Website\([^)]+\))/g
141145
let match
142146

143147
while ((match = regex.exec(raw_text)) !== null) {
@@ -210,7 +214,11 @@ export const map_raw_pos_to_display_pos = (
210214
display_match_length = 'Image'.length
211215
is_replacement_match = true
212216
} else if (document_symbol) {
213-
display_match_length = 'Document'.length
217+
const match = document_symbol.match(/^#Document\(([a-fA-F0-9]+):(\d+)\)$/)
218+
const token_count = match ? match[2] : null
219+
display_match_length = token_count
220+
? `Pasted ${token_count} tokens`.length
221+
: 0
214222
is_replacement_match = true
215223
} else if (website_symbol) {
216224
const url = website_symbol.slice(9, -1)

0 commit comments

Comments
 (0)