change implementation of 'word' so that we stop at newlines when we press 'w' motion, like in Vim and add tests to verify this behaviour (todo: fix regressions in deletion tests)
This commit is contained in:
@@ -12,14 +12,19 @@ struct
|
|||||||
val spaceToAlpha: Word8.word = 0w6
|
val spaceToAlpha: Word8.word = 0w6
|
||||||
val spaceToPunct: Word8.word = 0w7
|
val spaceToPunct: Word8.word = 0w7
|
||||||
|
|
||||||
val alphaToPunct: Word8.word = 0w8
|
val startNewline: Word8.word = 0w8
|
||||||
val punctToAlpha: Word8.word = 0w9
|
val newlineToNewline: Word8.word = 0w9
|
||||||
|
val chrToNewline: Word8.word = 0w10
|
||||||
|
|
||||||
|
val alphaToPunct: Word8.word = 0w11
|
||||||
|
val punctToAlpha: Word8.word = 0w12
|
||||||
|
|
||||||
fun makeStart i =
|
fun makeStart i =
|
||||||
let
|
let
|
||||||
val chr = Char.chr i
|
val chr = Char.chr i
|
||||||
in
|
in
|
||||||
if Char.isAlphaNum chr orelse chr = #"_" then startAlpha
|
if Char.isAlphaNum chr orelse chr = #"_" then startAlpha
|
||||||
|
else if chr = #"\n" then startNewline
|
||||||
else if Char.isSpace chr then startSpace
|
else if Char.isSpace chr then startSpace
|
||||||
else startPunct
|
else startPunct
|
||||||
end
|
end
|
||||||
@@ -29,6 +34,7 @@ struct
|
|||||||
val chr = Char.chr i
|
val chr = Char.chr i
|
||||||
in
|
in
|
||||||
if Char.isAlphaNum chr orelse chr = #"_" then startAlpha
|
if Char.isAlphaNum chr orelse chr = #"_" then startAlpha
|
||||||
|
else if chr = #"\n" then chrToNewline
|
||||||
else if Char.isSpace chr then alphaToSpace
|
else if Char.isSpace chr then alphaToSpace
|
||||||
else alphaToPunct
|
else alphaToPunct
|
||||||
end
|
end
|
||||||
@@ -38,6 +44,7 @@ struct
|
|||||||
val chr = Char.chr i
|
val chr = Char.chr i
|
||||||
in
|
in
|
||||||
if Char.isAlphaNum chr orelse chr = #"_" then spaceToAlpha
|
if Char.isAlphaNum chr orelse chr = #"_" then spaceToAlpha
|
||||||
|
else if chr = #"\n" then chrToNewline
|
||||||
else if Char.isSpace chr then startSpace
|
else if Char.isSpace chr then startSpace
|
||||||
else spaceToPunct
|
else spaceToPunct
|
||||||
end
|
end
|
||||||
@@ -47,10 +54,21 @@ struct
|
|||||||
val chr = Char.chr i
|
val chr = Char.chr i
|
||||||
in
|
in
|
||||||
if Char.isAlphaNum chr orelse chr = #"_" then punctToAlpha
|
if Char.isAlphaNum chr orelse chr = #"_" then punctToAlpha
|
||||||
|
else if chr = #"\n" then chrToNewline
|
||||||
else if Char.isSpace chr then punctToSpace
|
else if Char.isSpace chr then punctToSpace
|
||||||
else startPunct
|
else startPunct
|
||||||
end
|
end
|
||||||
|
|
||||||
|
fun makeStartNewline i =
|
||||||
|
let
|
||||||
|
val chr = Char.chr i
|
||||||
|
in
|
||||||
|
if Char.isAlphaNum chr orelse chr = #"_" then startAlpha
|
||||||
|
else if chr = #"\n" then newlineToNewline
|
||||||
|
else if Char.isSpace chr then startSpace
|
||||||
|
else startPunct
|
||||||
|
end
|
||||||
|
|
||||||
val startTable = Vector.tabulate (255, makeStart)
|
val startTable = Vector.tabulate (255, makeStart)
|
||||||
|
|
||||||
val startAlphaTable = Vector.tabulate (255, makeStartAlpha)
|
val startAlphaTable = Vector.tabulate (255, makeStartAlpha)
|
||||||
@@ -63,6 +81,8 @@ struct
|
|||||||
val spaceToAlphaTable = startAlphaTable
|
val spaceToAlphaTable = startAlphaTable
|
||||||
val spaceToPunctTable = startPunctTable
|
val spaceToPunctTable = startPunctTable
|
||||||
|
|
||||||
|
val newlineTable = Vector.tabulate (255, makeStartNewline)
|
||||||
|
|
||||||
val tables =
|
val tables =
|
||||||
#[ startTable
|
#[ startTable
|
||||||
|
|
||||||
@@ -75,6 +95,10 @@ struct
|
|||||||
|
|
||||||
, spaceToAlphaTable
|
, spaceToAlphaTable
|
||||||
, spaceToPunctTable
|
, spaceToPunctTable
|
||||||
|
|
||||||
|
, newlineTable
|
||||||
|
, newlineTable
|
||||||
|
, newlineTable
|
||||||
]
|
]
|
||||||
|
|
||||||
structure StartOfNextWord =
|
structure StartOfNextWord =
|
||||||
@@ -92,6 +116,7 @@ struct
|
|||||||
currentState = alphaToPunct orelse currentState = punctToAlpha
|
currentState = alphaToPunct orelse currentState = punctToAlpha
|
||||||
orelse currentState = spaceToAlpha
|
orelse currentState = spaceToAlpha
|
||||||
orelse currentState = spaceToPunct
|
orelse currentState = spaceToPunct
|
||||||
|
orelse currentState = newlineToNewline
|
||||||
|
|
||||||
fun finish x = x
|
fun finish x = x
|
||||||
end)
|
end)
|
||||||
@@ -130,6 +155,8 @@ struct
|
|||||||
fun isFinal currentState =
|
fun isFinal currentState =
|
||||||
currentState = alphaToSpace orelse currentState = punctToSpace
|
currentState = alphaToSpace orelse currentState = punctToSpace
|
||||||
orelse currentState = alphaToPunct orelse currentState = punctToAlpha
|
orelse currentState = alphaToPunct orelse currentState = punctToAlpha
|
||||||
|
orelse currentState = chrToNewline
|
||||||
|
orelse currentState = newlineToNewline
|
||||||
|
|
||||||
fun finish idx = idx + 1
|
fun finish idx = idx + 1
|
||||||
end)
|
end)
|
||||||
@@ -151,6 +178,7 @@ struct
|
|||||||
fun isFinalForEndOfCurrentWord currentState =
|
fun isFinalForEndOfCurrentWord currentState =
|
||||||
currentState = alphaToSpace orelse currentState = punctToSpace
|
currentState = alphaToSpace orelse currentState = punctToSpace
|
||||||
orelse currentState = alphaToPunct orelse currentState = punctToAlpha
|
orelse currentState = alphaToPunct orelse currentState = punctToAlpha
|
||||||
|
orelse currentState = chrToNewline
|
||||||
|
|
||||||
structure EndOfCurrentWordFolder =
|
structure EndOfCurrentWordFolder =
|
||||||
MakeCharFolderNext
|
MakeCharFolderNext
|
||||||
|
|||||||
@@ -624,26 +624,21 @@ struct
|
|||||||
in
|
in
|
||||||
Expect.isTrue (chr = #"w")
|
Expect.isTrue (chr = #"w")
|
||||||
end)
|
end)
|
||||||
, test "moves cursor past newline when next word is after newline" (fn _ =>
|
, test
|
||||||
(* This behaviour makes behaviour different from vi,
|
"moves cursor to first char-after-newline \
|
||||||
* where "w" when a newline is in between causes cursor
|
\when cursor is on last word of line \
|
||||||
* to go to newline and not next word.
|
\and there is another line after this one"
|
||||||
* I don't personally like this behaviour from vi
|
(fn _ =>
|
||||||
* since one can just press "j" to go to the newline instead
|
let
|
||||||
* and it is more intuitive for the cursor to go the next word
|
(* arrange *)
|
||||||
* as usual with "w". *)
|
val app = TestUtils.init "hello \n\n\n world\n"
|
||||||
let
|
|
||||||
(* arrange *)
|
|
||||||
val app = TestUtils.init "hello \n\n\n world\n"
|
|
||||||
|
|
||||||
(* act *)
|
(* act *)
|
||||||
val app = TestUtils.update (app, CHAR_EVENT #"w")
|
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"w")
|
||||||
|
in
|
||||||
(* assert *)
|
(* assert *)
|
||||||
val cursorChr = getChr app
|
Expect.isTrue (cursorIdx = 7)
|
||||||
in
|
end)
|
||||||
Expect.isTrue (cursorChr = #"w")
|
|
||||||
end)
|
|
||||||
, test "does not break on undescore when cursor is on alphanumeric char"
|
, test "does not break on undescore when cursor is on alphanumeric char"
|
||||||
(fn _ =>
|
(fn _ =>
|
||||||
let
|
let
|
||||||
@@ -949,10 +944,10 @@ struct
|
|||||||
in
|
in
|
||||||
Expect.isTrue (cursorChr = #")")
|
Expect.isTrue (cursorChr = #")")
|
||||||
end)
|
end)
|
||||||
, test "skips 'space' chars: '\\n', '\\t', ' '" (fn _ =>
|
, test "skips past tab" (fn _ =>
|
||||||
let
|
let
|
||||||
(* arrange *)
|
(* arrange *)
|
||||||
val app = TestUtils.init "0123 \t \n \t 789\n"
|
val app = TestUtils.init "0123 \t \t \t 789\n"
|
||||||
val app = AppWith.idx (app, 4)
|
val app = AppWith.idx (app, 4)
|
||||||
|
|
||||||
(* act *)
|
(* act *)
|
||||||
@@ -992,6 +987,23 @@ struct
|
|||||||
in
|
in
|
||||||
Expect.isTrue chrIsEnd
|
Expect.isTrue chrIsEnd
|
||||||
end)
|
end)
|
||||||
|
, test
|
||||||
|
"moves cursor to end of current word \
|
||||||
|
\when current word is last word in line"
|
||||||
|
(fn _ =>
|
||||||
|
let
|
||||||
|
(* arrange *)
|
||||||
|
val app = TestUtils.init "hello\n\n\nworld\n"
|
||||||
|
val app = AppWith.idx (app, 0)
|
||||||
|
|
||||||
|
(* act *)
|
||||||
|
val app = TestUtils.update (app, CHAR_EVENT #"e")
|
||||||
|
|
||||||
|
(* assert *)
|
||||||
|
val isAtEndOfHello = getChr app = #"o"
|
||||||
|
in
|
||||||
|
Expect.isTrue isAtEndOfHello
|
||||||
|
end)
|
||||||
]
|
]
|
||||||
|
|
||||||
val EMove = describe "move motion 'E'"
|
val EMove = describe "move motion 'E'"
|
||||||
@@ -1050,10 +1062,10 @@ struct
|
|||||||
in
|
in
|
||||||
Expect.isTrue (cursorChr = #"o")
|
Expect.isTrue (cursorChr = #"o")
|
||||||
end)
|
end)
|
||||||
, test "skips 'space' chars: '\\n', '\\t', ' '" (fn _ =>
|
, test "skips past tab: '\\t'" (fn _ =>
|
||||||
let
|
let
|
||||||
(* arrange *)
|
(* arrange *)
|
||||||
val app = TestUtils.init "0123 \t \n \t 789\n"
|
val app = TestUtils.init "0123 \t \t \t 789\n"
|
||||||
val app = AppWith.idx (app, 4)
|
val app = AppWith.idx (app, 4)
|
||||||
|
|
||||||
(* act *)
|
(* act *)
|
||||||
@@ -1175,6 +1187,19 @@ struct
|
|||||||
(* assert *)
|
(* assert *)
|
||||||
Expect.isTrue (getChr app = #"!")
|
Expect.isTrue (getChr app = #"!")
|
||||||
end)
|
end)
|
||||||
|
, test "stops when char preceding word is newline" (fn _ =>
|
||||||
|
let
|
||||||
|
(* arrange *)
|
||||||
|
val originalString = "hello\n\n\nworld\n"
|
||||||
|
val app = TestUtils.init originalString
|
||||||
|
val app = AppWith.idx (app, String.size originalString - 2)
|
||||||
|
|
||||||
|
(* act *)
|
||||||
|
val app = TestUtils.update (app, CHAR_EVENT #"b")
|
||||||
|
in
|
||||||
|
(* assert *)
|
||||||
|
Expect.isTrue (getChr app = #"w")
|
||||||
|
end)
|
||||||
]
|
]
|
||||||
|
|
||||||
val BMove = describe "move motion 'B'"
|
val BMove = describe "move motion 'B'"
|
||||||
|
|||||||
Reference in New Issue
Block a user