From 19cb10f8729d2cc7b47cdcd4014635e4308e6f2e Mon Sep 17 00:00:00 2001 From: dethan3 Date: Tue, 10 Feb 2026 11:31:10 +0800 Subject: [PATCH] feat: add Delete key support (forward delete) Separate Backspace and Delete key behavior in the CLI input: - Backspace: delete character before cursor (unchanged) - Delete: delete character at cursor (new) - Ctrl/Option+Backspace: delete word backward (unchanged) - Ctrl/Option+Delete: delete word forward (new) Closes #80 --- src/components/Input.tsx | 18 +++++++++++++++--- src/hooks/useTextBuffer.ts | 25 ++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 9c80e117..0b7822e6 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -91,17 +91,29 @@ export function Input({ onSubmit, historyValue, onHistoryNavigate }: InputProps) } // Option+Backspace (Mac) / Ctrl+Backspace (Windows) - delete word backward - if ((key.meta || key.ctrl) && (key.backspace || key.delete)) { + if ((key.meta || key.ctrl) && key.backspace) { actions.deleteWordBackward(); return; } - // Handle backspace/delete - delete character before cursor - if (key.backspace || key.delete) { + // Option+Delete (Mac) / Ctrl+Delete (Windows) - delete word forward + if ((key.meta || key.ctrl) && key.delete) { + actions.deleteWordForward(); + return; + } + + // Backspace - delete character before cursor + if (key.backspace) { actions.deleteBackward(); return; } + // Delete - delete character at cursor + if (key.delete) { + actions.deleteForward(); + return; + } + // Shift+Enter - insert newline for multi-line input if (key.return && key.shift) { actions.insert('\n'); diff --git a/src/hooks/useTextBuffer.ts b/src/hooks/useTextBuffer.ts index 3ba6ed07..07d245a9 100644 --- a/src/hooks/useTextBuffer.ts +++ b/src/hooks/useTextBuffer.ts @@ -1,13 +1,17 @@ import { useRef, useState, useCallback } from 'react'; -import { findPrevWordStart } from '../utils/text-navigation.js'; +import { findPrevWordStart, findNextWordEnd } from '../utils/text-navigation.js'; export interface TextBufferActions { /** Insert text at the current cursor position */ insert: (text: string) => void; /** Delete the character before the cursor */ deleteBackward: () => void; + /** Delete the character at the cursor */ + deleteForward: () => void; /** Delete from cursor back to start of previous word */ deleteWordBackward: () => void; + /** Delete from cursor forward to end of next word */ + deleteWordForward: () => void; /** Move cursor to an absolute position (clamped to valid range) */ moveCursor: (position: number) => void; /** Clear the buffer and reset cursor to 0 */ @@ -60,6 +64,15 @@ export function useTextBuffer(): UseTextBufferResult { } }, + deleteForward: () => { + if (cursorPos.current < buffer.current.length) { + buffer.current = + buffer.current.slice(0, cursorPos.current) + + buffer.current.slice(cursorPos.current + 1); + rerender(); + } + }, + deleteWordBackward: () => { if (cursorPos.current > 0) { const wordStart = findPrevWordStart(buffer.current, cursorPos.current); @@ -71,6 +84,16 @@ export function useTextBuffer(): UseTextBufferResult { } }, + deleteWordForward: () => { + if (cursorPos.current < buffer.current.length) { + const wordEnd = findNextWordEnd(buffer.current, cursorPos.current); + buffer.current = + buffer.current.slice(0, cursorPos.current) + + buffer.current.slice(wordEnd); + rerender(); + } + }, + moveCursor: (position: number) => { cursorPos.current = Math.max(0, Math.min(buffer.current.length, position)); rerender();