Conversation
Summary of changes:
1. crates/repl/src/app.rs:
- Added Shift+Enter handler that detects SHIFT or ALT modifiers (macOS terminals report Shift+Enter as ALT)
- Also handles Char('\n') for terminals that send that instead
- Multiline input rendering with .... continuation prompt
2. crates/repl/src/ui/repl_pane.rs:
- Rewrote build_lines() to split input by newlines and render each line separately
- Cursor position correctly tracked across multiple lines
- History entries also handle multiline display
- Enabled text wrapping with proper scroll calculation
3. crates/repl/src/main.rs:
- Added keyboard enhancement flags for better modifier detection
The REPL now supports:
- Shift+Enter to insert newlines for multiline input
- Text wrapping for long lines
- Continuation prompt (.... ) for multiline entries
PR Review: Multiline Input SupportThank you for implementing multiline input support for the REPL! This is a valuable feature that enhances the user experience. Here's my detailed review: ✅ Strengths
🐛 Potential BugsCritical: Cursor Position Logic Issue (crates/repl/src/ui/repl_pane.rs:293-309)The cursor position calculation has a subtle bug when the cursor is at the end of input: for (i, line_text) in input_lines.iter().enumerate() {
let line_end = pos + line_text.len();
if self.state.cursor <= line_end { // ⚠️ Problem here
line_idx = i;
col = self.state.cursor - pos;
break;
}
pos = line_end + 1;
line_idx = i + 1; // This executes after the last line
}Issue: When cursor is past all lines (e.g., at position after the final newline), Test case that would fail:
Suggested fix: let mut line_idx = 0;
let mut col = self.state.cursor;
let mut pos = 0;
for (i, line_text) in input_lines.iter().enumerate() {
let line_end = pos + line_text.len();
if self.state.cursor <= line_end {
line_idx = i;
col = self.state.cursor - pos;
break;
}
pos = line_end + 1;
}
// Clamp line_idx to valid range
line_idx = line_idx.min(input_lines.len().saturating_sub(1));
|
…feedback addressed:
Fixes made:
1. Critical bug fixed - Cursor position now clamped to valid range for trailing newlines:
line_idx = line_idx.min(input_lines.len().saturating_sub(1));
2. Added CONTINUATION_PROMPT constant - No more magic string duplication
3. Fixed potential overflow - Using saturating arithmetic for wrapped height:
.fold(0u16, |acc, h| acc.saturating_add(h))
4. Added 4 multiline tests:
- test_multiline_input_rendering
- test_cursor_position_trailing_newline
- test_cursor_position_empty_lines
- test_multiline_history_entry
5. Updated README - Added Editing section documenting Shift+Enter, Tab, and F1/F2/F3
Code Review - PR #184: Multiline Input SupportSummaryThis PR successfully implements multiline input support for the REPL with Shift+Enter functionality, along with comprehensive test coverage and documentation updates. The implementation addresses issue #177 and includes important bug fixes discovered during development. ✅ Strengths1. Excellent Bug Fixes
2. Cross-Platform CompatibilityThe implementation handles terminal inconsistencies gracefully (
This is well-documented and shows strong awareness of real-world terminal behavior. 3. Test CoverageFour new multiline tests added:
The tests target the exact bugs that were fixed, which is excellent practice. 4. Code Organization
🔍 Issues & Concerns1. Performance: Redundant String Splitting (Medium Priority)In let input_lines: Vec<&str> = self.state.input.split('\n').collect();
// ... cursor calculation loop ...
for (i, line_text) in input_lines.iter().enumerate() { // Line 299Then immediately after at line 318, we iterate through for (i, line_text) in input_lines.iter().enumerate() { // Line 318Issue: For every render (which happens frequently in a TUI), we're splitting the input string and iterating twice. Impact:
Recommendation: Consider combining the cursor calculation and rendering into a single pass, or cache the split result if 2. Potential Panic in Cursor Position Calculation (Low-Medium Priority)In let col = col.min(input_lines.get(line_idx).map_or(0, |l| l.len()));While the line index is clamped at line 310, there's a subtle logic issue: The loop at line 299-308 sets However, the Example scenario:
But with trailing newline:
Recommendation: Recalculate 3. Expanded Builtin Completions List (Minor)The Observations:
Questions:
Recommendation: Consider adding a comment or TODO about potentially auto-generating this from the compiler's builtin definitions in the future. 4. Missing Edge Case Test (Low Priority)Test coverage gap: No test for cursor navigation within multiline input (e.g., moving cursor with arrow keys between lines). While the rendering is tested, it would be valuable to verify that:
🔒 Security Considerations✅ No security concerns identified. The code:
🎯 Performance Considerations
📝 Code QualityOverall: Good Positives:
Minor style notes:
📚 Documentation✅ Excellent: README updated with clear Editing section documenting Shift+Enter, Tab, and F1/F2/F3 keys 🧪 Test Coverage✅ Good: 4 new tests covering the multiline functionality and edge cases Suggestions:
🎯 RecommendationsHigh PriorityNone - the critical bugs are already fixed! Medium Priority
Low Priority
✨ Final AssessmentOverall: LGTM with minor suggestions This is a well-implemented feature with:
The performance and logic clarity concerns are minor and don't block merging. They could be addressed in a follow-up PR if desired. Great work on the defensive programming and comprehensive testing! 🎉 |
Summary of changes:
#177
- Added Shift+Enter handler that detects SHIFT or ALT modifiers (macOS terminals report Shift+Enter as ALT)
- Also handles Char('\n') for terminals that send that instead
- Multiline input rendering with .... continuation prompt
- Rewrote build_lines() to split input by newlines and render each line separately
- Cursor position correctly tracked across multiple lines
- History entries also handle multiline display
- Enabled text wrapping with proper scroll calculation
- Added keyboard enhancement flags for better modifier detection
The REPL now supports: