reimplement '/home/humza/Downloads/sml/shf/todo.md' motion so that it has the same behaviour as Vim. (If the cursor is not at a pair character, then check after the cursor to see if we find a pair-character there. If some location after the cursor has a pair-character, then move the cursor to it and find the pair of the character, if any.)

This commit is contained in:
2026-01-01 06:58:30 +00:00
parent a65b950b77
commit 44dbe1ffb0
5 changed files with 121 additions and 72 deletions

View File

@@ -209,14 +209,47 @@ struct
val toPrevChr = ToPrevChr.foldPrev
structure NextPairChr =
MakeIfCharFolderNext
(struct
type env = unit
fun isPairChr chr =
chr = #"(" orelse chr = #")" orelse
chr = #"[" orelse chr = #"]" orelse
chr = #"{" orelse chr = #"}" orelse
chr = #"<" orelse chr = #">"
fun loop (strPos, str, absIdx, stl) =
if strPos = String.size str then
case stl of
str :: stl => loop (0, str, absIdx, stl)
| [] => ~1
else
let
val chr = String.sub (str, strPos)
in
if isPairChr chr then
absIdx
else
loop (strPos + 1, str, absIdx + 1, stl)
end
fun fStart (strPos, str, _, absIdx, stl, _, _) =
loop (strPos, str, absIdx, stl)
end)
fun nextPairChr (lineGap, cursorIdx) =
NextPairChr.foldNext (lineGap, cursorIdx, ())
fun helpMatchPairNext
(strPos, str, absIdx, stl, origIdx, openChr, openNum, closeChr, closeNum) =
(strPos, str, absIdx, stl, openChr, openNum, closeChr, closeNum) =
if strPos = String.size str then
case stl of
hd :: tl =>
helpMatchPairNext
(0, hd, absIdx, tl, origIdx, openChr, openNum, closeChr, closeNum)
| [] => origIdx
(0, hd, absIdx, tl, openChr, openNum, closeChr, closeNum)
| [] => ~1
else
let
val chr = String.sub (str, strPos)
@@ -231,7 +264,6 @@ struct
, str
, absIdx + 1
, stl
, origIdx
, openChr
, openNum
, closeChr
@@ -240,7 +272,7 @@ struct
end
fun helpMatchPairPrev
(strPos, str, absIdx, stl, origIdx, openChr, openNum, closeChr, closeNum) =
(strPos, str, absIdx, stl, openChr, openNum, closeChr, closeNum) =
if strPos < 0 then
case stl of
hd :: tl =>
@@ -249,13 +281,12 @@ struct
, hd
, absIdx
, tl
, origIdx
, openChr
, openNum
, closeChr
, closeNum
)
| [] => origIdx
| [] => ~1
else
let
val chr = String.sub (str, strPos)
@@ -270,7 +301,6 @@ struct
, str
, absIdx - 1
, stl
, origIdx
, openChr
, openNum
, closeChr
@@ -286,7 +316,6 @@ struct
, shd
, cursorIdx + 1
, rightStrings
, cursorIdx
, #"("
, 1
, #")"
@@ -298,7 +327,6 @@ struct
, shd
, cursorIdx - 1
, leftStrings
, cursorIdx
, #"("
, 0
, #")"
@@ -310,7 +338,6 @@ struct
, shd
, cursorIdx + 1
, rightStrings
, cursorIdx
, #"["
, 1
, #"]"
@@ -322,7 +349,6 @@ struct
, shd
, cursorIdx - 1
, leftStrings
, cursorIdx
, #"["
, 0
, #"]"
@@ -334,7 +360,6 @@ struct
, shd
, cursorIdx + 1
, rightStrings
, cursorIdx
, #"{"
, 1
, #"}"
@@ -346,7 +371,6 @@ struct
, shd
, cursorIdx - 1
, leftStrings
, cursorIdx
, #"{"
, 0
, #"}"
@@ -358,7 +382,6 @@ struct
, shd
, cursorIdx + 1
, rightStrings
, cursorIdx
, #"<"
, 1
, #">"
@@ -370,13 +393,12 @@ struct
, shd
, cursorIdx - 1
, leftStrings
, cursorIdx
, #"<"
, 0
, #">"
, 1
)
| _ => cursorIdx
| _ => ~1
fun matchPair (lineGap: LineGap.t, cursorIdx) =
let

