feat(ui): add Ctrl/Cmd+L to send selected text to chat
Bind mod+l to append the current selection into the chat composer (Cursor-style), and move session sidebar toggle to mod+alt+l so desktop menus stay in sync. Closes #208. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
co-authored by
Serhii Dziupin
parent
e0bd787468
commit
3ad3f21024
@@ -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<HTMLElement | null>;
|
||||
@@ -63,6 +65,11 @@ export const TextSelectionMenu: React.FC<TextSelectionMenuProps> = ({ 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<TextSelectionMenuProps> = ({ 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<TextSelectionMenuProps> = ({ 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"
|
||||
>
|
||||
<Icon name="add" className="h-5 w-5 flex-shrink-0" />
|
||||
@@ -508,11 +520,16 @@ export const TextSelectionMenu: React.FC<TextSelectionMenuProps> = ({ 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"
|
||||
>
|
||||
<Icon name="add" className="h-4 w-4" />
|
||||
<span className="whitespace-nowrap">{t('chat.textSelection.actions.addToChat')}</span>
|
||||
{addToChatShortcut ? (
|
||||
<span className="whitespace-nowrap text-xs text-muted-foreground">{addToChatShortcut}</span>
|
||||
) : null}
|
||||
</button>
|
||||
|
||||
<div className="w-px h-4 bg-[var(--interactive-border)]" />
|
||||
|
||||
@@ -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: '',
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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<HTMLElement>('.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;
|
||||
};
|
||||
@@ -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',
|
||||
|
||||
@@ -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)',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1656,6 +1656,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"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)",
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)',
|
||||
|
||||
@@ -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 サーフェスを開く',
|
||||
|
||||
@@ -1674,6 +1674,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'helpDialog.item.openCommandPalette': 'コマンドパレットを開く',
|
||||
'helpDialog.item.showKeyboardShortcuts': 'キーボードショートカットを表示(このダイアログ)',
|
||||
'helpDialog.item.toggleSessionSidebar': 'セッションサイドバーの切り替え',
|
||||
'helpDialog.item.addSelectionToChat': '選択範囲をチャットに追加',
|
||||
'helpDialog.item.cycleAgent': 'エージェント切り替え(チャット入力)',
|
||||
'helpDialog.item.openModelSelector': 'モデルセレクターを開く',
|
||||
'helpDialog.item.navigateModels': 'モデルを移動(ピッカー内)',
|
||||
|
||||
@@ -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 서피스 열기',
|
||||
|
||||
@@ -1680,6 +1680,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'helpDialog.item.openCommandPalette': '명령 팔레트 열기',
|
||||
'helpDialog.item.showKeyboardShortcuts': '키보드 단축키 보기(이 대화상자)',
|
||||
'helpDialog.item.toggleSessionSidebar': '토글 세션 사이드바',
|
||||
'helpDialog.item.addSelectionToChat': '선택 내용을 채팅에 추가',
|
||||
'helpDialog.item.cycleAgent': '에이전트 순환(채팅 입력)',
|
||||
'helpDialog.item.openModelSelector': '모델 선택기 열기',
|
||||
'helpDialog.item.navigateModels': '모델 이동(선택기)',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -2325,6 +2325,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1656,6 +1656,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"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)",
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1656,6 +1656,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"helpDialog.item.openCommandPalette": "Відкрити палітру команд",
|
||||
"helpDialog.item.showKeyboardShortcuts": "Показати комбінації клавіш (це діалогове вікно)",
|
||||
"helpDialog.item.toggleSessionSidebar": "Перемкнути бічну панель сесій",
|
||||
"helpDialog.item.addSelectionToChat": "Додати виділення в чат",
|
||||
"helpDialog.item.cycleAgent": "Перемкнути агента (введення в чат)",
|
||||
"helpDialog.item.openModelSelector": "Відкрити засіб вибору моделі",
|
||||
"helpDialog.item.navigateModels": "Навігація моделями (у засобі вибору)",
|
||||
|
||||
@@ -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 界面',
|
||||
|
||||
@@ -1644,6 +1644,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'helpDialog.item.openCommandPalette': '打开命令面板',
|
||||
'helpDialog.item.showKeyboardShortcuts': '显示键盘快捷键(此对话框)',
|
||||
'helpDialog.item.toggleSessionSidebar': '切换会话侧边栏',
|
||||
'helpDialog.item.addSelectionToChat': '将选中内容添加到聊天',
|
||||
'helpDialog.item.cycleAgent': '循环切换智能体(聊天输入)',
|
||||
'helpDialog.item.openModelSelector': '打开模型选择器',
|
||||
'helpDialog.item.navigateModels': '导航模型(选择器中)',
|
||||
|
||||
@@ -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 介面',
|
||||
|
||||
@@ -1648,6 +1648,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'helpDialog.item.openCommandPalette': '開啟命令面板',
|
||||
'helpDialog.item.showKeyboardShortcuts': '顯示鍵盤快速鍵(此對話方塊)',
|
||||
'helpDialog.item.toggleSessionSidebar': '切換會話側邊欄',
|
||||
'helpDialog.item.addSelectionToChat': '將選取內容加入聊天',
|
||||
'helpDialog.item.cycleAgent': '循環切換 Agent(聊天輸入)',
|
||||
'helpDialog.item.openModelSelector': '開啟模型選擇器',
|
||||
'helpDialog.item.navigateModels': '導覽模型(選擇器中)',
|
||||
|
||||
@@ -159,8 +159,15 @@ const SHORTCUT_ACTIONS: ReadonlyArray<ShortcutAction> = [
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user