Command.cc: share the word scans, search reset and completion prefix
Word motion (M-b/M-f) and word deletion (M-Backspace/M-d) each carried a copy of the same backward and forward scans; word_back and word_forward now serve both. Deleting N words backwards built the kill text by prepending each piece (quadratic in N); the pieces are joined once. The five-call search reset appeared nine times (end_search), and the completion longest-common-prefix loop twice (keep_common_prefix). A new test pins word motion and deletion with counts across line ends and punctuation; it gives the same results on the code before this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
@@ -131,3 +131,55 @@ TEST(CommandSemantics_Syntax_OnOff_SetsUserOverride)
|
||||
ASSERT_EQ(b.SyntaxEnabled(), true);
|
||||
ASSERT_EQ(b.SyntaxUserOverride(), true);
|
||||
}
|
||||
|
||||
|
||||
// Word motion and word deletion with counts, across line ends and
|
||||
// punctuation; deleting backwards N words kills them in text order.
|
||||
TEST(CommandSemantics_WordMotionAndDelete_WithCounts)
|
||||
{
|
||||
const std::string text = "alpha beta, gamma\n\n delta.epsilon zeta\nend";
|
||||
struct Pos {
|
||||
std::size_t x, y;
|
||||
};
|
||||
auto run_motion = [&](CommandId id, Pos start, int count) {
|
||||
TestHarness h;
|
||||
h.Buf().insert_text(0, 0, text);
|
||||
h.Buf().SetCursor(start.x, start.y);
|
||||
(void) h.Exec(id, "", count);
|
||||
return Pos{h.Buf().Curx(), h.Buf().Cury()};
|
||||
};
|
||||
Pos p = run_motion(CommandId::WordNext, {0, 0}, 1);
|
||||
ASSERT_EQ(p.x, (std::size_t) 6);
|
||||
p = run_motion(CommandId::WordNext, {0, 0}, 3);
|
||||
ASSERT_EQ(p.y, (std::size_t) 2);
|
||||
ASSERT_EQ(p.x, (std::size_t) 2);
|
||||
p = run_motion(CommandId::WordNext, {0, 0}, 5);
|
||||
ASSERT_EQ(p.y, (std::size_t) 2);
|
||||
ASSERT_EQ(p.x, (std::size_t) 16);
|
||||
p = run_motion(CommandId::WordPrev, {3, 3}, 1);
|
||||
ASSERT_EQ(p.y, (std::size_t) 3);
|
||||
ASSERT_EQ(p.x, (std::size_t) 0);
|
||||
p = run_motion(CommandId::WordPrev, {3, 3}, 3);
|
||||
ASSERT_EQ(p.y, (std::size_t) 2);
|
||||
ASSERT_EQ(p.x, (std::size_t) 8);
|
||||
p = run_motion(CommandId::WordPrev, {3, 3}, 50);
|
||||
ASSERT_EQ(p.y, (std::size_t) 0);
|
||||
ASSERT_EQ(p.x, (std::size_t) 0);
|
||||
|
||||
{
|
||||
TestHarness h;
|
||||
h.Buf().insert_text(0, 0, text);
|
||||
h.Buf().SetCursor(3, 3);
|
||||
ASSERT_TRUE(h.Exec(CommandId::DeleteWordPrev, "", 3));
|
||||
ASSERT_EQ(h.Text(), std::string("alpha beta, gamma\n\n delta."));
|
||||
ASSERT_EQ(h.EditorRef().KillRingHead(), std::string("epsilon zeta\nend"));
|
||||
}
|
||||
{
|
||||
TestHarness h;
|
||||
h.Buf().insert_text(0, 0, text);
|
||||
h.Buf().SetCursor(6, 0);
|
||||
ASSERT_TRUE(h.Exec(CommandId::DeleteWordNext, "", 2));
|
||||
ASSERT_EQ(h.Text(), std::string("alpha delta.epsilon zeta\nend"));
|
||||
ASSERT_EQ(h.EditorRef().KillRingHead(), std::string("beta, gamma\n\n "));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user