Skip to content

Commit 77f1bd0

Browse files
fix: add null/undefined checks for lineInfo.lineStartCols to prevent runtime errors
- Add safety check for lineInfo.lineStartCols existence before accessing it - Prevents 'undefined is not an object' error when OpenTUI TextBufferView doesn't populate lineStartCols - Fixes issue where CLI would crash on startup with TypeError
1 parent 67e6256 commit 77f1bd0

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

cli/src/components/multiline-input.tsx

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,16 @@ const TAB_WIDTH = 4
8989
*/
9090
function isPrintableCharacterKey(key: KeyEvent): boolean {
9191
const name = key.name
92-
92+
9393
// No name = likely multi-byte input (Chinese, Japanese, Korean, etc.) - treat as printable
9494
if (!name) return true
95-
95+
9696
// Single character name = regular ASCII printable (a, b, 1, $, etc.)
9797
if (name.length === 1) return true
98-
98+
9999
// Special case: space key has name 'space' but is printable
100100
if (name === 'space') return true
101-
101+
102102
// Multi-char name = special key (up, f1, backspace, etc.)
103103
return false
104104
}
@@ -122,8 +122,8 @@ function renderPositionToOriginal(text: string, renderPos: number): number {
122122

123123
type KeyWithPreventDefault =
124124
| {
125-
preventDefault?: () => void
126-
}
125+
preventDefault?: () => void
126+
}
127127
| null
128128
| undefined
129129

@@ -136,9 +136,9 @@ function isAltModifier(key: KeyEvent): boolean {
136136
const ESC = '\x1b'
137137
return Boolean(
138138
key.option ||
139-
(key.sequence?.length === 2 &&
140-
key.sequence[0] === ESC &&
141-
key.sequence[1] !== '['),
139+
(key.sequence?.length === 2 &&
140+
key.sequence[0] === ESC &&
141+
key.sequence[1] !== '['),
142142
)
143143
}
144144

@@ -241,9 +241,9 @@ export const MultilineInput = forwardRef<
241241

242242
const lineInfo = textRef.current
243243
? (
244-
(textRef.current satisfies TextRenderable as any)
245-
.textBufferView as TextBufferView
246-
).lineInfo
244+
(textRef.current satisfies TextRenderable as any)
245+
.textBufferView as TextBufferView
246+
).lineInfo
247247
: null
248248

249249
// Focus/blur scrollbox when focused prop changes
@@ -271,13 +271,13 @@ export const MultilineInput = forwardRef<
271271
[],
272272
)
273273

274-
const cursorRow = lineInfo
274+
const cursorRow = lineInfo && lineInfo.lineStartCols
275275
? Math.max(
276-
0,
277-
lineInfo.lineStartCols.findLastIndex(
278-
(lineStart) => lineStart <= cursorPosition,
279-
),
280-
)
276+
0,
277+
lineInfo.lineStartCols.findLastIndex(
278+
(lineStart) => lineStart <= cursorPosition,
279+
),
280+
)
281281
: 0
282282

283283
// Auto-scroll to cursor when content changes
@@ -314,7 +314,7 @@ export const MultilineInput = forwardRef<
314314
// Helper to clear the current selection
315315
const clearSelection = useCallback(() => {
316316
// Use renderer's clearSelection for proper visual clearing
317-
;(renderer as any)?.clearSelection?.()
317+
; (renderer as any)?.clearSelection?.()
318318
}, [renderer])
319319

320320
// Helper to delete selected text and return new value and cursor position
@@ -1091,7 +1091,7 @@ export const MultilineInput = forwardRef<
10911091
const effectiveMinHeight = Math.max(1, Math.min(minHeight, safeMaxHeight))
10921092

10931093
const totalLines =
1094-
lineInfo === null ? 0 : lineInfo.lineStartCols.length
1094+
lineInfo === null || !lineInfo.lineStartCols ? 0 : lineInfo.lineStartCols.length
10951095

10961096
// Add bottom gutter when cursor is on line 2 of exactly 2 lines
10971097
const gutterEnabled =

0 commit comments

Comments
 (0)