Skip to content

Commit 79b81af

Browse files
committed
fix: Stop replxx aborting when navigating multi-line buffers
mgconsole assembles multi-line queries itself via the continuation prompt and does not use replxx's in-buffer multiline editing, which is buggy in the pinned release-0.0.4. history_previous() calls prev_newline_position(_pos - 1) without the `_pos > 0` guard its sibling history_next() has; with a newline at buffer position 0 (navigating up through a recalled multi-line history entry) it passes -1 and trips an assertion that aborts the process. Separately, in-buffer multiline redraws clear to end of screen and erase already-printed output. Patch replxx (replxx-patches/, applied via the replxx-proj PATCH_COMMAND) to add the missing bounds guard to history_previous. This fixes the abort for any newline-bearing buffer, including multi-line entries decoded from the history file. Rebind Ctrl-J (line feed, 0x0A) to commit_line so a bare newline submits the current line like Enter instead of feeding replxx's NEW_LINE action. A multi-line paste then submits one physical line at a time, which is what GetQuery expects, and keeps pasted or typed newlines out of the buffer so the redraw corruption stays unreachable for the common paste case. It does not cover newlines that arrive from history, which is why the bounds guard is the actual crash fix.
1 parent f4a1c3b commit 79b81af

4 files changed

Lines changed: 53 additions & 0 deletions

File tree

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# git apply needs LF context lines to match an LF-checked-out source tree;
2+
# Windows autocrlf would otherwise rewrite these to CRLF and break the patch.
3+
*.patch text eol=lf

src/utils/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,24 @@ else()
99
endif()
1010

1111
get_filename_component(REPLXX_LIB_PATH "${REPLXX_PREFIX}/${MG_INSTALL_LIB_DIR}/libreplxx${REPLXX_LIB_POSTFIX}.a" ABSOLUTE)
12+
13+
# Local fixes applied on top of the pinned replxx tag.
14+
find_package(Git REQUIRED)
1215
ExternalProject_Add(replxx-proj
1316
PREFIX ${REPLXX_PREFIX}
1417
GIT_REPOSITORY https://github.com/AmokHuginnsson/replxx.git
1518
GIT_TAG release-0.0.4
19+
# Force an LF checkout so the LF patch below applies. Windows/MSYS2 git
20+
# defaults to core.autocrlf=true, which rewrites the sources with CRLF
21+
# endings and makes the patch fail with "patch does not apply" (the
22+
# trailing-CR context lines no longer match). --config persists into the
23+
# cloned repo, so the update-step checkout stays LF too.
24+
GIT_CONFIG core.autocrlf=false
25+
# --3way makes this idempotent: the patch step chains off the git
26+
# update step and can re-run, and --3way no-ops cleanly when the fix is
27+
# already present (plain `git apply` would error "patch does not apply").
28+
PATCH_COMMAND ${GIT_EXECUTABLE} apply --3way
29+
"${CMAKE_CURRENT_SOURCE_DIR}/replxx-patches/0001-history_previous-bounds-check.patch"
1630
CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>"
1731
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
1832
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Add the missing bounds guard to ReplxxImpl::history_previous.
2+
3+
When the edit buffer contains newlines and the cursor sits on a newline at
4+
position 0, history_previous indexed prev_newline_position(_pos - 1), that is
5+
prev_newline_position(-1), tripping the `pos_ >= 0` assertion and aborting the
6+
process. history_next already guards the symmetric case with
7+
`_pos > 0 ? ... : -1`; apply the same guard so navigating up through a
8+
multi-line buffer falls through to history_move instead of aborting.
9+
10+
Not fixed in the pinned upstream tag.
11+
12+
diff --git a/src/replxx_impl.cxx b/src/replxx_impl.cxx
13+
index 22ee748..24a63b8 100644
14+
--- a/src/replxx_impl.cxx
15+
+++ b/src/replxx_impl.cxx
16+
@@ -1831,7 +1831,7 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_previous( char32_t ) {
17+
}
18+
int prevNewlinePosition( prev_newline_position( _pos ) );
19+
if ( prevNewlinePosition == _pos ) {
20+
- prevNewlinePosition = prev_newline_position( _pos - 1 );
21+
+ prevNewlinePosition = _pos > 0 ? prev_newline_position( _pos - 1 ) : -1;
22+
}
23+
if ( prevNewlinePosition < 0 ) {
24+
break;

src/utils/utils.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,18 @@ Replxx *InitAndSetupReplxx() {
13241324
replxx_set_unique_history(replxx_instance, 1);
13251325
replxx_set_completion_callback(replxx_instance, CompletionHook, nullptr);
13261326

1327+
// Treat a bare line feed (Ctrl-J / 0x0A) like Enter: commit the current line
1328+
// instead of feeding replxx's NEW_LINE action. mgconsole assembles multi-line
1329+
// queries itself via the continuation prompt, so a multi-line paste should
1330+
// submit one physical line at a time rather than accumulate in replxx's edit
1331+
// buffer, whose in-buffer multiline redraw clears to end of screen and erases
1332+
// already-printed output.
1333+
//
1334+
// This only keeps typed and pasted newlines out of the buffer. A recalled
1335+
// multi-line history entry still contains them, so replxx's multiline cursor
1336+
// navigation has to stay correct independently of this bind.
1337+
replxx_bind_key_internal(replxx_instance, REPLXX_KEY_CONTROL('J'), "commit_line");
1338+
13271339
// ToDo(the-joksim):
13281340
// - syntax highlighting disabled for now - figure out a smarter way of
13291341
// picking the right colors depending on the user's terminal settings

0 commit comments

Comments
 (0)