View File

@@ -398,46 +398,57 @@ struct
(* move LineGap and buffer to start of line *)
val buffer = LineGap.goToIdx (cursorIdx, buffer)
val cursorIdx = Cursor.matchPair (buffer, cursorIdx)
val cursorIdx = Cursor.nextPairChr (buffer, cursorIdx)
in
let
val buffer = LineGap.goToIdx (cursorIdx, buffer)
val visualScrollColumn =
TextScroll.getScrollColumn
(buffer, cursorIdx, windowWidth, prevScrollColumn)
if cursorIdx = ~1 then
NormalFinish.clearMode app
else
let
val buffer = LineGap.goToIdx (cursorIdx, buffer)
val cursorIdx = Cursor.matchPair (buffer, cursorIdx)
in
if cursorIdx = ~1 then
NormalFinish.clearMode app
else
let
val buffer = LineGap.goToIdx (cursorIdx, buffer)
val visualScrollColumn =
TextScroll.getScrollColumn
(buffer, cursorIdx, windowWidth, prevScrollColumn)
val cursorLine = LineGap.idxToLineNumber (cursorIdx, buffer)
val startLine =
TextScroll.getStartLine
(prevLineNumber, cursorLine, windowHeight, #lineLength buffer)
val cursorLine = LineGap.idxToLineNumber (cursorIdx, buffer)
val startLine =
TextScroll.getStartLine
(prevLineNumber, cursorLine, windowHeight, #lineLength buffer)
val buffer = LineGap.goToLine (startLine, buffer)
val buffer = LineGap.goToLine (startLine, buffer)
val drawMsg = NormalModeTextBuilder.build
( startLine
, cursorIdx
, buffer
, windowWidth
, windowHeight
, searchList
, visualScrollColumn
)
val drawMsg = Vector.concat drawMsg
val drawMsg = DrawMsg.DRAW_TEXT drawMsg
val drawMsg = [MailboxType.DRAW drawMsg]
in
NormalModeWith.bufferAndCursorIdx
( app
, buffer
, cursorIdx
, NORMAL_MODE ""
, startLine
, searchList
, drawMsg
, bufferModifyTime
, visualScrollColumn
)
end
val drawMsg = NormalModeTextBuilder.build
( startLine
, cursorIdx
, buffer
, windowWidth
, windowHeight
, searchList
, visualScrollColumn
)
val drawMsg = Vector.concat drawMsg
val drawMsg = DrawMsg.DRAW_TEXT drawMsg
val drawMsg = [MailboxType.DRAW drawMsg]
in
NormalModeWith.bufferAndCursorIdx
( app
, buffer
, cursorIdx
, NORMAL_MODE ""
, startLine
, searchList
, drawMsg
, bufferModifyTime
, visualScrollColumn
)
end
end
end
fun firstNonSpaceChr (app: app_type) =

View File

@@ -1,3 +1 @@
hello
world
again
he()o world

View File

@@ -1752,21 +1752,39 @@ struct
(* assert *)
Expect.isTrue (getChr app = #"<")
end)
(* testing that % on a non-pair character is a no-op *)
, test "does not move when cursor is on a non-pair-character" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello, world\n"
val app = AppWith.idx (app, 5)
val oldIdx = #cursorIdx app
, test
"does not move when cursor is on a non-pair-character, \
\and there is no pair-character where the cursor is at or after the cursor"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "he()o, world\n"
val app = AppWith.idx (app, 5)
val oldIdx = #cursorIdx app
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = oldIdx)
end)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = oldIdx)
end)
, test
"moves cursor when the cursor is not on a \
\pair-character, but there is a pair-character \
\after the cursor"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "he()o world\n"
val app = AppWith.idx (app, 0)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (cursorIdx = 3)
end)
]
(* movements which use multiple chars *)

View File

@@ -1,8 +1,8 @@
# To-do list
- Add tests for:
- Reimplement `%` motion and `d%` motion.
- They should both search for the next character in any pair, the same way in Vim
- Reimplement `d%` motion.
- It should both search for the next character in any pair, the same way in Vim
- Add tests for reimplemented movements and motions
- Reimplement `di<symbol>` and `da<symbol>`
- They should search for the next char in the specific pair, the same way in Vim