summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/cli/src/ui/components/InputPrompt.tsx5
-rw-r--r--packages/cli/src/ui/components/shared/text-buffer.test.ts29
-rw-r--r--packages/cli/src/ui/components/shared/text-buffer.ts25
3 files changed, 32 insertions, 27 deletions
diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx
index 9f15b56d..8d296dc4 100644
--- a/packages/cli/src/ui/components/InputPrompt.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.tsx
@@ -164,7 +164,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
const handleInput = useCallback(
(key: Key) => {
- if (!focus) {
+ /// We want to handle paste even when not focused to support drag and drop.
+ if (!focus && !key.paste) {
return;
}
@@ -349,7 +350,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
],
);
- useKeypress(handleInput, { isActive: focus });
+ useKeypress(handleInput, { isActive: true });
const linesToRender = buffer.viewportVisualLines;
const [cursorVisualRowAbsolute, cursorVisualColAbsolute] =
diff --git a/packages/cli/src/ui/components/shared/text-buffer.test.ts b/packages/cli/src/ui/components/shared/text-buffer.test.ts
index 89930c18..4db1ce7b 100644
--- a/packages/cli/src/ui/components/shared/text-buffer.test.ts
+++ b/packages/cli/src/ui/components/shared/text-buffer.test.ts
@@ -407,8 +407,8 @@ describe('useTextBuffer', () => {
useTextBuffer({ viewport, isValidPath: () => true }),
);
const filePath = '/path/to/a/valid/file.txt';
- act(() => result.current.insert(filePath));
- expect(getBufferState(result).text).toBe(`@${filePath}`);
+ act(() => result.current.insert(filePath, { paste: true }));
+ expect(getBufferState(result).text).toBe(`@${filePath} `);
});
it('should not prepend @ to an invalid file path on insert', () => {
@@ -416,7 +416,7 @@ describe('useTextBuffer', () => {
useTextBuffer({ viewport, isValidPath: () => false }),
);
const notAPath = 'this is just some long text';
- act(() => result.current.insert(notAPath));
+ act(() => result.current.insert(notAPath, { paste: true }));
expect(getBufferState(result).text).toBe(notAPath);
});
@@ -425,8 +425,8 @@ describe('useTextBuffer', () => {
useTextBuffer({ viewport, isValidPath: () => true }),
);
const filePath = "'/path/to/a/valid/file.txt'";
- act(() => result.current.insert(filePath));
- expect(getBufferState(result).text).toBe(`@/path/to/a/valid/file.txt`);
+ act(() => result.current.insert(filePath, { paste: true }));
+ expect(getBufferState(result).text).toBe(`@/path/to/a/valid/file.txt `);
});
it('should not prepend @ to short text that is not a path', () => {
@@ -434,7 +434,7 @@ describe('useTextBuffer', () => {
useTextBuffer({ viewport, isValidPath: () => true }),
);
const shortText = 'ab';
- act(() => result.current.insert(shortText));
+ act(() => result.current.insert(shortText, { paste: true }));
expect(getBufferState(result).text).toBe(shortText);
});
});
@@ -449,7 +449,7 @@ describe('useTextBuffer', () => {
}),
);
const filePath = '/path/to/a/valid/file.txt';
- act(() => result.current.insert(filePath));
+ act(() => result.current.insert(filePath, { paste: true }));
expect(getBufferState(result).text).toBe(filePath); // No @ prefix
});
@@ -462,7 +462,7 @@ describe('useTextBuffer', () => {
}),
);
const quotedFilePath = "'/path/to/a/valid/file.txt'";
- act(() => result.current.insert(quotedFilePath));
+ act(() => result.current.insert(quotedFilePath, { paste: true }));
expect(getBufferState(result).text).toBe(quotedFilePath); // No @ prefix, keeps quotes
});
@@ -475,7 +475,7 @@ describe('useTextBuffer', () => {
}),
);
const notAPath = 'this is just some text';
- act(() => result.current.insert(notAPath));
+ act(() => result.current.insert(notAPath, { paste: true }));
expect(getBufferState(result).text).toBe(notAPath);
});
@@ -488,7 +488,7 @@ describe('useTextBuffer', () => {
}),
);
const shortText = 'ls';
- act(() => result.current.insert(shortText));
+ act(() => result.current.insert(shortText, { paste: true }));
expect(getBufferState(result).text).toBe(shortText); // No @ prefix for short text
});
});
@@ -849,6 +849,7 @@ describe('useTextBuffer', () => {
ctrl: false,
meta: false,
shift: false,
+ paste: false,
sequence: '\x7f',
});
result.current.handleInput({
@@ -856,6 +857,7 @@ describe('useTextBuffer', () => {
ctrl: false,
meta: false,
shift: false,
+ paste: false,
sequence: '\x7f',
});
result.current.handleInput({
@@ -863,6 +865,7 @@ describe('useTextBuffer', () => {
ctrl: false,
meta: false,
shift: false,
+ paste: false,
sequence: '\x7f',
});
});
@@ -990,9 +993,9 @@ Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots
// Simulate pasting the long text multiple times
act(() => {
- result.current.insert(longText);
- result.current.insert(longText);
- result.current.insert(longText);
+ result.current.insert(longText, { paste: true });
+ result.current.insert(longText, { paste: true });
+ result.current.insert(longText, { paste: true });
});
const state = getBufferState(result);
diff --git a/packages/cli/src/ui/components/shared/text-buffer.ts b/packages/cli/src/ui/components/shared/text-buffer.ts
index 7eb3088a..31db1f14 100644
--- a/packages/cli/src/ui/components/shared/text-buffer.ts
+++ b/packages/cli/src/ui/components/shared/text-buffer.ts
@@ -1023,26 +1023,27 @@ export function useTextBuffer({
}, [visualCursor, visualScrollRow, viewport]);
const insert = useCallback(
- (ch: string): void => {
+ (ch: string, { paste = false }: { paste?: boolean } = {}): void => {
if (/[\n\r]/.test(ch)) {
dispatch({ type: 'insert', payload: ch });
return;
}
const minLengthToInferAsDragDrop = 3;
- if (ch.length >= minLengthToInferAsDragDrop && !shellModeActive) {
- let potentialPath = ch;
- if (
- potentialPath.length > 2 &&
- potentialPath.startsWith("'") &&
- potentialPath.endsWith("'")
- ) {
- potentialPath = ch.slice(1, -1);
+ if (
+ ch.length >= minLengthToInferAsDragDrop &&
+ !shellModeActive &&
+ paste
+ ) {
+ let potentialPath = ch.trim();
+ const quoteMatch = potentialPath.match(/^'(.*)'$/);
+ if (quoteMatch) {
+ potentialPath = quoteMatch[1];
}
potentialPath = potentialPath.trim();
if (isValidPath(unescapePath(potentialPath))) {
- ch = `@${potentialPath}`;
+ ch = `@${potentialPath} `;
}
}
@@ -1203,7 +1204,7 @@ export function useTextBuffer({
backspace();
else if (key.name === 'delete' || (key.ctrl && key.name === 'd')) del();
else if (input && !key.ctrl && !key.meta) {
- insert(input);
+ insert(input, { paste: key.paste });
}
},
[newline, move, deleteWordLeft, deleteWordRight, backspace, del, insert],
@@ -1306,7 +1307,7 @@ export interface TextBuffer {
/**
* Insert a single character or string without newlines.
*/
- insert: (ch: string) => void;
+ insert: (ch: string, opts?: { paste?: boolean }) => void;
newline: () => void;
backspace: () => void;
del: () => void;