diff --git a/packages/electron/main.mjs b/packages/electron/main.mjs index d82fbb3b..31731358 100644 --- a/packages/electron/main.mjs +++ b/packages/electron/main.mjs @@ -4559,6 +4559,7 @@ const buildMacMenu = () => { { type: 'separator' }, { role: 'cut' }, { label: 'Copy', accelerator: 'Cmd+C', click: () => handleCopyAction() }, + { label: 'Add Selection to Chat', accelerator: 'Cmd+L', registerAccelerator: false, click: () => dispatchAction('add-selection-to-chat') }, { role: 'paste' }, { role: 'selectAll' }, ], @@ -4577,7 +4578,7 @@ const buildMacMenu = () => { { label: 'Dark Theme', click: () => dispatchAction('theme-dark') }, { label: 'System Theme', click: () => dispatchAction('theme-system') }, { type: 'separator' }, - { label: 'Toggle Session Sidebar', accelerator: 'Cmd+L', click: () => dispatchAction('toggle-sidebar') }, + { label: 'Toggle Session Sidebar', accelerator: 'Cmd+Alt+L', click: () => dispatchAction('toggle-sidebar') }, { label: 'Toggle Memory Debug', accelerator: 'Cmd+Shift+D', click: () => dispatchAction('toggle-memory-debug') }, { type: 'separator' }, { role: 'togglefullscreen' }, @@ -4656,6 +4657,7 @@ const buildAutoHiddenMenu = () => { { type: 'separator' }, { role: 'cut' }, { label: 'Copy', accelerator: 'Ctrl+C', click: () => handleCopyAction() }, + { label: 'Add Selection to Chat', accelerator: 'Ctrl+L', registerAccelerator: false, click: () => dispatchAction('add-selection-to-chat') }, { role: 'paste' }, { role: 'selectAll' }, ], @@ -4678,7 +4680,7 @@ const buildAutoHiddenMenu = () => { { label: 'Dark Theme', click: () => dispatchAction('theme-dark') }, { label: 'System Theme', click: () => dispatchAction('theme-system') }, { type: 'separator' }, - { label: 'Toggle Session Sidebar', accelerator: 'Ctrl+L', click: () => dispatchAction('toggle-sidebar') }, + { label: 'Toggle Session Sidebar', accelerator: 'Ctrl+Alt+L', click: () => dispatchAction('toggle-sidebar') }, { label: 'Toggle Memory Debug', accelerator: 'Ctrl+Shift+D', click: () => dispatchAction('toggle-memory-debug') }, { type: 'separator' }, { role: 'togglefullscreen' }, diff --git a/packages/ui/src/components/chat/message/TextSelectionMenu.tsx b/packages/ui/src/components/chat/message/TextSelectionMenu.tsx index b8d1486c..3bac2934 100644 --- a/packages/ui/src/components/chat/message/TextSelectionMenu.tsx +++ b/packages/ui/src/components/chat/message/TextSelectionMenu.tsx @@ -16,6 +16,8 @@ import { useEffectiveDirectory } from '@/hooks/useEffectiveDirectory'; import { isVSCodeRuntime } from '@/lib/desktop'; import { useI18n } from '@/lib/i18n'; import { rangeToMarkdown, trimSelectionValue, wrapMarkdownSelectionForChat } from './selectionMarkdown'; +import { formatShortcutForDisplay, getEffectiveShortcutCombo } from '@/lib/shortcuts'; +import { focusChatInput } from '@/components/chat/composer/editor/dom'; interface TextSelectionMenuProps { containerRef: React.RefObject; @@ -63,6 +65,11 @@ export const TextSelectionMenu: React.FC = ({ containerR const currentSessionId = useSessionUIStore((state) => state.currentSessionId); const setPendingInputText = useInputStore((state) => state.setPendingInputText); const isMobile = useUIStore((state) => state.isMobile); + const shortcutOverrides = useUIStore((state) => state.shortcutOverrides); + const addToChatShortcut = React.useMemo( + () => formatShortcutForDisplay(getEffectiveShortcutCombo('add_selection_to_chat', shortcutOverrides)), + [shortcutOverrides], + ); const projects = useProjectsStore((state) => state.projects); const availableWorktreesByProject = useSessionUIStore((state) => state.availableWorktreesByProject); const effectiveDirectory = useEffectiveDirectory(); @@ -309,6 +316,9 @@ export const TextSelectionMenu: React.FC = ({ containerR // Clear selection window.getSelection()?.removeAllRanges(); + queueMicrotask(() => { + focusChatInput(); + }); }, [selectedTextMarkdown, setPendingInputText, hideMenu]); const handleCreateNewSession = React.useCallback(async () => { @@ -415,7 +425,9 @@ export const TextSelectionMenu: React.FC = ({ containerR 'active:opacity-80', 'transition-opacity duration-150' )} - title={t('chat.textSelection.title.addToCurrentChat')} + title={addToChatShortcut + ? `${t('chat.textSelection.title.addToCurrentChat')} (${addToChatShortcut})` + : t('chat.textSelection.title.addToCurrentChat')} type="button" > @@ -508,11 +520,16 @@ export const TextSelectionMenu: React.FC = ({ containerR 'hover:bg-[var(--interactive-hover)]', 'transition-colors duration-150' )} - title={t('chat.textSelection.title.addToCurrentChat')} + title={addToChatShortcut + ? `${t('chat.textSelection.title.addToCurrentChat')} (${addToChatShortcut})` + : t('chat.textSelection.title.addToCurrentChat')} type="button" > {t('chat.textSelection.actions.addToChat')} + {addToChatShortcut ? ( + {addToChatShortcut} + ) : null}
diff --git a/packages/ui/src/components/ui/HelpDialog.tsx b/packages/ui/src/components/ui/HelpDialog.tsx index f74b9ee6..027e8833 100644 --- a/packages/ui/src/components/ui/HelpDialog.tsx +++ b/packages/ui/src/components/ui/HelpDialog.tsx @@ -65,6 +65,12 @@ export const HelpDialog: React.FC = () => { icon: "layout-left", keys: '', }, + { + id: 'add_selection_to_chat', + descriptionKey: "helpDialog.item.addSelectionToChat", + icon: "add", + keys: '', + }, { id: 'cycle_agent', keys: '', diff --git a/packages/ui/src/hooks/useKeyboardShortcuts.ts b/packages/ui/src/hooks/useKeyboardShortcuts.ts index c3f5a6f4..87cabf01 100644 --- a/packages/ui/src/hooks/useKeyboardShortcuts.ts +++ b/packages/ui/src/hooks/useKeyboardShortcuts.ts @@ -16,6 +16,7 @@ import { useDirectoryStore } from '@/stores/useDirectoryStore'; import { useProjectsStore } from '@/stores/useProjectsStore'; import { getCycledPrimaryAgentName } from '@/components/chat/mobileControlsUtils'; import { focusChatInput } from '@/components/chat/composer/editor/dom'; +import { addSelectionToChat } from '@/lib/addSelectionToChat'; import { hasOpenDropdown } from './keyboard-shortcut-dom'; export const useKeyboardShortcuts = () => { @@ -337,6 +338,12 @@ export const useKeyboardShortcuts = () => { return; } + if (eventMatchesShortcut(e, combo('add_selection_to_chat'))) { + e.preventDefault(); + addSelectionToChat(); + return; + } + if (eventMatchesShortcut(e, combo('toggle_sidebar'))) { e.preventDefault(); const { isMobile, isSessionSwitcherOpen } = useUIStore.getState(); diff --git a/packages/ui/src/hooks/useMenuActions.ts b/packages/ui/src/hooks/useMenuActions.ts index 6b6abc09..d74243ec 100644 --- a/packages/ui/src/hooks/useMenuActions.ts +++ b/packages/ui/src/hooks/useMenuActions.ts @@ -10,6 +10,7 @@ import { useThemeSystem } from '@/contexts/useThemeSystem'; import { sessionEvents } from '@/lib/sessionEvents'; import { createWorktreeSession } from '@/lib/worktreeSessionCreator'; import { showOpenCodeStatus } from '@/lib/openCodeStatus'; +import { addSelectionToChat } from '@/lib/addSelectionToChat'; const getActiveElementSelectedText = (): string => { if (typeof document === 'undefined') { @@ -77,6 +78,7 @@ type MenuAction = | 'toggle-terminal' | 'toggle-terminal-expanded' | 'copy' + | 'add-selection-to-chat' | 'theme-light' | 'theme-dark' | 'theme-system' @@ -278,6 +280,10 @@ export const useMenuActions = ( setThemeMode('system'); break; + case 'add-selection-to-chat': + addSelectionToChat(); + break; + case 'toggle-sidebar': toggleSidebar(); break; diff --git a/packages/ui/src/lib/addSelectionToChat.test.ts b/packages/ui/src/lib/addSelectionToChat.test.ts new file mode 100644 index 00000000..c95cf09f --- /dev/null +++ b/packages/ui/src/lib/addSelectionToChat.test.ts @@ -0,0 +1,137 @@ +import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'; + +const focusChatInputCalls: number[] = []; +const pendingInputCalls: Array<{ text: string | null; mode?: string }> = []; +const activeMainTabCalls: string[] = []; +const sessionSwitcherCalls: boolean[] = []; + +mock.module('@/components/chat/composer/editor/dom', () => ({ + focusChatInput: () => { + focusChatInputCalls.push(1); + }, +})); + +mock.module('@/sync/input-store', () => ({ + useInputStore: { + getState: () => ({ + setPendingInputText: (text: string | null, mode?: string) => { + pendingInputCalls.push({ text, mode }); + }, + }), + }, +})); + +mock.module('@/stores/useUIStore', () => ({ + useUIStore: { + getState: () => ({ + setActiveMainTab: (tab: string) => { + activeMainTabCalls.push(tab); + }, + setSessionSwitcherOpen: (open: boolean) => { + sessionSwitcherCalls.push(open); + }, + }), + }, +})); + +const { addSelectionToChat, captureSelectionMarkdownForChat } = await import('./addSelectionToChat'); + +const originalDocument = globalThis.document; +const originalWindow = globalThis.window; + +const installEmptySelectionEnvironment = (activeElement: Element | null = null) => { + const documentLike = { + activeElement, + querySelector: () => null, + }; + const windowLike = { + getSelection: () => null, + }; + Object.defineProperty(globalThis, 'document', { value: documentLike, configurable: true }); + Object.defineProperty(globalThis, 'window', { value: windowLike, configurable: true }); +}; + +const clearCalls = () => { + focusChatInputCalls.length = 0; + pendingInputCalls.length = 0; + activeMainTabCalls.length = 0; + sessionSwitcherCalls.length = 0; +}; + +afterEach(() => { + Object.defineProperty(globalThis, 'document', { value: originalDocument, configurable: true }); + Object.defineProperty(globalThis, 'window', { value: originalWindow, configurable: true }); +}); + +describe('captureSelectionMarkdownForChat', () => { + beforeEach(() => { + clearCalls(); + }); + + test('returns null when nothing is selected', () => { + installEmptySelectionEnvironment(); + expect(captureSelectionMarkdownForChat()).toBeNull(); + }); + + test('captures a textarea selection outside the composer', () => { + const textarea = { + tagName: 'TEXTAREA', + value: 'alpha beta gamma', + selectionStart: 6, + selectionEnd: 10, + closest: () => null, + } as unknown as HTMLTextAreaElement; + + installEmptySelectionEnvironment(textarea); + expect(captureSelectionMarkdownForChat()).toBe('```md\nbeta\n```'); + }); + + test('ignores selections inside the chat composer', () => { + const textarea = { + tagName: 'TEXTAREA', + value: 'draft text', + selectionStart: 0, + selectionEnd: 5, + closest: (selector: string) => (selector === '[data-chat-input="true"]' ? textarea : null), + } as unknown as HTMLTextAreaElement; + + installEmptySelectionEnvironment(textarea); + expect(captureSelectionMarkdownForChat()).toBeNull(); + }); +}); + +describe('addSelectionToChat', () => { + beforeEach(() => { + clearCalls(); + }); + + test('appends captured selection and focuses chat input', async () => { + const textarea = { + tagName: 'TEXTAREA', + value: 'selected', + selectionStart: 0, + selectionEnd: 8, + closest: () => null, + } as unknown as HTMLTextAreaElement; + installEmptySelectionEnvironment(textarea); + + expect(addSelectionToChat()).toBe(true); + expect(activeMainTabCalls).toEqual(['chat']); + expect(sessionSwitcherCalls).toEqual([false]); + expect(pendingInputCalls).toEqual([{ text: '```md\nselected\n```', mode: 'append' }]); + + await Promise.resolve(); + expect(focusChatInputCalls.length).toBe(1); + }); + + test('focuses chat input when nothing is selected', async () => { + installEmptySelectionEnvironment(); + + expect(addSelectionToChat()).toBe(false); + expect(pendingInputCalls).toEqual([]); + expect(activeMainTabCalls).toEqual(['chat']); + + await Promise.resolve(); + expect(focusChatInputCalls.length).toBe(1); + }); +}); diff --git a/packages/ui/src/lib/addSelectionToChat.ts b/packages/ui/src/lib/addSelectionToChat.ts new file mode 100644 index 00000000..6fc8c1ad --- /dev/null +++ b/packages/ui/src/lib/addSelectionToChat.ts @@ -0,0 +1,153 @@ +import { EditorView } from '@codemirror/view'; +import { focusChatInput } from '@/components/chat/composer/editor/dom'; +import { + formatCodeSelectionMarkdown, + rangeToMarkdown, + trimSelectionValue, + wrapMarkdownSelectionForChat, +} from '@/components/chat/message/selectionMarkdown'; +import { useInputStore } from '@/sync/input-store'; +import { useUIStore } from '@/stores/useUIStore'; + +const CHAT_INPUT_HOST_SELECTOR = '[data-chat-input="true"]'; + +const isInsideChatComposer = (node: Node | null): boolean => { + if (!node) { + return false; + } + const asElement = node as Element; + const element = typeof asElement.closest === 'function' + ? asElement + : (node as Node).parentElement; + return Boolean(element?.closest(CHAT_INPUT_HOST_SELECTOR)); +}; + +const readTextControlSelection = (element: Element): string | null => { + if (isInsideChatComposer(element)) { + return null; + } + + const tag = element.tagName?.toLowerCase(); + if (tag === 'textarea') { + const control = element as HTMLTextAreaElement; + return trimSelectionValue( + control.value.slice(control.selectionStart ?? 0, control.selectionEnd ?? 0), + ) || null; + } + + if (tag === 'input') { + const control = element as HTMLInputElement; + const type = control.type?.toLowerCase() ?? 'text'; + if (!['text', 'search', 'url', 'tel', 'password'].includes(type)) { + return null; + } + return trimSelectionValue( + control.value.slice(control.selectionStart ?? 0, control.selectionEnd ?? 0), + ) || null; + } + + return null; +}; + +const captureActiveElementSelection = (): string | null => { + if (typeof document === 'undefined') { + return null; + } + + const activeElement = document.activeElement; + if (!activeElement || typeof (activeElement as Element).tagName !== 'string') { + return null; + } + + const text = readTextControlSelection(activeElement as Element); + return text ? wrapMarkdownSelectionForChat(text) : null; +}; + +const captureCodeMirrorSelection = (): string | null => { + if (typeof document === 'undefined') { + return null; + } + + const focusedEditor = document.querySelector('.cm-editor.cm-focused'); + if (!focusedEditor || isInsideChatComposer(focusedEditor)) { + return null; + } + + const view = EditorView.findFromDOM(focusedEditor); + if (!view) { + return null; + } + + const { from, to } = view.state.selection.main; + if (from === to) { + return null; + } + + const text = trimSelectionValue(view.state.sliceDoc(from, to)); + if (!text) { + return null; + } + + view.dispatch({ + selection: { anchor: to }, + }); + + return formatCodeSelectionMarkdown(text); +}; + +const captureDomSelection = (): string | null => { + if (typeof window === 'undefined') { + return null; + } + + const selection = window.getSelection(); + if (!selection || selection.rangeCount === 0 || selection.isCollapsed) { + return null; + } + + const range = selection.getRangeAt(0); + if (isInsideChatComposer(range.commonAncestorContainer)) { + return null; + } + + const plainText = trimSelectionValue(selection.toString()); + if (!plainText) { + return null; + } + + const markdown = rangeToMarkdown(range, plainText); + selection.removeAllRanges(); + return wrapMarkdownSelectionForChat(markdown); +}; + +/** + * Capture the current non-composer selection as chat-ready markdown. + * Returns null when nothing usable is selected. + */ +export const captureSelectionMarkdownForChat = (): string | null => { + return captureCodeMirrorSelection() + ?? captureActiveElementSelection() + ?? captureDomSelection(); +}; + +/** + * Append the current selection to the chat composer. + * When nothing is selected, focuses the chat input (Cursor-style Ctrl/Cmd+L). + * Returns true when selected text was appended. + */ +export const addSelectionToChat = (): boolean => { + const markdown = captureSelectionMarkdownForChat(); + + useUIStore.getState().setActiveMainTab('chat'); + useUIStore.getState().setSessionSwitcherOpen(false); + + if (markdown) { + useInputStore.getState().setPendingInputText(markdown, 'append'); + } + + queueMicrotask(() => { + focusChatInput(); + }); + + return markdown !== null; +}; diff --git a/packages/ui/src/lib/i18n/messages/de.settings.ts b/packages/ui/src/lib/i18n/messages/de.settings.ts index 1291cf6d..51c57a17 100644 --- a/packages/ui/src/lib/i18n/messages/de.settings.ts +++ b/packages/ui/src/lib/i18n/messages/de.settings.ts @@ -1039,6 +1039,7 @@ export const settingsDict = { 'settings.openchamber.keyboardShortcuts.action.open_settings.label': 'Einstellungen öffnen', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal.label': 'Terminal-Dock umschalten', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label': 'Terminal erweitert umschalten', + 'settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label': 'Auswahl zum Chat hinzufügen', 'settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label': 'Seitenleiste umschalten', 'settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label': 'Rechte Seitenleiste umschalten', 'settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label': 'Git-Tab der rechten Seitenleiste öffnen', diff --git a/packages/ui/src/lib/i18n/messages/de.ts b/packages/ui/src/lib/i18n/messages/de.ts index f9d325b9..b631f826 100644 --- a/packages/ui/src/lib/i18n/messages/de.ts +++ b/packages/ui/src/lib/i18n/messages/de.ts @@ -1531,6 +1531,7 @@ export const dict = { 'helpDialog.item.openCommandPalette': 'Befehlspalette öffnen', 'helpDialog.item.showKeyboardShortcuts': 'Tastaturkürzel anzeigen (dieses Dialogfeld)', 'helpDialog.item.toggleSessionSidebar': 'Sitzungs-Seitenleiste umschalten', + 'helpDialog.item.addSelectionToChat': 'Auswahl zum Chat hinzufügen', 'helpDialog.item.cycleAgent': 'Agent wechseln (Chat-Eingabe)', 'helpDialog.item.openModelSelector': 'Modell-Auswahldialog öffnen', 'helpDialog.item.navigateModels': 'Modelle navigieren (in Auswahl)', diff --git a/packages/ui/src/lib/i18n/messages/en.settings.ts b/packages/ui/src/lib/i18n/messages/en.settings.ts index 924965d1..4c453515 100644 --- a/packages/ui/src/lib/i18n/messages/en.settings.ts +++ b/packages/ui/src/lib/i18n/messages/en.settings.ts @@ -1104,6 +1104,7 @@ export const settingsDict = { 'settings.openchamber.keyboardShortcuts.action.open_settings.label': 'Open settings', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal.label': 'Toggle terminal dock', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label': 'Toggle terminal expanded', + 'settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label': 'Add selection to chat', 'settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label': 'Toggle sidebar', 'settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label': 'Toggle context panel', 'settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label': 'Open Git surface', diff --git a/packages/ui/src/lib/i18n/messages/en.ts b/packages/ui/src/lib/i18n/messages/en.ts index 7b63e05e..5501f15b 100644 --- a/packages/ui/src/lib/i18n/messages/en.ts +++ b/packages/ui/src/lib/i18n/messages/en.ts @@ -1678,6 +1678,7 @@ export const dict = { 'helpDialog.item.openCommandPalette': 'Open Command Palette', 'helpDialog.item.showKeyboardShortcuts': 'Show Keyboard Shortcuts (this dialog)', 'helpDialog.item.toggleSessionSidebar': 'Toggle Session Sidebar', + 'helpDialog.item.addSelectionToChat': 'Add Selection to Chat', 'helpDialog.item.cycleAgent': 'Cycle Agent (chat input)', 'helpDialog.item.openModelSelector': 'Open Model Selector', 'helpDialog.item.navigateModels': 'Navigate Models (in picker)', diff --git a/packages/ui/src/lib/i18n/messages/es.settings.ts b/packages/ui/src/lib/i18n/messages/es.settings.ts index 88f12bfe..1178accc 100644 --- a/packages/ui/src/lib/i18n/messages/es.settings.ts +++ b/packages/ui/src/lib/i18n/messages/es.settings.ts @@ -1071,6 +1071,7 @@ export const settingsDict = { "settings.openchamber.keyboardShortcuts.action.open_settings.label": "Abrir configuración", "settings.openchamber.keyboardShortcuts.action.toggle_terminal.label": "Mostrar u ocultar panel de terminal", "settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label": "Expandir o contraer terminal", + "settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label": "Agregar selección al chat", "settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label": "Mostrar u ocultar barra lateral", "settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label": 'Alternar panel de contexto', "settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label": 'Abrir superficie de Git', diff --git a/packages/ui/src/lib/i18n/messages/es.ts b/packages/ui/src/lib/i18n/messages/es.ts index 08a3f727..c7a94320 100644 --- a/packages/ui/src/lib/i18n/messages/es.ts +++ b/packages/ui/src/lib/i18n/messages/es.ts @@ -1656,6 +1656,7 @@ export const dict: Record = { "helpDialog.item.openCommandPalette": "Abrir paleta de comandos", "helpDialog.item.showKeyboardShortcuts": "Mostrar atajos de teclado (este diálogo)", "helpDialog.item.toggleSessionSidebar": "Mostrar u ocultar barra lateral de sesión", + "helpDialog.item.addSelectionToChat": "Agregar selección al chat", "helpDialog.item.cycleAgent": "Cambiar agente (entrada de chat)", "helpDialog.item.openModelSelector": "Abrir selector de modelos", "helpDialog.item.navigateModels": "Navegar modelos (en selector)", diff --git a/packages/ui/src/lib/i18n/messages/fr.settings.ts b/packages/ui/src/lib/i18n/messages/fr.settings.ts index 30cfe251..ad5e7561 100644 --- a/packages/ui/src/lib/i18n/messages/fr.settings.ts +++ b/packages/ui/src/lib/i18n/messages/fr.settings.ts @@ -992,6 +992,7 @@ export const settingsDict = { 'settings.openchamber.keyboardShortcuts.action.open_settings.label': 'Ouvrir les paramètres', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal.label': 'Basculer la station d\'accueil du terminal', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label': 'Terminal à bascule étendu', + 'settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label': 'Ajouter la sélection au chat', 'settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label': 'Basculer la barre latérale', 'settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label': 'Afficher/masquer le panneau de contexte', 'settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label': 'Ouvrir la surface Git', diff --git a/packages/ui/src/lib/i18n/messages/fr.ts b/packages/ui/src/lib/i18n/messages/fr.ts index 2f99e4f4..8303c247 100644 --- a/packages/ui/src/lib/i18n/messages/fr.ts +++ b/packages/ui/src/lib/i18n/messages/fr.ts @@ -1491,6 +1491,7 @@ export const dict = { 'helpDialog.item.openCommandPalette': 'Ouvrir la palette de commandes', 'helpDialog.item.showKeyboardShortcuts': 'Afficher les raccourcis clavier (cette boîte de dialogue)', 'helpDialog.item.toggleSessionSidebar': 'Toggle la barre latérale de la session', + 'helpDialog.item.addSelectionToChat': 'Ajouter la sélection au chat', 'helpDialog.item.cycleAgent': 'Agent de cycle (entrée de chat)', 'helpDialog.item.openModelSelector': 'Ouvrir le sélecteur de modèle', 'helpDialog.item.navigateModels': 'Naviguer dans les modèles (dans le sélecteur)', diff --git a/packages/ui/src/lib/i18n/messages/ja.settings.ts b/packages/ui/src/lib/i18n/messages/ja.settings.ts index 6ad20690..50571a78 100644 --- a/packages/ui/src/lib/i18n/messages/ja.settings.ts +++ b/packages/ui/src/lib/i18n/messages/ja.settings.ts @@ -1104,6 +1104,7 @@ export const settingsDict = { 'settings.openchamber.keyboardShortcuts.action.open_settings.label': '設定を開く', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal.label': 'ターミナルドックの切替', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label': 'ターミナル拡大の切替', + 'settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label': '選択範囲をチャットに追加', 'settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label': 'サイドバーの切替', 'settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label': 'コンテキストパネルの表示切替', 'settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label': 'Git サーフェスを開く', diff --git a/packages/ui/src/lib/i18n/messages/ja.ts b/packages/ui/src/lib/i18n/messages/ja.ts index e7c7d111..12d57006 100644 --- a/packages/ui/src/lib/i18n/messages/ja.ts +++ b/packages/ui/src/lib/i18n/messages/ja.ts @@ -1674,6 +1674,7 @@ export const dict: Record = { 'helpDialog.item.openCommandPalette': 'コマンドパレットを開く', 'helpDialog.item.showKeyboardShortcuts': 'キーボードショートカットを表示(このダイアログ)', 'helpDialog.item.toggleSessionSidebar': 'セッションサイドバーの切り替え', + 'helpDialog.item.addSelectionToChat': '選択範囲をチャットに追加', 'helpDialog.item.cycleAgent': 'エージェント切り替え(チャット入力)', 'helpDialog.item.openModelSelector': 'モデルセレクターを開く', 'helpDialog.item.navigateModels': 'モデルを移動(ピッカー内)', diff --git a/packages/ui/src/lib/i18n/messages/ko.settings.ts b/packages/ui/src/lib/i18n/messages/ko.settings.ts index a46f1b2e..246b1427 100644 --- a/packages/ui/src/lib/i18n/messages/ko.settings.ts +++ b/packages/ui/src/lib/i18n/messages/ko.settings.ts @@ -1071,6 +1071,7 @@ export const settingsDict = { 'settings.openchamber.keyboardShortcuts.action.open_settings.label': '설정 열기', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal.label': '터미널 dock 토글', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label': '터미널 확장 토글', + 'settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label': '선택 내용을 채팅에 추가', 'settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label': '사이드바 토글', 'settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label': '컨텍스트 패널 표시 전환', 'settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label': 'Git 서피스 열기', diff --git a/packages/ui/src/lib/i18n/messages/ko.ts b/packages/ui/src/lib/i18n/messages/ko.ts index 5e2983be..2f9eb896 100644 --- a/packages/ui/src/lib/i18n/messages/ko.ts +++ b/packages/ui/src/lib/i18n/messages/ko.ts @@ -1680,6 +1680,7 @@ export const dict: Record = { 'helpDialog.item.openCommandPalette': '명령 팔레트 열기', 'helpDialog.item.showKeyboardShortcuts': '키보드 단축키 보기(이 대화상자)', 'helpDialog.item.toggleSessionSidebar': '토글 세션 사이드바', + 'helpDialog.item.addSelectionToChat': '선택 내용을 채팅에 추가', 'helpDialog.item.cycleAgent': '에이전트 순환(채팅 입력)', 'helpDialog.item.openModelSelector': '모델 선택기 열기', 'helpDialog.item.navigateModels': '모델 이동(선택기)', diff --git a/packages/ui/src/lib/i18n/messages/pl.settings.ts b/packages/ui/src/lib/i18n/messages/pl.settings.ts index 93a9e901..2ddb59f9 100644 --- a/packages/ui/src/lib/i18n/messages/pl.settings.ts +++ b/packages/ui/src/lib/i18n/messages/pl.settings.ts @@ -825,6 +825,7 @@ export const settingsDict = { 'settings.openchamber.keyboardShortcuts.action.toggle_context_plan.label': 'Przełącz panel kontekstu planu', 'settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label': 'Przełącz panel kontekstu', 'settings.openchamber.keyboardShortcuts.action.toggle_services_menu.label': 'Przełącz menu usług', + 'settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label': 'Dodaj zaznaczenie do czatu', 'settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label': 'Przełącz pasek boczny', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal.label': 'Przełącz dokowanie terminala', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label': 'Przełącz rozszerzony terminal', diff --git a/packages/ui/src/lib/i18n/messages/pl.ts b/packages/ui/src/lib/i18n/messages/pl.ts index f4129c47..ae54407b 100644 --- a/packages/ui/src/lib/i18n/messages/pl.ts +++ b/packages/ui/src/lib/i18n/messages/pl.ts @@ -2325,6 +2325,7 @@ export const dict: Record = { 'helpDialog.item.toggleRightSidebar': 'Przełącz panel kontekstu', 'helpDialog.item.toggleServicesMenu': 'Przełącz menu usług', 'helpDialog.item.toggleSessionSidebar': 'Przełącz panel sesji', + 'helpDialog.item.addSelectionToChat': 'Dodaj zaznaczenie do czatu', 'helpDialog.item.toggleTerminalDock': 'Przełącz dolny terminal', 'helpDialog.item.toggleTerminalExpanded': 'Przełącz rozszerzenie terminala', 'helpDialog.keyCombiner.or': 'lub', diff --git a/packages/ui/src/lib/i18n/messages/pt-BR.settings.ts b/packages/ui/src/lib/i18n/messages/pt-BR.settings.ts index eebdc398..91fcdbd1 100644 --- a/packages/ui/src/lib/i18n/messages/pt-BR.settings.ts +++ b/packages/ui/src/lib/i18n/messages/pt-BR.settings.ts @@ -1071,6 +1071,7 @@ export const settingsDict = { "settings.openchamber.keyboardShortcuts.action.open_settings.label": "Abrir configurações", "settings.openchamber.keyboardShortcuts.action.toggle_terminal.label": "Mostrar ou ocultar painel de terminal", "settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label": "Expandir ou recolher terminal", + "settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label": "Adicionar seleção ao chat", "settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label": "Mostrar ou ocultar barra lateral", "settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label": 'Alternar painel de contexto', "settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label": 'Abrir superfície do Git', diff --git a/packages/ui/src/lib/i18n/messages/pt-BR.ts b/packages/ui/src/lib/i18n/messages/pt-BR.ts index a9c3bca9..789ac65d 100644 --- a/packages/ui/src/lib/i18n/messages/pt-BR.ts +++ b/packages/ui/src/lib/i18n/messages/pt-BR.ts @@ -1656,6 +1656,7 @@ export const dict: Record = { "helpDialog.item.openCommandPalette": "Abrir paleta de comandos", "helpDialog.item.showKeyboardShortcuts": "Mostrar atalhos de teclado (este diálogo)", "helpDialog.item.toggleSessionSidebar": "Mostrar ou ocultar barra lateral de sessão", + "helpDialog.item.addSelectionToChat": "Adicionar seleção ao chat", "helpDialog.item.cycleAgent": "Alternar agente (entrada do chat)", "helpDialog.item.openModelSelector": "Abrir seletor de modelos", "helpDialog.item.navigateModels": "Navegar por modelos (no seletor)", diff --git a/packages/ui/src/lib/i18n/messages/uk.settings.ts b/packages/ui/src/lib/i18n/messages/uk.settings.ts index b7f18d2e..a6c70f9b 100644 --- a/packages/ui/src/lib/i18n/messages/uk.settings.ts +++ b/packages/ui/src/lib/i18n/messages/uk.settings.ts @@ -1071,6 +1071,7 @@ export const settingsDict = { "settings.openchamber.keyboardShortcuts.action.open_settings.label": "Відкрити налаштування", "settings.openchamber.keyboardShortcuts.action.toggle_terminal.label": "Перемкнути панель терміналу", "settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label": "Розгорнути або згорнути термінал", + "settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label": "Додати виділення в чат", "settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label": "Перемкнути бічну панель", "settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label": 'Перемкнути контекстну панель', "settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label": 'Відкрити поверхню Git', diff --git a/packages/ui/src/lib/i18n/messages/uk.ts b/packages/ui/src/lib/i18n/messages/uk.ts index c1c3d7cc..911387f4 100644 --- a/packages/ui/src/lib/i18n/messages/uk.ts +++ b/packages/ui/src/lib/i18n/messages/uk.ts @@ -1656,6 +1656,7 @@ export const dict: Record = { "helpDialog.item.openCommandPalette": "Відкрити палітру команд", "helpDialog.item.showKeyboardShortcuts": "Показати комбінації клавіш (це діалогове вікно)", "helpDialog.item.toggleSessionSidebar": "Перемкнути бічну панель сесій", + "helpDialog.item.addSelectionToChat": "Додати виділення в чат", "helpDialog.item.cycleAgent": "Перемкнути агента (введення в чат)", "helpDialog.item.openModelSelector": "Відкрити засіб вибору моделі", "helpDialog.item.navigateModels": "Навігація моделями (у засобі вибору)", diff --git a/packages/ui/src/lib/i18n/messages/zh-CN.settings.ts b/packages/ui/src/lib/i18n/messages/zh-CN.settings.ts index 8fe889c7..1010ce46 100644 --- a/packages/ui/src/lib/i18n/messages/zh-CN.settings.ts +++ b/packages/ui/src/lib/i18n/messages/zh-CN.settings.ts @@ -1071,6 +1071,7 @@ export const settingsDict = { 'settings.openchamber.keyboardShortcuts.action.open_settings.label': '打开设置', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal.label': '切换终端停靠区', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label': '切换终端展开', + 'settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label': '将选中内容添加到聊天', 'settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label': '切换侧边栏', 'settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label': '切换上下文面板', 'settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label': '打开 Git 界面', diff --git a/packages/ui/src/lib/i18n/messages/zh-CN.ts b/packages/ui/src/lib/i18n/messages/zh-CN.ts index 9fef7f48..01748f14 100644 --- a/packages/ui/src/lib/i18n/messages/zh-CN.ts +++ b/packages/ui/src/lib/i18n/messages/zh-CN.ts @@ -1644,6 +1644,7 @@ export const dict: Record = { 'helpDialog.item.openCommandPalette': '打开命令面板', 'helpDialog.item.showKeyboardShortcuts': '显示键盘快捷键(此对话框)', 'helpDialog.item.toggleSessionSidebar': '切换会话侧边栏', + 'helpDialog.item.addSelectionToChat': '将选中内容添加到聊天', 'helpDialog.item.cycleAgent': '循环切换智能体(聊天输入)', 'helpDialog.item.openModelSelector': '打开模型选择器', 'helpDialog.item.navigateModels': '导航模型(选择器中)', diff --git a/packages/ui/src/lib/i18n/messages/zh-TW.settings.ts b/packages/ui/src/lib/i18n/messages/zh-TW.settings.ts index a7405089..1ebe3d6c 100644 --- a/packages/ui/src/lib/i18n/messages/zh-TW.settings.ts +++ b/packages/ui/src/lib/i18n/messages/zh-TW.settings.ts @@ -978,6 +978,7 @@ 'settings.openchamber.keyboardShortcuts.action.open_settings.label': '開啟設定', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal.label': '切換終端機停靠區', 'settings.openchamber.keyboardShortcuts.action.toggle_terminal_expanded.label': '切換終端機展開', + 'settings.openchamber.keyboardShortcuts.action.add_selection_to_chat.label': '將選取內容加入聊天', 'settings.openchamber.keyboardShortcuts.action.toggle_sidebar.label': '切換側邊欄', 'settings.openchamber.keyboardShortcuts.action.toggle_right_sidebar.label': '切換上下文面板', 'settings.openchamber.keyboardShortcuts.action.open_right_sidebar_git.label': '開啟 Git 介面', diff --git a/packages/ui/src/lib/i18n/messages/zh-TW.ts b/packages/ui/src/lib/i18n/messages/zh-TW.ts index 2615292a..84ce8f87 100644 --- a/packages/ui/src/lib/i18n/messages/zh-TW.ts +++ b/packages/ui/src/lib/i18n/messages/zh-TW.ts @@ -1648,6 +1648,7 @@ export const dict: Record = { 'helpDialog.item.openCommandPalette': '開啟命令面板', 'helpDialog.item.showKeyboardShortcuts': '顯示鍵盤快速鍵(此對話方塊)', 'helpDialog.item.toggleSessionSidebar': '切換會話側邊欄', + 'helpDialog.item.addSelectionToChat': '將選取內容加入聊天', 'helpDialog.item.cycleAgent': '循環切換 Agent(聊天輸入)', 'helpDialog.item.openModelSelector': '開啟模型選擇器', 'helpDialog.item.navigateModels': '導覽模型(選擇器中)', diff --git a/packages/ui/src/lib/shortcuts.ts b/packages/ui/src/lib/shortcuts.ts index e6e16e29..6afb4656 100644 --- a/packages/ui/src/lib/shortcuts.ts +++ b/packages/ui/src/lib/shortcuts.ts @@ -159,8 +159,15 @@ const SHORTCUT_ACTIONS: ReadonlyArray = [ description: 'Toggle the files panel', }, { - id: 'toggle_sidebar', + id: 'add_selection_to_chat', defaultCombo: 'mod+l', + label: 'Add selection to chat', + description: 'Add the selected text to the chat input', + customizable: true, + }, + { + id: 'toggle_sidebar', + defaultCombo: 'mod+alt+l', label: 'Toggle sidebar', description: 'Toggle the session sidebar', customizable: true,