Skip to content

Commit 42a3a3e

Browse files
committed
fix(inquirerer): use inverse video cursor and add Ctrl+J for newlines
- Replace block cursor character with inverse video on current char - This fixes the jittery cursor that shifted text due to width differences - Add CTRL_J as fallback for newline insertion since Shift+Enter doesn't work in most terminals without special configuration - Update help text to show Ctrl+J instead of Shift+Enter
1 parent 80eeaab commit 42a3a3e

2 files changed

Lines changed: 9 additions & 7 deletions

File tree

packages/inquirerer/src/keypress.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const KEY_CODES = {
3838
CTRL_P: '\u0010', // Previous (up)
3939
CTRL_F: '\u0006', // Forward (right)
4040
CTRL_B: '\u0002', // Back (left)
41+
CTRL_J: '\u000a', // Newline (fallback for Shift+Enter)
4142

4243
// Alt/Meta key combinations (escape sequences)
4344
// Note: Alt key sends ESC followed by the character

packages/inquirerer/src/ui/aicode.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*/
1313

1414
import { Readable, Writable } from 'stream';
15-
import { cyan, dim, green, white, yellow, blue } from 'yanse';
15+
import { cyan, dim, green, white, yellow, blue, inverse } from 'yanse';
1616
import { TerminalKeypress, KEY_CODES } from '../keypress';
1717
import { ViewportRenderer, createViewport } from './viewport';
1818

@@ -417,7 +417,7 @@ export class AICodeUI {
417417
{ keys: [KEY_CODES.CTRL_K], action: () => this.killToEnd(), description: 'Kill to end of line' },
418418
{ keys: [KEY_CODES.CTRL_U], action: () => this.killToStart(), description: 'Kill to start of line' },
419419
{ keys: [KEY_CODES.ENTER], action: () => this.submit(), description: 'Submit input' },
420-
{ keys: [KEY_CODES.SHIFT_ENTER, KEY_CODES.SHIFT_ENTER_ALT], action: () => this.insertNewline(), description: 'Insert newline' },
420+
{ keys: [KEY_CODES.SHIFT_ENTER, KEY_CODES.SHIFT_ENTER_ALT, KEY_CODES.CTRL_J], action: () => this.insertNewline(), description: 'Insert newline' },
421421
{ keys: [KEY_CODES.CTRL_C], action: () => this.exit(), description: 'Exit' },
422422
{ keys: [KEY_CODES.CTRL_L], action: () => this.clearScreen(), description: 'Clear screen' },
423423
];
@@ -727,11 +727,11 @@ export class AICodeUI {
727727
visibleLines[0] = green('AI: ') + visibleLines[0];
728728
}
729729

730-
// Add cursor indicator if streaming
730+
// Add cursor indicator if streaming (inverse video on space at end)
731731
if (this.cursorVisible) {
732732
const lastIdx = visibleLines.length - 1;
733733
if (lastIdx >= 0) {
734-
visibleLines[lastIdx] += cyan('▋');
734+
visibleLines[lastIdx] += inverse(' ');
735735
}
736736
}
737737

@@ -748,7 +748,7 @@ export class AICodeUI {
748748

749749
if (this.messages.length === 0) {
750750
lines.push(dim('No messages yet. Type a message and press Enter.'));
751-
lines.push(dim('Shift+Enter for newline, UP/DOWN for history, PageUp/PageDown to scroll.'));
751+
lines.push(dim('Ctrl+J for newline, UP/DOWN for history, PageUp/PageDown to scroll.'));
752752
return lines;
753753
}
754754

@@ -779,8 +779,9 @@ export class AICodeUI {
779779
const prefix = idx === 0 ? blue(this.promptPrefix) : blue(' ');
780780
if (idx === this.lineEditor.lineIndex && this.cursorVisible && !this.isStreaming) {
781781
const before = line.slice(0, this.lineEditor.cursorPos);
782-
const after = line.slice(this.lineEditor.cursorPos);
783-
lines.push(prefix + before + cyan('▋') + after);
782+
const cursorChar = line[this.lineEditor.cursorPos] || ' ';
783+
const after = line.slice(this.lineEditor.cursorPos + 1);
784+
lines.push(prefix + before + inverse(cursorChar) + after);
784785
} else {
785786
lines.push(prefix + line);
786787
}

0 commit comments

Comments
 (0)