feat: add kill and yank commands (#165)

This commit is contained in:
cthomas
2025-12-09 15:12:44 -08:00
committed by GitHub
parent e8bd2e6537
commit e0c4ac8163

View File

@@ -28,8 +28,8 @@ function isControlSequence(input, key) {
} }
function TextInput({ value: originalValue, placeholder = '', focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit, externalCursorOffset, onCursorOffsetChange }) { function TextInput({ value: originalValue, placeholder = '', focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit, externalCursorOffset, onCursorOffsetChange }) {
const [state, setState] = useState({ cursorOffset: (originalValue || '').length, cursorWidth: 0 }); const [state, setState] = useState({ cursorOffset: (originalValue || '').length, cursorWidth: 0, killBuffer: '' });
const { cursorOffset, cursorWidth } = state; const { cursorOffset, cursorWidth, killBuffer } = state;
useEffect(() => { useEffect(() => {
setState(previousState => { setState(previousState => {
if (!focus || !showCursor) { if (!focus || !showCursor) {
@@ -37,7 +37,7 @@ function TextInput({ value: originalValue, placeholder = '', focus = true, mask,
} }
const newValue = originalValue || ''; const newValue = originalValue || '';
if (previousState.cursorOffset > newValue.length - 1) { if (previousState.cursorOffset > newValue.length - 1) {
return { cursorOffset: newValue.length, cursorWidth: 0 }; return { ...previousState, cursorOffset: newValue.length, cursorWidth: 0 };
} }
return previousState; return previousState;
}); });
@@ -46,7 +46,7 @@ function TextInput({ value: originalValue, placeholder = '', focus = true, mask,
if (typeof externalCursorOffset === 'number') { if (typeof externalCursorOffset === 'number') {
const newValue = originalValue || ''; const newValue = originalValue || '';
const clamped = Math.max(0, Math.min(externalCursorOffset, newValue.length)); const clamped = Math.max(0, Math.min(externalCursorOffset, newValue.length));
setState(prev => ({ cursorOffset: clamped, cursorWidth: 0 })); setState(prev => ({ ...prev, cursorOffset: clamped, cursorWidth: 0 }));
if (typeof onCursorOffsetChange === 'function') onCursorOffsetChange(clamped); if (typeof onCursorOffsetChange === 'function') onCursorOffsetChange(clamped);
} }
}, [externalCursorOffset, originalValue, onCursorOffsetChange]); }, [externalCursorOffset, originalValue, onCursorOffsetChange]);
@@ -80,6 +80,7 @@ function TextInput({ value: originalValue, placeholder = '', focus = true, mask,
let nextCursorOffset = cursorOffset; let nextCursorOffset = cursorOffset;
let nextValue = originalValue; let nextValue = originalValue;
let nextCursorWidth = 0; let nextCursorWidth = 0;
let nextKillBuffer = killBuffer;
if (key.leftArrow || key.rightArrow) { if (key.leftArrow || key.rightArrow) {
// Skip if meta is pressed - Option+Arrow is handled by parent for word navigation // Skip if meta is pressed - Option+Arrow is handled by parent for word navigation
if (key.meta) { if (key.meta) {
@@ -115,6 +116,28 @@ function TextInput({ value: originalValue, placeholder = '', focus = true, mask,
nextCursorOffset = originalValue.length; nextCursorOffset = originalValue.length;
} }
} }
else if (key.ctrl && input === 'k') {
// CTRL-K: kill from cursor to end of line
if (cursorOffset < originalValue.length) {
nextKillBuffer = originalValue.slice(cursorOffset);
nextValue = originalValue.slice(0, cursorOffset);
}
}
else if (key.ctrl && input === 'u') {
// CTRL-U: kill from beginning to cursor
if (cursorOffset > 0) {
nextKillBuffer = originalValue.slice(0, cursorOffset);
nextValue = originalValue.slice(cursorOffset);
nextCursorOffset = 0;
}
}
else if (key.ctrl && input === 'y') {
// CTRL-Y: yank (paste) from kill buffer
if (killBuffer) {
nextValue = originalValue.slice(0, cursorOffset) + killBuffer + originalValue.slice(cursorOffset);
nextCursorOffset = cursorOffset + killBuffer.length;
}
}
else { else {
nextValue = originalValue.slice(0, cursorOffset) + input + originalValue.slice(cursorOffset, originalValue.length); nextValue = originalValue.slice(0, cursorOffset) + input + originalValue.slice(cursorOffset, originalValue.length);
nextCursorOffset += input.length; nextCursorOffset += input.length;
@@ -123,7 +146,7 @@ function TextInput({ value: originalValue, placeholder = '', focus = true, mask,
} }
} }
nextCursorOffset = Math.max(0, Math.min(nextCursorOffset, nextValue.length)); nextCursorOffset = Math.max(0, Math.min(nextCursorOffset, nextValue.length));
setState({ cursorOffset: nextCursorOffset, cursorWidth: nextCursorWidth }); setState(prev => ({ ...prev, cursorOffset: nextCursorOffset, cursorWidth: nextCursorWidth, killBuffer: nextKillBuffer }));
if (typeof onCursorOffsetChange === 'function') onCursorOffsetChange(nextCursorOffset); if (typeof onCursorOffsetChange === 'function') onCursorOffsetChange(nextCursorOffset);
if (nextValue !== originalValue) { if (nextValue !== originalValue) {
onChange(nextValue); onChange(nextValue);