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:
@@ -209,14 +209,47 @@ struct
|
|||||||
|
|
||||||
val toPrevChr = ToPrevChr.foldPrev
|
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
|
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
|
if strPos = String.size str then
|
||||||
case stl of
|
case stl of
|
||||||
hd :: tl =>
|
hd :: tl =>
|
||||||
helpMatchPairNext
|
helpMatchPairNext
|
||||||
(0, hd, absIdx, tl, origIdx, openChr, openNum, closeChr, closeNum)
|
(0, hd, absIdx, tl, openChr, openNum, closeChr, closeNum)
|
||||||
| [] => origIdx
|
| [] => ~1
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
val chr = String.sub (str, strPos)
|
val chr = String.sub (str, strPos)
|
||||||
@@ -231,7 +264,6 @@ struct
|
|||||||
, str
|
, str
|
||||||
, absIdx + 1
|
, absIdx + 1
|
||||||
, stl
|
, stl
|
||||||
, origIdx
|
|
||||||
, openChr
|
, openChr
|
||||||
, openNum
|
, openNum
|
||||||
, closeChr
|
, closeChr
|
||||||
@@ -240,7 +272,7 @@ struct
|
|||||||
end
|
end
|
||||||
|
|
||||||
fun helpMatchPairPrev
|
fun helpMatchPairPrev
|
||||||
(strPos, str, absIdx, stl, origIdx, openChr, openNum, closeChr, closeNum) =
|
(strPos, str, absIdx, stl, openChr, openNum, closeChr, closeNum) =
|
||||||
if strPos < 0 then
|
if strPos < 0 then
|
||||||
case stl of
|
case stl of
|
||||||
hd :: tl =>
|
hd :: tl =>
|
||||||
@@ -249,13 +281,12 @@ struct
|
|||||||
, hd
|
, hd
|
||||||
, absIdx
|
, absIdx
|
||||||
, tl
|
, tl
|
||||||
, origIdx
|
|
||||||
, openChr
|
, openChr
|
||||||
, openNum
|
, openNum
|
||||||
, closeChr
|
, closeChr
|
||||||
, closeNum
|
, closeNum
|
||||||
)
|
)
|
||||||
| [] => origIdx
|
| [] => ~1
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
val chr = String.sub (str, strPos)
|
val chr = String.sub (str, strPos)
|
||||||
@@ -270,7 +301,6 @@ struct
|
|||||||
, str
|
, str
|
||||||
, absIdx - 1
|
, absIdx - 1
|
||||||
, stl
|
, stl
|
||||||
, origIdx
|
|
||||||
, openChr
|
, openChr
|
||||||
, openNum
|
, openNum
|
||||||
, closeChr
|
, closeChr
|
||||||
@@ -286,7 +316,6 @@ struct
|
|||||||
, shd
|
, shd
|
||||||
, cursorIdx + 1
|
, cursorIdx + 1
|
||||||
, rightStrings
|
, rightStrings
|
||||||
, cursorIdx
|
|
||||||
, #"("
|
, #"("
|
||||||
, 1
|
, 1
|
||||||
, #")"
|
, #")"
|
||||||
@@ -298,7 +327,6 @@ struct
|
|||||||
, shd
|
, shd
|
||||||
, cursorIdx - 1
|
, cursorIdx - 1
|
||||||
, leftStrings
|
, leftStrings
|
||||||
, cursorIdx
|
|
||||||
, #"("
|
, #"("
|
||||||
, 0
|
, 0
|
||||||
, #")"
|
, #")"
|
||||||
@@ -310,7 +338,6 @@ struct
|
|||||||
, shd
|
, shd
|
||||||
, cursorIdx + 1
|
, cursorIdx + 1
|
||||||
, rightStrings
|
, rightStrings
|
||||||
, cursorIdx
|
|
||||||
, #"["
|
, #"["
|
||||||
, 1
|
, 1
|
||||||
, #"]"
|
, #"]"
|
||||||
@@ -322,7 +349,6 @@ struct
|
|||||||
, shd
|
, shd
|
||||||
, cursorIdx - 1
|
, cursorIdx - 1
|
||||||
, leftStrings
|
, leftStrings
|
||||||
, cursorIdx
|
|
||||||
, #"["
|
, #"["
|
||||||
, 0
|
, 0
|
||||||
, #"]"
|
, #"]"
|
||||||
@@ -334,7 +360,6 @@ struct
|
|||||||
, shd
|
, shd
|
||||||
, cursorIdx + 1
|
, cursorIdx + 1
|
||||||
, rightStrings
|
, rightStrings
|
||||||
, cursorIdx
|
|
||||||
, #"{"
|
, #"{"
|
||||||
, 1
|
, 1
|
||||||
, #"}"
|
, #"}"
|
||||||
@@ -346,7 +371,6 @@ struct
|
|||||||
, shd
|
, shd
|
||||||
, cursorIdx - 1
|
, cursorIdx - 1
|
||||||
, leftStrings
|
, leftStrings
|
||||||
, cursorIdx
|
|
||||||
, #"{"
|
, #"{"
|
||||||
, 0
|
, 0
|
||||||
, #"}"
|
, #"}"
|
||||||
@@ -358,7 +382,6 @@ struct
|
|||||||
, shd
|
, shd
|
||||||
, cursorIdx + 1
|
, cursorIdx + 1
|
||||||
, rightStrings
|
, rightStrings
|
||||||
, cursorIdx
|
|
||||||
, #"<"
|
, #"<"
|
||||||
, 1
|
, 1
|
||||||
, #">"
|
, #">"
|
||||||
@@ -370,13 +393,12 @@ struct
|
|||||||
, shd
|
, shd
|
||||||
, cursorIdx - 1
|
, cursorIdx - 1
|
||||||
, leftStrings
|
, leftStrings
|
||||||
, cursorIdx
|
|
||||||
, #"<"
|
, #"<"
|
||||||
, 0
|
, 0
|
||||||
, #">"
|
, #">"
|
||||||
, 1
|
, 1
|
||||||
)
|
)
|
||||||
| _ => cursorIdx
|
| _ => ~1
|
||||||
|
|
||||||
fun matchPair (lineGap: LineGap.t, cursorIdx) =
|
fun matchPair (lineGap: LineGap.t, cursorIdx) =
|
||||||
let
|
let
|
||||||
|
|||||||
@@ -398,46 +398,57 @@ struct
|
|||||||
|
|
||||||
(* move LineGap and buffer to start of line *)
|
(* move LineGap and buffer to start of line *)
|
||||||
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
||||||
val cursorIdx = Cursor.matchPair (buffer, cursorIdx)
|
val cursorIdx = Cursor.nextPairChr (buffer, cursorIdx)
|
||||||
in
|
in
|
||||||
let
|
if cursorIdx = ~1 then
|
||||||
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
NormalFinish.clearMode app
|
||||||
val visualScrollColumn =
|
else
|
||||||
TextScroll.getScrollColumn
|
let
|
||||||
(buffer, cursorIdx, windowWidth, prevScrollColumn)
|
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 cursorLine = LineGap.idxToLineNumber (cursorIdx, buffer)
|
||||||
val startLine =
|
val startLine =
|
||||||
TextScroll.getStartLine
|
TextScroll.getStartLine
|
||||||
(prevLineNumber, cursorLine, windowHeight, #lineLength buffer)
|
(prevLineNumber, cursorLine, windowHeight, #lineLength buffer)
|
||||||
|
|
||||||
val buffer = LineGap.goToLine (startLine, buffer)
|
val buffer = LineGap.goToLine (startLine, buffer)
|
||||||
|
|
||||||
val drawMsg = NormalModeTextBuilder.build
|
val drawMsg = NormalModeTextBuilder.build
|
||||||
( startLine
|
( startLine
|
||||||
, cursorIdx
|
, cursorIdx
|
||||||
, buffer
|
, buffer
|
||||||
, windowWidth
|
, windowWidth
|
||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, visualScrollColumn
|
, visualScrollColumn
|
||||||
)
|
)
|
||||||
val drawMsg = Vector.concat drawMsg
|
val drawMsg = Vector.concat drawMsg
|
||||||
val drawMsg = DrawMsg.DRAW_TEXT drawMsg
|
val drawMsg = DrawMsg.DRAW_TEXT drawMsg
|
||||||
val drawMsg = [MailboxType.DRAW drawMsg]
|
val drawMsg = [MailboxType.DRAW drawMsg]
|
||||||
in
|
in
|
||||||
NormalModeWith.bufferAndCursorIdx
|
NormalModeWith.bufferAndCursorIdx
|
||||||
( app
|
( app
|
||||||
, buffer
|
, buffer
|
||||||
, cursorIdx
|
, cursorIdx
|
||||||
, NORMAL_MODE ""
|
, NORMAL_MODE ""
|
||||||
, startLine
|
, startLine
|
||||||
, searchList
|
, searchList
|
||||||
, drawMsg
|
, drawMsg
|
||||||
, bufferModifyTime
|
, bufferModifyTime
|
||||||
, visualScrollColumn
|
, visualScrollColumn
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
fun firstNonSpaceChr (app: app_type) =
|
fun firstNonSpaceChr (app: app_type) =
|
||||||
|
|||||||
@@ -1752,21 +1752,39 @@ struct
|
|||||||
(* assert *)
|
(* assert *)
|
||||||
Expect.isTrue (getChr app = #"<")
|
Expect.isTrue (getChr app = #"<")
|
||||||
end)
|
end)
|
||||||
(* testing that % on a non-pair character is a no-op *)
|
, test
|
||||||
, test "does not move when cursor is on a non-pair-character" (fn _ =>
|
"does not move when cursor is on a non-pair-character, \
|
||||||
let
|
\and there is no pair-character where the cursor is at or after the cursor"
|
||||||
(* arrange *)
|
(fn _ =>
|
||||||
val app = TestUtils.init "hello, world\n"
|
let
|
||||||
val app = AppWith.idx (app, 5)
|
(* arrange *)
|
||||||
val oldIdx = #cursorIdx app
|
val app = TestUtils.init "he()o, world\n"
|
||||||
|
val app = AppWith.idx (app, 5)
|
||||||
|
val oldIdx = #cursorIdx app
|
||||||
|
|
||||||
(* act *)
|
(* act *)
|
||||||
val app = TestUtils.update (app, CHAR_EVENT #"%")
|
val app = TestUtils.update (app, CHAR_EVENT #"%")
|
||||||
val newIdx = #cursorIdx app
|
val newIdx = #cursorIdx app
|
||||||
in
|
in
|
||||||
(* assert *)
|
(* assert *)
|
||||||
Expect.isTrue (newIdx = oldIdx)
|
Expect.isTrue (newIdx = oldIdx)
|
||||||
end)
|
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 *)
|
(* movements which use multiple chars *)
|
||||||
|
|||||||
4
todo.md
4
todo.md
@@ -1,8 +1,8 @@
|
|||||||
# To-do list
|
# To-do list
|
||||||
|
|
||||||
- Add tests for:
|
- Add tests for:
|
||||||
- Reimplement `%` motion and `d%` motion.
|
- Reimplement `d%` motion.
|
||||||
- They should both search for the next character in any pair, the same way in Vim
|
- It should both search for the next character in any pair, the same way in Vim
|
||||||
- Add tests for reimplemented movements and motions
|
- Add tests for reimplemented movements and motions
|
||||||
- Reimplement `di<symbol>` and `da<symbol>`
|
- Reimplement `di<symbol>` and `da<symbol>`
|
||||||
- They should search for the next char in the specific pair, the same way in Vim
|
- They should search for the next char in the specific pair, the same way in Vim
|
||||||
|
|||||||
Reference in New Issue
Block a user