Skip to content

Commit 08e174a

Browse files
aanarijacob314
andauthored
feat(ui): add vim yank/paste (y/p/P) with unnamed register (#22026)
Co-authored-by: Jacob Richman <jacob314@gmail.com>
1 parent df8b399 commit 08e174a

6 files changed

Lines changed: 1361 additions & 34 deletions

File tree

packages/cli/src/ui/components/shared/text-buffer.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ const initialState: TextBufferState = {
6666
visualLayout: defaultVisualLayout,
6767
pastedContent: {},
6868
expandedPaste: null,
69+
yankRegister: null,
6970
};
7071

7172
/**

packages/cli/src/ui/components/shared/text-buffer.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ export interface TextBufferState {
15681568
visualLayout: VisualLayout;
15691569
pastedContent: Record<string, string>;
15701570
expandedPaste: ExpandedPasteInfo | null;
1571+
yankRegister: { text: string; linewise: boolean } | null;
15711572
}
15721573

15731574
const historyLimit = 100;
@@ -1722,6 +1723,14 @@ export type TextBufferAction =
17221723
type: 'vim_delete_to_char_backward';
17231724
payload: { char: string; count: number; till: boolean };
17241725
}
1726+
| { type: 'vim_yank_line'; payload: { count: number } }
1727+
| { type: 'vim_yank_word_forward'; payload: { count: number } }
1728+
| { type: 'vim_yank_big_word_forward'; payload: { count: number } }
1729+
| { type: 'vim_yank_word_end'; payload: { count: number } }
1730+
| { type: 'vim_yank_big_word_end'; payload: { count: number } }
1731+
| { type: 'vim_yank_to_end_of_line'; payload: { count: number } }
1732+
| { type: 'vim_paste_after'; payload: { count: number } }
1733+
| { type: 'vim_paste_before'; payload: { count: number } }
17251734
| {
17261735
type: 'toggle_paste_expansion';
17271736
payload: { id: string; row: number; col: number };
@@ -2510,6 +2519,14 @@ function textBufferReducerLogic(
25102519
case 'vim_find_char_backward':
25112520
case 'vim_delete_to_char_forward':
25122521
case 'vim_delete_to_char_backward':
2522+
case 'vim_yank_line':
2523+
case 'vim_yank_word_forward':
2524+
case 'vim_yank_big_word_forward':
2525+
case 'vim_yank_word_end':
2526+
case 'vim_yank_big_word_end':
2527+
case 'vim_yank_to_end_of_line':
2528+
case 'vim_paste_after':
2529+
case 'vim_paste_before':
25132530
return handleVimAction(state, action as VimAction);
25142531

25152532
case 'toggle_paste_expansion': {
@@ -2765,6 +2782,7 @@ export function useTextBuffer({
27652782
visualLayout,
27662783
pastedContent: {},
27672784
expandedPaste: null,
2785+
yankRegister: null,
27682786
};
27692787
}, [initialText, initialCursorOffset, viewport.width, viewport.height]);
27702788

@@ -3173,6 +3191,38 @@ export function useTextBuffer({
31733191
dispatch({ type: 'vim_escape_insert_mode' });
31743192
}, []);
31753193

3194+
const vimYankLine = useCallback((count: number): void => {
3195+
dispatch({ type: 'vim_yank_line', payload: { count } });
3196+
}, []);
3197+
3198+
const vimYankWordForward = useCallback((count: number): void => {
3199+
dispatch({ type: 'vim_yank_word_forward', payload: { count } });
3200+
}, []);
3201+
3202+
const vimYankBigWordForward = useCallback((count: number): void => {
3203+
dispatch({ type: 'vim_yank_big_word_forward', payload: { count } });
3204+
}, []);
3205+
3206+
const vimYankWordEnd = useCallback((count: number): void => {
3207+
dispatch({ type: 'vim_yank_word_end', payload: { count } });
3208+
}, []);
3209+
3210+
const vimYankBigWordEnd = useCallback((count: number): void => {
3211+
dispatch({ type: 'vim_yank_big_word_end', payload: { count } });
3212+
}, []);
3213+
3214+
const vimYankToEndOfLine = useCallback((count: number): void => {
3215+
dispatch({ type: 'vim_yank_to_end_of_line', payload: { count } });
3216+
}, []);
3217+
3218+
const vimPasteAfter = useCallback((count: number): void => {
3219+
dispatch({ type: 'vim_paste_after', payload: { count } });
3220+
}, []);
3221+
3222+
const vimPasteBefore = useCallback((count: number): void => {
3223+
dispatch({ type: 'vim_paste_before', payload: { count } });
3224+
}, []);
3225+
31763226
const openInExternalEditor = useCallback(async (): Promise<void> => {
31773227
const tmpDir = fs.mkdtempSync(pathMod.join(os.tmpdir(), 'gemini-edit-'));
31783228
const filePath = pathMod.join(tmpDir, 'buffer.txt');
@@ -3640,6 +3690,14 @@ export function useTextBuffer({
36403690
vimMoveToLastLine,
36413691
vimMoveToLine,
36423692
vimEscapeInsertMode,
3693+
vimYankLine,
3694+
vimYankWordForward,
3695+
vimYankBigWordForward,
3696+
vimYankWordEnd,
3697+
vimYankBigWordEnd,
3698+
vimYankToEndOfLine,
3699+
vimPasteAfter,
3700+
vimPasteBefore,
36433701
}),
36443702
[
36453703
lines,
@@ -3735,6 +3793,14 @@ export function useTextBuffer({
37353793
vimMoveToLastLine,
37363794
vimMoveToLine,
37373795
vimEscapeInsertMode,
3796+
vimYankLine,
3797+
vimYankWordForward,
3798+
vimYankBigWordForward,
3799+
vimYankWordEnd,
3800+
vimYankBigWordEnd,
3801+
vimYankToEndOfLine,
3802+
vimPasteAfter,
3803+
vimPasteBefore,
37383804
],
37393805
);
37403806
return returnValue;
@@ -4095,4 +4161,20 @@ export interface TextBuffer {
40954161
* Handle escape from insert mode (moves cursor left if not at line start)
40964162
*/
40974163
vimEscapeInsertMode: () => void;
4164+
/** Yank N lines into the unnamed register (vim 'yy' / 'Nyy') */
4165+
vimYankLine: (count: number) => void;
4166+
/** Yank forward N words into the unnamed register (vim 'yw') */
4167+
vimYankWordForward: (count: number) => void;
4168+
/** Yank forward N big words into the unnamed register (vim 'yW') */
4169+
vimYankBigWordForward: (count: number) => void;
4170+
/** Yank to end of N words into the unnamed register (vim 'ye') */
4171+
vimYankWordEnd: (count: number) => void;
4172+
/** Yank to end of N big words into the unnamed register (vim 'yE') */
4173+
vimYankBigWordEnd: (count: number) => void;
4174+
/** Yank from cursor to end of line into the unnamed register (vim 'y$') */
4175+
vimYankToEndOfLine: (count: number) => void;
4176+
/** Paste the unnamed register after cursor (vim 'p') */
4177+
vimPasteAfter: (count: number) => void;
4178+
/** Paste the unnamed register before cursor (vim 'P') */
4179+
vimPasteBefore: (count: number) => void;
40984180
}

0 commit comments

Comments
 (0)