@@ -12,6 +12,7 @@ import {
1212
1313import { useOpentuiPaste } from '../hooks/use-opentui-paste'
1414import { useTheme } from '../hooks/use-theme'
15+ import { clamp } from '../utils/math'
1516import { computeInputLayoutMetrics } from '../utils/text-layout'
1617
1718import type { InputValue } from '../state/chat-store'
@@ -90,7 +91,6 @@ interface MultilineInputProps {
9091 width : number
9192 textAttributes ?: number
9293 cursorPosition : number
93- setCursorPosition : ( position : number ) => void
9494}
9595
9696export type MultilineInputHandle = {
@@ -112,7 +112,6 @@ export const MultilineInput = forwardRef<
112112 textAttributes,
113113 onKeyIntercept,
114114 cursorPosition,
115- setCursorPosition,
116115 } : MultilineInputProps ,
117116 forwardedRef ,
118117) {
@@ -143,12 +142,10 @@ export const MultilineInput = forwardRef<
143142
144143 // Sync cursor when value changes externally
145144 useEffect ( ( ) => {
146- if ( cursorPosition > value . length ) {
147- setCursorPosition ( value . length )
148- }
149- if ( cursorPosition < 0 ) {
150- setCursorPosition ( 0 )
151- }
145+ onChange ( ( prev ) => ( {
146+ ...prev ,
147+ cursorPosition : clamp ( cursorPosition , 0 , value . length ) ,
148+ } ) )
152149 } , [ value . length , cursorPosition ] )
153150
154151 useOpentuiPaste (
@@ -467,7 +464,11 @@ export const MultilineInput = forwardRef<
467464 ( key . name === 'left' || lowerKeyName === 'b' )
468465 ) {
469466 preventKeyDefault ( key )
470- setCursorPosition ( wordStart )
467+ onChange ( {
468+ text : value ,
469+ cursorPosition : wordStart ,
470+ lastEditDueToNav : false ,
471+ } )
471472 return
472473 }
473474
@@ -477,7 +478,11 @@ export const MultilineInput = forwardRef<
477478 ( key . name === 'right' || lowerKeyName === 'f' )
478479 ) {
479480 preventKeyDefault ( key )
480- setCursorPosition ( wordEnd )
481+ onChange ( {
482+ text : value ,
483+ cursorPosition : wordEnd ,
484+ lastEditDueToNav : false ,
485+ } )
481486 return
482487 }
483488
@@ -488,7 +493,11 @@ export const MultilineInput = forwardRef<
488493 ( key . name === 'home' && ! key . ctrl && ! key . meta )
489494 ) {
490495 preventKeyDefault ( key )
491- setCursorPosition ( lineStart )
496+ onChange ( {
497+ text : value ,
498+ cursorPosition : lineStart ,
499+ lastEditDueToNav : false ,
500+ } )
492501 return
493502 }
494503
@@ -499,7 +508,11 @@ export const MultilineInput = forwardRef<
499508 ( key . name === 'end' && ! key . ctrl && ! key . meta )
500509 ) {
501510 preventKeyDefault ( key )
502- setCursorPosition ( lineEnd )
511+ onChange ( {
512+ text : value ,
513+ cursorPosition : lineEnd ,
514+ lastEditDueToNav : false ,
515+ } )
503516 return
504517 }
505518
@@ -509,7 +522,7 @@ export const MultilineInput = forwardRef<
509522 ( key . ctrl && key . name === 'home' )
510523 ) {
511524 preventKeyDefault ( key )
512- setCursorPosition ( 0 )
525+ onChange ( { text : value , cursorPosition : 0 , lastEditDueToNav : false } )
513526 return
514527 }
515528
@@ -519,48 +532,76 @@ export const MultilineInput = forwardRef<
519532 ( key . ctrl && key . name === 'end' )
520533 ) {
521534 preventKeyDefault ( key )
522- setCursorPosition ( value . length )
535+ onChange ( {
536+ text : value ,
537+ cursorPosition : value . length ,
538+ lastEditDueToNav : false ,
539+ } )
523540 return
524541 }
525542
526543 // Ctrl+B: Backward char (Emacs)
527544 if ( key . ctrl && lowerKeyName === 'b' && ! key . meta && ! key . option ) {
528545 preventKeyDefault ( key )
529- setCursorPosition ( Math . max ( 0 , cursorPosition - 1 ) )
546+ onChange ( {
547+ text : value ,
548+ cursorPosition : cursorPosition - 1 ,
549+ lastEditDueToNav : false ,
550+ } )
530551 return
531552 }
532553
533554 // Ctrl+F: Forward char (Emacs)
534555 if ( key . ctrl && lowerKeyName === 'f' && ! key . meta && ! key . option ) {
535556 preventKeyDefault ( key )
536- setCursorPosition ( Math . min ( value . length , cursorPosition + 1 ) )
557+ onChange ( {
558+ text : value ,
559+ cursorPosition : Math . min ( value . length , cursorPosition + 1 ) ,
560+ lastEditDueToNav : false ,
561+ } )
537562 return
538563 }
539564
540565 // Left arrow (no modifiers)
541566 if ( key . name === 'left' && ! key . ctrl && ! key . meta && ! key . option ) {
542567 preventKeyDefault ( key )
543- setCursorPosition ( Math . max ( 0 , cursorPosition - 1 ) )
568+ onChange ( {
569+ text : value ,
570+ cursorPosition : cursorPosition - 1 ,
571+ lastEditDueToNav : false ,
572+ } )
544573 return
545574 }
546575
547576 // Right arrow (no modifiers)
548577 if ( key . name === 'right' && ! key . ctrl && ! key . meta && ! key . option ) {
549578 preventKeyDefault ( key )
550- setCursorPosition ( Math . min ( value . length , cursorPosition + 1 ) )
579+ onChange ( {
580+ text : value ,
581+ cursorPosition : cursorPosition + 1 ,
582+ lastEditDueToNav : false ,
583+ } )
551584 return
552585 }
553586
554587 // Up arrow (no modifiers)
555588 if ( key . name === 'up' && ! key . ctrl && ! key . meta && ! key . option ) {
556589 preventKeyDefault ( key )
557- setCursorPosition ( cursorPosition - getEffectiveCols ( ) )
590+ onChange ( {
591+ text : value ,
592+ cursorPosition : cursorPosition - getEffectiveCols ( ) ,
593+ lastEditDueToNav : false ,
594+ } )
558595 }
559596
560597 // Down arrow (no modifiers)
561598 if ( key . name === 'down' && ! key . ctrl && ! key . meta && ! key . option ) {
562599 preventKeyDefault ( key )
563- setCursorPosition ( cursorPosition + getEffectiveCols ( ) )
600+ onChange ( {
601+ text : value ,
602+ cursorPosition : cursorPosition + getEffectiveCols ( ) ,
603+ lastEditDueToNav : false ,
604+ } )
564605 }
565606
566607 // Regular character input
0 commit comments