From 42bd641be4e8a30e557a36c3b513f14cece946af Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Sat, 6 Sep 2025 04:39:53 +0100 Subject: [PATCH] add a function to remove line breaks: the equivalent of Vim's 'J' command. --- fcore/normal-mode/make-normal-delete.sml | 41 ++++++++++++++++++++++++ fcore/normal-mode/normal-mode.sml | 1 + temp.txt | 3 +- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/fcore/normal-mode/make-normal-delete.sml b/fcore/normal-mode/make-normal-delete.sml index 0b47df6..e97bbc6 100644 --- a/fcore/normal-mode/make-normal-delete.sml +++ b/fcore/normal-mode/make-normal-delete.sml @@ -91,6 +91,47 @@ struct fun removeChr (app: app_type, count, time) = helpRemoveChr (app, #buffer app, #cursorIdx app, count, time) + (* Note: The below implementation of removing line breaks with the 'J' + * command slightly differs from the implementation in Vim. + * In Vim, the J, 1J, and 2J commands all have the same effect. + * 3J, 4J, 5J, etc. all have different effects because of the different counts + * though. + * Our implementation has a different effect for each count. + * 1J delettes 1 line break, 2J deletes 2, and so on. *) + fun helpRemoveLineBreaks (app, buffer, cursorIdx, count, time) = + if count = 0 then + finishAfterDeletingBuffer (app, cursorIdx, buffer, time, []) + else + let + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = Cursor.toNextChr (buffer, cursorIdx, #"\n") + + val buffer = LineGap.delete (newCursorIdx, 1, buffer) + val buffer = LineGap.insert (newCursorIdx, " ", buffer) + val newCount = if newCursorIdx = cursorIdx then 0 else count - 1 + in + helpRemoveLineBreaks (app, buffer, newCursorIdx, newCount, time) + end + + (* todo: first loop should be here, like do-while *) + fun removeLineBreaks (app: app_type, count, time) = + let + val {buffer, cursorIdx, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = Cursor.toNextChr (buffer, cursorIdx, #"\n") + in + if cursorIdx = newCursorIdx then + (* no change *) + NormalFinish.clearMode app + else + let + val buffer = LineGap.delete (newCursorIdx, 1, buffer) + val buffer = LineGap.insert (newCursorIdx, " ", buffer) + in + helpRemoveLineBreaks (app, buffer, newCursorIdx, count - 1, time) + end + end + fun helpDelete (app: app_type, buffer, cursorIdx, otherIdx, count, fMove, time) = (* As a small optimisation to reduce allocations, diff --git a/fcore/normal-mode/normal-mode.sml b/fcore/normal-mode/normal-mode.sml index c17daaf..5703b80 100644 --- a/fcore/normal-mode/normal-mode.sml +++ b/fcore/normal-mode/normal-mode.sml @@ -86,6 +86,7 @@ struct else NormalMove.moveToLine (app, count - 1) | #"%" => NormalMove.moveToMatchingPair app | #"x" => NormalDelete.removeChr (app, count, time) + | #"J" => NormalDelete.removeLineBreaks (app, count, time) | #"/" => switchToNormalSearchMode app (* multi-char commands which can be appended *) | #"t" => appendChr (app, chr, str) diff --git a/temp.txt b/temp.txt index d6ea8a2..82ce789 100644 --- a/temp.txt +++ b/temp.txt @@ -1,5 +1,4 @@ -signature TEXT_BUILDER = -aaron baron carrot durian +signature TEXT_BUILDER = aaron baron carrot durian (* Prerequisite: LineGap is moved to requested line first. *) val build: int * int * LineGap.t * int * int -> MailboxType.t list