From 2ee963a3d875f43b572db3b124523d6b85968ea8 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Sat, 31 Jan 2026 22:20:52 +0000 Subject: [PATCH] done implementing tests for yank. Also simplify 'NormalDelete.deleteLineDown' and 'NormalYank.yankLineDown' functions by removing an if-branch which can never trigger. (The code path can only be executed in the event that 'endLineIdx' is on a newline, and there is an if-expression in that branch checking whether 'endLineIdx' is on a newline, which is redundant.) --- fcore/normal-mode/make-normal-delete.sml | 19 ++--- fcore/normal-mode/normal-yank.sml | 8 +- test/normal-yank-tests.sml | 100 ++++++++++++++++++++++- todo.md | 3 +- 4 files changed, 110 insertions(+), 20 deletions(-) diff --git a/fcore/normal-mode/make-normal-delete.sml b/fcore/normal-mode/make-normal-delete.sml index 0508045..81ef747 100644 --- a/fcore/normal-mode/make-normal-delete.sml +++ b/fcore/normal-mode/make-normal-delete.sml @@ -549,29 +549,26 @@ struct let val buffer = LineGap.goToIdx (endLineIdx, buffer) - (* right now, endLineIdx may be on a newline. - * If it is, we want to delete that newline too, - * and in that case, we increment by 1 to do so. + (* endLineIdx is on a newline because it was retrieved + * by calling the `LineGap.lineNumberToIdx` function, + * which always returns the idx of a line break. + * Since that is the case, we want to delete that newline too, + * and we increment by 1 to do so. * However, we don't want to delete the last newline in the file * so we don't increment in that case. * Edge case: if the startIdx also begins after a newline * then it is okay for us to delete the newline at the end of the file * because there will already be a newline at the end of the file * after the deletion. *) - val endsOnNewline = Cursor.isCursorAtStartOfLine (buffer, endLineIdx) - val buffer = LineGap.goToIdx (startIdx, buffer) val startsAfterNewline = startIdx > 0 andalso Cursor.isPrevChrStartOfLine (buffer, startIdx) val endLineIdx = - if endsOnNewline then - if endLineIdx = #textLength buffer - 1 then - if startsAfterNewline then endLineIdx + 1 else endLineIdx - else - endLineIdx + 1 + if endLineIdx = #textLength buffer - 1 then + if startsAfterNewline then endLineIdx + 1 else endLineIdx else - endLineIdx + endLineIdx + 1 val length = endLineIdx - startIdx diff --git a/fcore/normal-mode/normal-yank.sml b/fcore/normal-mode/normal-yank.sml index 3a378b2..ec96ad1 100644 --- a/fcore/normal-mode/normal-yank.sml +++ b/fcore/normal-mode/normal-yank.sml @@ -130,13 +130,7 @@ struct NormalFinish.clearMode app else let - val buffer = LineGap.goToIdx (endLineIdx, buffer) - val endLineIdx = - if Cursor.isCursorAtStartOfLine (buffer, endLineIdx) then - endLineIdx + 1 - else - endLineIdx - + val endLineIdx = endLineIdx + 1 val length = endLineIdx - startIdx (* perform the actual yank *) diff --git a/test/normal-yank-tests.sml b/test/normal-yank-tests.sml index 9fba8a3..9573b36 100644 --- a/test/normal-yank-tests.sml +++ b/test/normal-yank-tests.sml @@ -428,7 +428,105 @@ struct in TestUtils.expectYank (app, expectedString) end) - ] + , test + "yanks first two lines when there are three lines \ + \and cursor is on first line" + (fn _ => + let + (* arrange *) + val originalIdx = 0 + val originalString = "hello\nworld\nbye world\n" + + val app = TestUtils.init originalString + val app = AppWith.idx (app, originalIdx) + + (* act *) + val app = TestUtils.updateMany (app, "yj") + + (* assert *) + val expectedString = "hello\nworld\n" + in + TestUtils.expectYank (app, expectedString) + end) + , test + "yanks last two lines when there are three lines \ + \and cursor is on second line" + (fn _ => + let + (* arrange *) + val originalIdx = 6 + val originalString = "hello\nworld\nbye world\n" + + val app = TestUtils.init originalString + val app = AppWith.idx (app, originalIdx) + + (* act *) + val app = TestUtils.updateMany (app, "yj") + + (* assert *) + val expectedString = "world\nbye world\n" + in + TestUtils.expectYank (app, expectedString) + end) + , test + "yanks entire file when cursor is on first line \ + \and a count is given which is larger \ + \than the total number of lines in the file" + (fn _ => + let + (* arrange *) + val originalString = "hello\nworld\n" + val originalIdx = 0 + + val app = TestUtils.init originalString + val app = AppWith.idx (app, originalIdx) + + (* act *) + val app = TestUtils.updateMany (app, "33yj") + + (* assert *) + val expectedString = originalString + in + TestUtils.expectYank (app, expectedString) + end) + , test + "yanks entire file when a count greater than the total number of lines \ + \is given, while the file does not end with a newline" + (fn _ => + let + (* arrange *) + val originalString = "hello\nworld" + val originalIdx = 0 + + val app = TestUtils.init originalString + val app = AppWith.idx (app, originalIdx) + + (* act *) + val app = TestUtils.updateMany (app, "33yj") + + (* assert *) + val expectedString = originalString + in + TestUtils.expectYank (app, expectedString) + end) + , test "yanks two lines when cursor is on a newline" (fn _ => + let + (* arrange *) + val originalString = "\nhello\nworld\ntrello\nbrillo\n" + val originalIdx = 0 + + val app = TestUtils.init originalString + val app = AppWith.idx (app, originalIdx) + + (* act *) + val app = TestUtils.updateMany (app, "yj") + + (* assert *) + val expectedString = "\nhello\n" + in + TestUtils.expectYank (app, expectedString) + end) + ] val tests = [yhYank, ylYank, ykYank, yjYank] end diff --git a/todo.md b/todo.md index 074d990..58e4bc7 100644 --- a/todo.md +++ b/todo.md @@ -1,4 +1,5 @@ # To-do list -- Add tests for 'yj' motion +- Add tests for other yank motoins + - Tests should be based on existing tests for delete-motions, and in the same order. - Bind gamepad functions from GLFW and/or RGFW - Add tests for NormalYankDelete functions, to make sure that they are yanking the expected string.