From 8941ce9f89ef7416d76ba73c38f4b51ce87ce602 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Wed, 8 Oct 2025 08:10:51 +0100 Subject: [PATCH] reimplement functionality to search forwards using 'n' command --- fcore/normal-mode/normal-move.sml | 2 +- fcore/persistent-vector.sml | 84 ++++++++++++- temp.txt | 188 +++++++++++++++++++++++++++++- 3 files changed, 267 insertions(+), 7 deletions(-) diff --git a/fcore/normal-mode/normal-move.sml b/fcore/normal-mode/normal-move.sml index 895824c..48385fd 100644 --- a/fcore/normal-mode/normal-move.sml +++ b/fcore/normal-mode/normal-move.sml @@ -494,7 +494,7 @@ struct , visualScrollColumn , ... } = app - val newCursorIdx = SearchList.nextMatch (cursorIdx, searchList, count) + val newCursorIdx = PersistentVector.nextMatch (cursorIdx, searchList, count) in if newCursorIdx = ~1 then NormalFinish.clearMode app diff --git a/fcore/persistent-vector.sml b/fcore/persistent-vector.sml index f1c0e1d..a771ef6 100644 --- a/fcore/persistent-vector.sml +++ b/fcore/persistent-vector.sml @@ -96,12 +96,86 @@ struct end fun append (start, finish, tree) = - case helpAppend (start, finish, tree) of - UPDATE t => t - | APPEND newNode => + case helpAppend (start, finish, tree) of + UPDATE t => t + | APPEND newNode => + let + val maxSize = getFinishIdx tree + in + BRANCH (#[tree, newNode], #[maxSize, finish]) + end + + fun getStart tree = + case tree of + LEAF (values, _) => Vector.sub (values, 0) + | BRANCH (nodes, _) => getStart (Vector.sub (nodes, 0)) + + fun helpNextMatch (cusorIdx, tree) = + case tree of + LEAF (values, sizes) => + let + val idx = BinSearch.equalOrMore (cusorIdx, sizes) + in + if idx = ~1 then {start = ~1, finish = ~1} + else Vector.sub (values, idx) + end + | BRANCH (nodes, sizes) => + let + val idx = BinSearch.equalOrMore (cusorIdx, sizes) + in + if idx = ~1 then {start = ~1, finish = ~1} + else helpNextMatch (cusorIdx, Vector.sub (nodes, idx)) + end + + fun startNextMatch (cusorIdx, tree) = + case tree of + LEAF (values, sizes) => + if Vector.length sizes = 0 then + {start = ~1, finish = ~1} + else let - val maxSize = getFinishIdx tree + val idx = BinSearch.equalOrMore (cusorIdx, sizes) + val idx = if idx = ~1 then 0 else idx in - BRANCH (#[tree, newNode], #[maxSize, finish]) + Vector.sub (values, idx) end + | BRANCH (nodes, sizes) => + let + val idx = BinSearch.equalOrMore (cusorIdx, sizes) + in + if idx = ~1 then {start = ~1, finish = ~1} + else helpNextMatch (cusorIdx, Vector.sub (nodes, idx)) + end + + fun loopNextMatch (prevStart, prevFinish, tree, count) = + if count = 0 then + prevStart + else + let + val {start, finish} = startNextMatch (prevFinish + 1, tree) + in + if start = ~1 then + let val {start, finish} = getStart tree + in loopNextMatch (start, finish, tree, count - 1) + end + else + loopNextMatch (start, finish, tree, count - 1) + end + + fun nextMatch (cusorIdx, tree, count) = + if isEmpty tree then + ~1 + else + let + val {start, finish} = startNextMatch (cusorIdx, tree) + in + if start = ~1 then + let val {start, finish} = getStart tree + in loopNextMatch (start, finish, tree, count - 1) + end + else if cusorIdx >= start andalso cusorIdx <= finish then + loopNextMatch (start, finish, tree, count) + else + loopNextMatch (start, finish, tree, count - 1) + end end diff --git a/temp.txt b/temp.txt index 65624dc..faf412c 100644 --- a/temp.txt +++ b/temp.txt @@ -1 +1,187 @@ -Hello, World! - + * / ? +structure PersistentVector = +struct + (* Clojure-style persistent vector, for building search list. + * There is an "int table" too, which stores the last index + * at the node with the same index. + * We can use the size table for binary search. + * *) + datatype t = + BRANCH of t vector * int vector + | LEAF of {start: int, finish: int} vector * int vector + + val maxSize = 32 + + fun isEmpty t = + case t of + LEAF (_, sizes) => Vector.length sizes = 0 + | _ => false + + val empty = LEAF (#[], #[]) + + datatype append_result = APPEND of t | UPDATE of t + + fun isInRange (checkIdx, t) = + case t of + BRANCH (nodes, sizes) => + let + val searchIdx = BinSearch.equalOrMore (checkIdx, sizes) + in + if searchIdx = ~1 then + false + else + isInRange (checkIdx, Vector.sub (nodes, searchIdx)) + end + | LEAF (values, sizes) => + let + val searchIdx = BinSearch.equalOrMore (checkIdx, sizes) + in + if searchIdx = ~1 then + false + else + let + val {start, finish} = Vector.sub (values, searchIdx) + in + checkIdx >= start andalso checkIdx <= finish + end + end + + fun getFinishIdx t = + case t of + BRANCH (_, sizes) => Vector.sub (sizes, Vector.length sizes - 1) + | LEAF (_, sizes) => Vector.sub (sizes, Vector.length sizes - 1) + + fun helpAppend (start, finish, tree) = + case tree of + BRANCH (nodes, sizes) => + let + val lastNode = Vector.sub (nodes, Vector.length nodes - 1) + in + case helpAppend (start, finish, lastNode) of + UPDATE newLast => + let + val lastPos = Vector.length nodes - 1 + val newNode = Vector.update (nodes, lastPos, newLast) + val newSizes = Vector.update (sizes, lastPos, finish) + val newNode = BRANCH (newNode, newSizes) + in + UPDATE newNode + end + | APPEND newVec => + if Vector.length nodes + 1 > maxSize then + let val newNode = BRANCH (#[newVec], #[finish]) + in APPEND newNode + end + else + let + val newNodes = Vector.concat [nodes, #[newVec]] + val newSizes = Vector.concat [sizes, #[finish]] + val newNodes = BRANCH (newNodes, newSizes) + in + UPDATE newNodes + end + end + | LEAF (values, sizes) => + if Vector.length values + 1 > maxSize then + let val newNode = LEAF (#[{start = start, finish = finish}], #[finish]) + in APPEND newNode + end + else + let + val newNode = Vector.concat + [values, #[{start = start, finish = finish}]] + val newSizes = Vector.concat [sizes, #[finish]] + val newNode = LEAF (newNode, newSizes) + in + UPDATE newNode + end + + fun append (start, finish, tree) = + case helpAppend (start, finish, tree) of + UPDATE t => t + | APPEND newNode => + let + val maxSize = getFinishIdx tree + in + BRANCH (#[tree, newNode], #[maxSize, finish]) + end + + fun getStart tree = + case tree of + LEAF (values, _) => Vector.sub (values, 0) + | BRANCH (nodes, _) => getStart (Vector.sub (nodes, 0)) + + fun helpNextMatch (cusorIdx, tree) = + case tree of + LEAF (values, sizes) => + let + val idx = BinSearch.equalOrLess (cusorIdx, sizes) + in + if idx = ~1 then + {start = ~1, finish = ~1} + else + Vector.sub (values, idx) + end + | BRANCH (nodes, sizes) => + let + val idx = BinSearch.equalOrLess (cusorIdx, sizes) + in + if idx = ~1 then + {start = ~1, finish = ~1} + else + helpNextMatch (cusorIdx, Vector.sub (nodes, idx)) + end + + fun startNextMatch (cusorIdx, tree) = + case tree of + LEAF (values, sizes) => + if Vector.length sizes = 0 then + {start = ~1, finish = ~1} + else + let + val idx = BinSearch.equalOrLess (cusorIdx, sizes) + val idx = if idx = ~1 then 0 else idx + in + Vector.sub (values, idx) + end + | BRANCH (nodes, sizes) => + let + val idx = BinSearch.equalOrLess (cusorIdx, sizes) + in + if idx = ~1 then + {start = ~1, finish = ~1} + else + helpNextMatch (cusorIdx, Vector.sub (nodes, idx)) + end + + fun loopNextMatch (prevStart, prevFinish, tree, count) = + if count = 0 then + prevStart + else + let + val {start, finish} = startNextMatch (prevFinish + 1, tree) + in + if start = ~1 then + let + val {start, finish} = getStart tree + in + loopNextMatch (start, finish, tree, count - 1) + end + else + loopNextMatch (start, finish, tree, count - 1) + end + + fun nextMatch (cusorIdx, tree, count) = + if isEmpty tree then ~1 + else + let + val {start, finish} = startNextMatch (cusorIdx, tree) + val count = + if cusorIdx >= start andalso cusorIdx <= finish then + count + else + count - 1 + in + loopNextMatch (start, finish, tree, count); + getStart tree + end +end