diff --git a/fcore/normal-mode/make-normal-delete.sml b/fcore/normal-mode/make-normal-delete.sml index 37ec15f..c3e47e1 100644 --- a/fcore/normal-mode/make-normal-delete.sml +++ b/fcore/normal-mode/make-normal-delete.sml @@ -648,7 +648,7 @@ struct fun deleteToFirstNonSpaceChr (app: app_type, time) = let - val {buffer, cursorIdx, windowWidth, windowHeight, startLine, ...} = app + val {buffer, cursorIdx, ...} = app (* move LineGap and buffer to start of line *) val buffer = LineGap.goToIdx (cursorIdx, buffer) @@ -712,6 +712,31 @@ struct , time ) + fun deleteToNextChr (app: app_type, count, chr, time) = + let + val {buffer, cursorIdx, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = + Cursor.toNextChrNew (buffer, cursorIdx, {findChr = chr, count = count}) + in + if newCursorIdx = ~1 then + NormalFinish.clearMode app + else + let + val length = newCursorIdx - cursorIdx + 1 + val buffer = LineGap.goToIdx (newCursorIdx, buffer) + val initialMsg = Fn.initMsgs (cursorIdx, length, buffer) + val buffer = LineGap.delete (cursorIdx, length, buffer) + + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val cursorIdx = + if Cursor.isOnNewlineAfterChr (buffer, cursorIdx) then cursorIdx - 1 + else cursorIdx + in + finishAfterDeletingBuffer (app, cursorIdx, buffer, time, initialMsg) + end + end + fun deleteToStart (app: app_type, time) : AppType.app_type = let val {cursorIdx, buffer, windowWidth, windowHeight, dfa, ...} = app diff --git a/fcore/normal-mode/normal-mode.sml b/fcore/normal-mode/normal-mode.sml index e0f98b9..59f4800 100644 --- a/fcore/normal-mode/normal-mode.sml +++ b/fcore/normal-mode/normal-mode.sml @@ -304,9 +304,7 @@ struct | #"T" => NormalDelete.deleteToChr (app, 1, Cursor.tillPrevChr, op-, chrCmd, time) - | #"f" => - NormalDelete.deleteToChr - (app, count, Cursor.toNextChr, op+, chrCmd, time) + | #"f" => NormalDelete.deleteToNextChr (app, count, chrCmd, time) | #"F" => NormalDelete.deleteToChr (app, count, Cursor.toPrevChr, op-, chrCmd, time) @@ -560,18 +558,13 @@ struct * which can be made terminal by adding "w" or "e" at the end. * *) case String.sub (str, strPos) of - #"t" => - (* to just before char, forward - * tillNextChr with count of 1 has same effect - * as tillNextChr with any count above 1 - * so just hardcode 1 *) - NormalMove.tillNextChr (app, count, chrCmd) + #"t" => NormalMove.tillNextChr (app, count, chrCmd) | #"T" => (* to just before chr, backward *) parseMoveToChr (1, app, Cursor.tillPrevChr, chrCmd) | #"y" => ParseYank.parseYank (strPos, str, count, app, chrCmd, time) | #"d" => ParseDelete.parseDelete (strPos, str, count, app, chrCmd, time) - | #"f" => (* to chr, forward *) NormalMove.toNextChr (app, count, chrCmd) + | #"f" => NormalMove.toNextChr (app, count, chrCmd) | #"F" => (* to chr, backward *) parseMoveToChr (count, app, Cursor.toPrevChr, chrCmd) diff --git a/test/normal-delete.sml b/test/normal-delete.sml index cd68cd8..98ecc7f 100644 --- a/test/normal-delete.sml +++ b/test/normal-delete.sml @@ -3576,6 +3576,28 @@ struct (actualString = expectedString andalso cursorIdx = expectedCursorIdx) end) + , test + "moves cursor back by one, when deletion range is \ + \from a newline that follows a non-newline char" + (fn _ => + let + (* arrange *) + val originalString = "hey hello\n" + val app = TestUtils.init originalString + val app = AppWith.idx (app, 3) + + (* act *) + val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "dfo") + + (* assert *) + val actualString = LineGap.toString buffer + val expectedString = "hey\n" + val expectedCursorIdx = 2 + in + Expect.isTrue + (actualString = expectedString + andalso cursorIdx = expectedCursorIdx) + end) ] val dtDelete = describe "delete motion 'dt'"