Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/cli/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ they appear in the UI.
| Show Home Directory Warning | `ui.showHomeDirectoryWarning` | Show a warning when running Gemini CLI in the home directory. | `true` |
| Show Compatibility Warnings | `ui.showCompatibilityWarnings` | Show warnings about terminal or OS compatibility issues. | `true` |
| Hide Tips | `ui.hideTips` | Hide helpful tips in the UI | `false` |
| Escape Pasted @ Symbols | `ui.escapePastedAtSymbols` | When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion. | `false` |
| Escape Pasted @ Symbols | `ui.escapePastedAtSymbols` | When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion. Type @path manually to include a file. | `true` |
| Show Shortcuts Hint | `ui.showShortcutsHint` | Show the "? for shortcuts" hint above the input. | `true` |
| Compact Tool Output | `ui.compactToolOutput` | Display tool outputs (like directory listings and file reads) in a compact, structured format. | `true` |
| Hide Banner | `ui.hideBanner` | Hide the application banner | `false` |
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ their corresponding top-level category object in your `settings.json` file.
- **`ui.escapePastedAtSymbols`** (boolean):

- **Description:** When enabled, @ symbols in pasted text are escaped to
prevent unintended @path expansion.
- **Default:** `false`
prevent unintended @path expansion. Type @path manually to include a file.
- **Default:** `true`

- **`ui.showShortcutsHint`** (boolean):

Expand Down
6 changes: 6 additions & 0 deletions packages/cli/src/config/settingsSchema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ describe('SettingsSchema', () => {
expect(definition?.options?.map((o) => o.value)).toEqual(['low', 'full']);
});

it('should escape @ symbols in pasted text by default', () => {
expect(
getSettingsSchema().ui?.properties?.escapePastedAtSymbols?.default,
).toBe(true);
});

it('should have checkpointing nested properties', () => {
expect(
getSettingsSchema().general?.properties?.checkpointing.properties
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/config/settingsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,9 @@ const SETTINGS_SCHEMA = {
label: 'Escape Pasted @ Symbols',
category: 'UI',
requiresRestart: false,
default: false,
default: true,
description:
'When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion.',
'When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion. Type @path manually to include a file.',
showInDialog: true,
},
showShortcutsHint: {
Expand Down
32 changes: 29 additions & 3 deletions packages/cli/src/ui/components/InputPrompt.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1017,13 +1017,17 @@ describe('InputPrompt', () => {
});

describe('clipboard text paste', () => {
it('should insert text from clipboard on Ctrl+V', async () => {
it('should escape @ symbols in clipboard text on Ctrl+V', async () => {
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
vi.mocked(clipboardy.read).mockResolvedValue('pasted text');
vi.mocked(clipboardy.read).mockResolvedValue(
'user@host:~/project$ cat @id_rsa',
);
vi.mocked(mockBuffer.replaceRangeByOffset).mockClear();
const settings = createMockSettings();

const { stdin, unmount } = await renderWithProviders(
<TestInputPrompt {...props} />,
{ settings },
);

await act(async () => {
Expand All @@ -1033,13 +1037,35 @@ describe('InputPrompt', () => {
await waitFor(() => {
expect(clipboardy.read).toHaveBeenCalled();
expect(mockBuffer.insert).toHaveBeenCalledWith(
'pasted text',
'user\\@host:~/project$ cat \\@id_rsa',
expect.objectContaining({ paste: true }),
);
});
unmount();
});

it('should escape @ symbols in bracketed terminal paste', async () => {
const settings = createMockSettings();
const { stdin, unmount } = await renderWithProviders(
<TestInputPrompt {...props} />,
{ settings },
);

await act(async () => {
stdin.write('\x1B[200~user@host:~/project$ cat @id_rsa\x1B[201~');
});

await waitFor(() => {
expect(mockBuffer.handleInput).toHaveBeenCalledWith(
expect.objectContaining({
name: 'paste',
sequence: 'user\\@host:~/project$ cat \\@id_rsa',
}),
);
});
unmount();
});

it('should use OSC 52 when useOSC52Paste setting is enabled', async () => {
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
const settings = createMockSettings({
Expand Down
6 changes: 3 additions & 3 deletions schemas/settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,9 @@
},
"escapePastedAtSymbols": {
"title": "Escape Pasted @ Symbols",
"description": "When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion.",
"markdownDescription": "When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion.\n\n- Category: `UI`\n- Requires restart: `no`\n- Default: `false`",
"default": false,
"description": "When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion. Type @path manually to include a file.",
"markdownDescription": "When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion. Type @path manually to include a file.\n\n- Category: `UI`\n- Requires restart: `no`\n- Default: `true`",
"default": true,
"type": "boolean"
},
"showShortcutsHint": {
Expand Down
Loading