reimplement 'G' motion so that it follows new rule (cursor goes to second-last chr if last chr is a newline preceded by a non-newline, but goes to last chr otherwise)

This commit is contained in:
2025-09-23 11:57:19 +01:00
parent 5d20b81bcc
commit fcc8c8085a
2 changed files with 59 additions and 24 deletions

View File

@@ -68,6 +68,13 @@ struct
val bufferIdx = Int.max (0, textLength - 1)
val bufferLine = bufferLine - 1
val buffer = LineGap.goToIdx (bufferIdx, buffer)
val bufferIdx =
if Cursor.isOnNewlineAfterChr (buffer, bufferIdx) then
Int.max (0, bufferIdx - 1)
else
bufferIdx
val buffer = LineGap.goToIdx (bufferIdx, buffer)
val visualScrollColumn =
TextScroll.getScrollColumn
@@ -248,10 +255,8 @@ struct
val lineIdx = LineGap.lineNumberToIdx (newCursorLineNumber, buffer)
val lineIdx =
if Cursor.isPrevChrStartOfLine (buffer, lineIdx) then
lineIdx
else
lineIdx - 1
if Cursor.isPrevChrStartOfLine (buffer, lineIdx) then lineIdx
else lineIdx - 1
val buffer = LineGap.goToIdx (lineIdx, buffer)
val lineIdx = Cursor.vi0 (buffer, lineIdx)
@@ -274,10 +279,8 @@ struct
val buffer = LineGap.goToIdx (lineIdx, buffer)
val lineIdx =
if Cursor.isPrevChrStartOfLine (buffer, lineIdx) then
lineIdx
else
lineIdx + 1
if Cursor.isPrevChrStartOfLine (buffer, lineIdx) then lineIdx
else lineIdx + 1
val lineIdx =
if lineIdx >= #textLength buffer - 1 then

View File

@@ -1328,23 +1328,55 @@ struct
]
val GMove = describe "move motion 'G'"
[test "moves cursor to last char in buffer" (fn _ =>
(* Note: We assume unix-style line endings:
* End of file always has \n at the end.
* We don't want cursor to ever reach this last \n
* so we say last char is the char before \n
* *)
let
(* arrange *)
val str = "01234\n56789\n"
val app = TestUtils.init str
[ test
"moves cursor to second last char in buffer, \
\if last char is a newline preced by a non-newline"
(fn _ =>
(* Note: We assume unix-style line endings:
* End of file always has \n at the end. *)
let
(* arrange *)
val str = "01234\n56789\n"
val app = TestUtils.init str
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"G")
in
(* assert *)
Expect.isTrue (#cursorIdx app = String.size str - 1)
end)]
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"G")
in
(* assert *)
Expect.isTrue (#cursorIdx app = String.size str - 2)
end)
, test
"moves cursor to last char in buffer, \
\if last char is a newline and second-last char is also a newline"
(fn _ =>
let
(* arrange *)
val str = "01234\n5678\n\n"
val app = TestUtils.init str
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"G")
in
(* assert *)
Expect.isTrue (#cursorIdx app = String.size str - 1)
end)
, test
"moves cursor to last char in buffer, \
\if last char is not a newline and second-last char \
\is also not a newline"
(fn _ =>
let
(* arrange *)
val str = "01234\n5678\n\n"
val app = TestUtils.init str
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"G")
in
(* assert *)
Expect.isTrue (#cursorIdx app = String.size str - 1)
end)
]
val percentMove = describe "move motion '%'"
[ test "moves to next ) when cursor is on (" (fn _ =>