a bit of refactoring to allow addition of more tests
This commit is contained in:
@@ -6,91 +6,153 @@ struct
|
||||
if sIdx < 0 then
|
||||
case stl of
|
||||
hd :: tl =>
|
||||
getStartLineBefore
|
||||
getStartLineBefore
|
||||
(String.size hd - 1, hd, lineNum, absIdx, cursorIdx, tl)
|
||||
| [] =>
|
||||
0
|
||||
| [] => 0
|
||||
else if absIdx = cursorIdx then
|
||||
Int.max (lineNum - 1, 0)
|
||||
else
|
||||
if absIdx = cursorIdx then
|
||||
Int.max (lineNum - 1, 0)
|
||||
else
|
||||
let
|
||||
val chr = String.sub (shd, sIdx)
|
||||
in
|
||||
if chr = #"\n" then
|
||||
getStartLineBefore
|
||||
(sIdx - 1, shd, lineNum - 1, absIdx - 1, cursorIdx, stl)
|
||||
else
|
||||
getStartLineBefore
|
||||
(sIdx - 1, shd, lineNum, absIdx - 1, cursorIdx, stl)
|
||||
let
|
||||
val chr = String.sub (shd, sIdx)
|
||||
in
|
||||
if chr = #"\n" then
|
||||
getStartLineBefore
|
||||
(sIdx - 1, shd, lineNum - 1, absIdx - 1, cursorIdx, stl)
|
||||
else
|
||||
getStartLineBefore
|
||||
(sIdx - 1, shd, lineNum, absIdx - 1, cursorIdx, stl)
|
||||
end
|
||||
|
||||
fun getStartLineAfter
|
||||
( sIdx, shd, lineNum, absIdx, cursorIdx, stl
|
||||
, maxWidth, maxHeight, curWidth, curHeight
|
||||
, origLine
|
||||
) =
|
||||
if sIdx = String.size shd then
|
||||
case stl of
|
||||
hd :: tl =>
|
||||
getStartLineAfter
|
||||
( 0, hd, lineNum, absIdx, cursorIdx, tl
|
||||
, maxWidth, maxHeight, curWidth, curHeight
|
||||
fun getStartLineAfter
|
||||
( sIdx
|
||||
, shd
|
||||
, lineNum
|
||||
, absIdx
|
||||
, cursorIdx
|
||||
, stl
|
||||
, maxWidth
|
||||
, maxHeight
|
||||
, curWidth
|
||||
, curHeight
|
||||
, origLine
|
||||
) =
|
||||
if sIdx = String.size shd then
|
||||
case stl of
|
||||
hd :: tl =>
|
||||
getStartLineAfter
|
||||
( 0
|
||||
, hd
|
||||
, lineNum
|
||||
, absIdx
|
||||
, cursorIdx
|
||||
, tl
|
||||
, maxWidth
|
||||
, maxHeight
|
||||
, curWidth
|
||||
, curHeight
|
||||
, origLine
|
||||
)
|
||||
| [] => origLine
|
||||
else if absIdx = cursorIdx then
|
||||
origLine
|
||||
else
|
||||
let
|
||||
val chr = String.sub (shd, sIdx)
|
||||
in
|
||||
if
|
||||
chr = #"\n"
|
||||
then
|
||||
if curHeight + (ySpace * 3) >= maxHeight then
|
||||
getStartLineAfter
|
||||
( sIdx + 1
|
||||
, shd
|
||||
, lineNum + 1
|
||||
, absIdx + 1
|
||||
, cursorIdx
|
||||
, stl
|
||||
, maxWidth
|
||||
, maxHeight
|
||||
, 0
|
||||
, curHeight + ySpace
|
||||
, origLine + 1
|
||||
)
|
||||
else
|
||||
getStartLineAfter
|
||||
( sIdx + 1
|
||||
, shd
|
||||
, lineNum + 1
|
||||
, absIdx + 1
|
||||
, cursorIdx
|
||||
, stl
|
||||
, maxWidth
|
||||
, maxHeight
|
||||
, 0
|
||||
, curHeight + ySpace
|
||||
, origLine
|
||||
)
|
||||
| [] =>
|
||||
origLine
|
||||
else
|
||||
if absIdx = cursorIdx then
|
||||
origLine
|
||||
else
|
||||
else if
|
||||
curWidth + xSpace <= maxWidth
|
||||
then
|
||||
let
|
||||
val chr = String.sub (shd, sIdx)
|
||||
val curWidth = curWidth + xSpace
|
||||
in
|
||||
if chr = #"\n" then
|
||||
if curHeight + (ySpace * 3) >= maxHeight then
|
||||
getStartLineAfter
|
||||
( sIdx + 1, shd, lineNum + 1, absIdx + 1, cursorIdx, stl
|
||||
, maxWidth, maxHeight, 0, curHeight + ySpace
|
||||
, origLine + 1
|
||||
)
|
||||
else
|
||||
getStartLineAfter
|
||||
( sIdx + 1, shd, lineNum + 1, absIdx + 1, cursorIdx, stl
|
||||
, maxWidth, maxHeight, 0, curHeight + ySpace
|
||||
, origLine
|
||||
)
|
||||
else
|
||||
if curWidth + xSpace <= maxWidth then
|
||||
let
|
||||
val curWidth = curWidth + xSpace
|
||||
in
|
||||
getStartLineAfter
|
||||
( sIdx + 1, shd, lineNum, absIdx + 1, cursorIdx, stl
|
||||
, maxWidth, maxHeight, curWidth, curHeight
|
||||
, origLine
|
||||
)
|
||||
end
|
||||
else
|
||||
(* have to create visual line break *)
|
||||
if curHeight + (ySpace * 3) >= maxHeight then
|
||||
getStartLineAfter
|
||||
( sIdx + 1, shd, lineNum + 1, absIdx + 1, cursorIdx, stl
|
||||
, maxWidth, maxHeight, 0, curHeight + ySpace
|
||||
, origLine + 1
|
||||
)
|
||||
else
|
||||
getStartLineAfter
|
||||
( sIdx + 1, shd, lineNum + 1, absIdx + 1, cursorIdx, stl
|
||||
, maxWidth, maxHeight, 0, curHeight + ySpace
|
||||
, origLine
|
||||
)
|
||||
getStartLineAfter
|
||||
( sIdx + 1
|
||||
, shd
|
||||
, lineNum
|
||||
, absIdx + 1
|
||||
, cursorIdx
|
||||
, stl
|
||||
, maxWidth
|
||||
, maxHeight
|
||||
, curWidth
|
||||
, curHeight
|
||||
, origLine
|
||||
)
|
||||
end
|
||||
else (* have to create visual line break *) if
|
||||
curHeight + (ySpace * 3) >= maxHeight
|
||||
then
|
||||
getStartLineAfter
|
||||
( sIdx + 1
|
||||
, shd
|
||||
, lineNum + 1
|
||||
, absIdx + 1
|
||||
, cursorIdx
|
||||
, stl
|
||||
, maxWidth
|
||||
, maxHeight
|
||||
, 0
|
||||
, curHeight + ySpace
|
||||
, origLine + 1
|
||||
)
|
||||
else
|
||||
getStartLineAfter
|
||||
( sIdx + 1
|
||||
, shd
|
||||
, lineNum + 1
|
||||
, absIdx + 1
|
||||
, cursorIdx
|
||||
, stl
|
||||
, maxWidth
|
||||
, maxHeight
|
||||
, 0
|
||||
, curHeight + ySpace
|
||||
, origLine
|
||||
)
|
||||
end
|
||||
|
||||
(* Prerequisite: LineGap is moved to oldLine first. *)
|
||||
fun getStartLine (lineGap: LineGap.t, oldLine, cursorIdx, maxWidth, maxHeight) =
|
||||
let
|
||||
val {rightStrings, rightLines, line = curLine, idx = curIdx, leftStrings, ...} = lineGap
|
||||
val
|
||||
{ rightStrings
|
||||
, rightLines
|
||||
, line = curLine
|
||||
, idx = curIdx
|
||||
, leftStrings
|
||||
, ...
|
||||
} = lineGap
|
||||
in
|
||||
case (rightStrings, rightLines) of
|
||||
(rStrHd :: rStrTl, rLnHd :: _) =>
|
||||
@@ -106,73 +168,81 @@ struct
|
||||
end
|
||||
else
|
||||
0
|
||||
val absIdx = curIdx + startIdx
|
||||
val absIdx = curIdx + startIdx
|
||||
in
|
||||
if cursorIdx < absIdx then
|
||||
(* move upwards *)
|
||||
getStartLineBefore
|
||||
getStartLineBefore
|
||||
(startIdx, rStrHd, oldLine, absIdx, cursorIdx, leftStrings)
|
||||
else if cursorIdx = absIdx + 1 then
|
||||
(* double linebreak *)
|
||||
getStartLineBefore
|
||||
(startIdx + 1, rStrHd, oldLine, absIdx + 1, cursorIdx, leftStrings)
|
||||
getStartLineBefore
|
||||
( startIdx + 1
|
||||
, rStrHd
|
||||
, oldLine
|
||||
, absIdx + 1
|
||||
, cursorIdx
|
||||
, leftStrings
|
||||
)
|
||||
else if cursorIdx > absIdx then
|
||||
(* possibly move downwards *)
|
||||
getStartLineAfter
|
||||
( startIdx, rStrHd, oldLine, absIdx, cursorIdx, rStrTl
|
||||
, maxWidth, maxHeight, 0, 0
|
||||
, oldLine
|
||||
)
|
||||
getStartLineAfter
|
||||
( startIdx
|
||||
, rStrHd
|
||||
, oldLine
|
||||
, absIdx
|
||||
, cursorIdx
|
||||
, rStrTl
|
||||
, maxWidth
|
||||
, maxHeight
|
||||
, 0
|
||||
, 0
|
||||
, oldLine
|
||||
)
|
||||
else
|
||||
(* keep current line *)
|
||||
Int.max (oldLine - 1, 0)
|
||||
end
|
||||
| (_, _) =>
|
||||
oldLine
|
||||
| (_, _) => oldLine
|
||||
end
|
||||
|
||||
fun helpCentreCursor (strPos, str, lineNum, stl, maxW, halfH, curW, curH) =
|
||||
if strPos < 0 then
|
||||
case stl of
|
||||
hd :: tl =>
|
||||
helpCentreCursor
|
||||
helpCentreCursor
|
||||
(String.size hd - 1, hd, lineNum, tl, maxW, halfH, curW, curH)
|
||||
| [] =>
|
||||
(* return 0 for start of buffer *)
|
||||
0
|
||||
| [] => (* return 0 for start of buffer *) 0
|
||||
else
|
||||
let
|
||||
val chr = String.sub (str, strPos)
|
||||
in
|
||||
if chr = #"\n" then
|
||||
if
|
||||
chr = #"\n"
|
||||
then
|
||||
if curH + (ySpace * 3) >= halfH then
|
||||
(* if we exceeded half the screen *)
|
||||
lineNum
|
||||
else
|
||||
helpCentreCursor
|
||||
( strPos - 1, str, lineNum - 1, stl, maxW, halfH
|
||||
, 0, curH + ySpace
|
||||
)
|
||||
else
|
||||
if curW + xSpace <= maxW then
|
||||
let
|
||||
val curW = curW + xSpace
|
||||
in
|
||||
helpCentreCursor
|
||||
( strPos - 1, str, lineNum, stl, maxW, halfH
|
||||
, curW + xSpace, curH
|
||||
)
|
||||
end
|
||||
else
|
||||
(* have to create visual line break *)
|
||||
if curH + (ySpace * 3) >= halfH then
|
||||
(* if at limit, return current line lineNum *)
|
||||
lineNum
|
||||
else
|
||||
helpCentreCursor
|
||||
( strPos - 1, str, lineNum - 1, stl, maxW, halfH
|
||||
, 0, curH + ySpace
|
||||
)
|
||||
helpCentreCursor
|
||||
(strPos - 1, str, lineNum - 1, stl, maxW, halfH, 0, curH + ySpace)
|
||||
else if
|
||||
curW + xSpace <= maxW
|
||||
then
|
||||
let
|
||||
val curW = curW + xSpace
|
||||
in
|
||||
helpCentreCursor
|
||||
(strPos - 1, str, lineNum, stl, maxW, halfH, curW + xSpace, curH)
|
||||
end
|
||||
else (* have to create visual line break *) if
|
||||
curH + (ySpace * 3) >= halfH
|
||||
then
|
||||
(* if at limit, return current line lineNum *)
|
||||
lineNum
|
||||
else
|
||||
helpCentreCursor
|
||||
(strPos - 1, str, lineNum - 1, stl, maxW, halfH, 0, curH + ySpace)
|
||||
end
|
||||
|
||||
(* search for prev \n, and once found,
|
||||
@@ -181,10 +251,8 @@ struct
|
||||
if strPos < 0 then
|
||||
case stl of
|
||||
hd :: tl =>
|
||||
getCursorStartLine
|
||||
(String.size hd - 1, hd, lineNum, tl, maxW, halfH)
|
||||
| [] =>
|
||||
0
|
||||
getCursorStartLine (String.size hd - 1, hd, lineNum, tl, maxW, halfH)
|
||||
| [] => 0
|
||||
else
|
||||
let
|
||||
val chr = String.sub (str, strPos)
|
||||
@@ -194,21 +262,15 @@ struct
|
||||
helpCentreCursor
|
||||
(strPos - 1, str, lineNum - 1, stl, maxW, halfH, xSpace, ySpace)
|
||||
else
|
||||
getCursorStartLine
|
||||
(strPos - 1, str, lineNum, stl, maxW, halfH)
|
||||
getCursorStartLine (strPos - 1, str, lineNum, stl, maxW, halfH)
|
||||
end
|
||||
|
||||
fun getLineNum (strIdx, lhd, bufferLine) =
|
||||
if Vector.length lhd = 0 then
|
||||
bufferLine
|
||||
else if Vector.length lhd = 1 then
|
||||
let
|
||||
val lineIdx = Vector.sub (lhd, 0)
|
||||
in
|
||||
if lineIdx < strIdx then
|
||||
bufferLine + 1
|
||||
else
|
||||
bufferLine
|
||||
let val lineIdx = Vector.sub (lhd, 0)
|
||||
in if lineIdx < strIdx then bufferLine + 1 else bufferLine
|
||||
end
|
||||
else
|
||||
let
|
||||
@@ -223,125 +285,164 @@ struct
|
||||
end
|
||||
|
||||
(* Prerequisite: LineGap is moved to cursor *)
|
||||
fun getStartLineWithCursorCentered
|
||||
fun getStartLineWithCursorCentered
|
||||
(lineGap: LineGap.t, cursorIdx, origLine, maxWidth, maxHeight) =
|
||||
let
|
||||
val {rightStrings, rightLines, idx = bufferIdx, line = bufferLine, leftStrings, ...} = lineGap
|
||||
in
|
||||
case (rightStrings, rightLines) of
|
||||
(shd :: stl, lhd :: ltl) =>
|
||||
let
|
||||
(* convert absolute cursorIdx to idx relative to hd string *)
|
||||
val strIdx = cursorIdx - bufferIdx
|
||||
in
|
||||
if strIdx < String.size shd then
|
||||
(* strIdx is in hd *)
|
||||
let
|
||||
val lineNum = getLineNum (strIdx, lhd, bufferLine)
|
||||
in
|
||||
getCursorStartLine
|
||||
(strIdx, shd, lineNum, leftStrings, maxWidth, maxHeight)
|
||||
end
|
||||
else
|
||||
(* strIdx is in tl *)
|
||||
case (stl, ltl) of
|
||||
(stlhd :: stltl, ltlhd :: _) =>
|
||||
let
|
||||
val strIdx = strIdx - String.size shd
|
||||
val bufferLine = bufferLine + Vector.length lhd
|
||||
val lineNum = getLineNum (strIdx, ltlhd, bufferLine)
|
||||
val leftStrings = shd :: leftStrings
|
||||
in
|
||||
getCursorStartLine
|
||||
(strIdx, stlhd, lineNum, leftStrings, maxWidth, maxHeight)
|
||||
end
|
||||
| (_, _) =>
|
||||
origLine
|
||||
end
|
||||
| (_, _) =>
|
||||
origLine
|
||||
end
|
||||
let
|
||||
val
|
||||
{ rightStrings
|
||||
, rightLines
|
||||
, idx = bufferIdx
|
||||
, line = bufferLine
|
||||
, leftStrings
|
||||
, ...
|
||||
} = lineGap
|
||||
in
|
||||
case (rightStrings, rightLines) of
|
||||
(shd :: stl, lhd :: ltl) =>
|
||||
let
|
||||
(* convert absolute cursorIdx to idx relative to hd string *)
|
||||
val strIdx = cursorIdx - bufferIdx
|
||||
in
|
||||
if strIdx < String.size shd then
|
||||
(* strIdx is in hd *)
|
||||
let
|
||||
val lineNum = getLineNum (strIdx, lhd, bufferLine)
|
||||
in
|
||||
getCursorStartLine
|
||||
(strIdx, shd, lineNum, leftStrings, maxWidth, maxHeight)
|
||||
end
|
||||
else
|
||||
(* strIdx is in tl *)
|
||||
case (stl, ltl) of
|
||||
(stlhd :: stltl, ltlhd :: _) =>
|
||||
let
|
||||
val strIdx = strIdx - String.size shd
|
||||
val bufferLine = bufferLine + Vector.length lhd
|
||||
val lineNum = getLineNum (strIdx, ltlhd, bufferLine)
|
||||
val leftStrings = shd :: leftStrings
|
||||
in
|
||||
getCursorStartLine
|
||||
(strIdx, stlhd, lineNum, leftStrings, maxWidth, maxHeight)
|
||||
end
|
||||
| (_, _) => origLine
|
||||
end
|
||||
| (_, _) => origLine
|
||||
end
|
||||
|
||||
fun helpIsCursorVisible
|
||||
(strPos, str, stl, absIdx, maxW, maxH, curW, curH, newCursorIdx) =
|
||||
if strPos = String.size str then
|
||||
case stl of
|
||||
hd :: tl =>
|
||||
helpIsCursorVisible
|
||||
(0, hd, tl, absIdx, maxW, maxH, curW, curH, newCursorIdx)
|
||||
| [] =>
|
||||
true
|
||||
else
|
||||
if absIdx = newCursorIdx then
|
||||
true
|
||||
else
|
||||
let
|
||||
val chr = String.sub (str, strPos)
|
||||
in
|
||||
if chr = #"\n" then
|
||||
if curH + (ySpace * 3) >= maxH then
|
||||
false
|
||||
else
|
||||
helpIsCursorVisible
|
||||
( strPos + 1, str, stl, absIdx + 1
|
||||
, maxW, maxH, 0, curH + ySpace, newCursorIdx
|
||||
)
|
||||
else
|
||||
if curW + xSpace <= maxW then
|
||||
helpIsCursorVisible
|
||||
( strPos + 1, str, stl, absIdx + 1
|
||||
, maxW, maxH, curW + xSpace, curH, newCursorIdx
|
||||
)
|
||||
else
|
||||
(* have to create visual line break *)
|
||||
if curH + (ySpace * 3) >= maxH then
|
||||
false
|
||||
else
|
||||
helpIsCursorVisible
|
||||
( strPos + 1, str, stl, absIdx + 1
|
||||
, maxW, maxH, 0, curH + ySpace, newCursorIdx
|
||||
)
|
||||
end
|
||||
|
||||
fun startIsCursorVisible
|
||||
(curIdx, shd, stl, lhd, startLine, curLine, maxW, maxH, newCursorIdx) =
|
||||
if startLine = curLine then
|
||||
helpIsCursorVisible
|
||||
(0, shd, stl, curIdx, maxW, maxH, 0, 0, newCursorIdx)
|
||||
else
|
||||
let
|
||||
val relativeLine = (curLine + Vector.length lhd) - startLine
|
||||
val lineIdx = Vector.sub (lhd, relativeLine)
|
||||
val absIdx = curIdx + lineIdx
|
||||
in
|
||||
if strPos = String.size str then
|
||||
case stl of
|
||||
hd :: tl =>
|
||||
helpIsCursorVisible
|
||||
(lineIdx, shd, stl, absIdx, maxW, maxH, 0, 0, newCursorIdx)
|
||||
end
|
||||
(0, hd, tl, absIdx, maxW, maxH, curW, curH, newCursorIdx)
|
||||
| [] => true
|
||||
else if absIdx = newCursorIdx then
|
||||
true
|
||||
else
|
||||
let
|
||||
val chr = String.sub (str, strPos)
|
||||
in
|
||||
if
|
||||
chr = #"\n"
|
||||
then
|
||||
if curH + (ySpace * 3) >= maxH then
|
||||
false
|
||||
else
|
||||
helpIsCursorVisible
|
||||
( strPos + 1
|
||||
, str
|
||||
, stl
|
||||
, absIdx + 1
|
||||
, maxW
|
||||
, maxH
|
||||
, 0
|
||||
, curH + ySpace
|
||||
, newCursorIdx
|
||||
)
|
||||
else if
|
||||
curW + xSpace <= maxW
|
||||
then
|
||||
helpIsCursorVisible
|
||||
( strPos + 1
|
||||
, str
|
||||
, stl
|
||||
, absIdx + 1
|
||||
, maxW
|
||||
, maxH
|
||||
, curW + xSpace
|
||||
, curH
|
||||
, newCursorIdx
|
||||
)
|
||||
else (* have to create visual line break *) if
|
||||
curH + (ySpace * 3) >= maxH
|
||||
then
|
||||
false
|
||||
else
|
||||
helpIsCursorVisible
|
||||
( strPos + 1
|
||||
, str
|
||||
, stl
|
||||
, absIdx + 1
|
||||
, maxW
|
||||
, maxH
|
||||
, 0
|
||||
, curH + ySpace
|
||||
, newCursorIdx
|
||||
)
|
||||
end
|
||||
|
||||
fun startIsCursorVisible
|
||||
(curIdx, shd, stl, lhd, startLine, curLine, maxW, maxH, newCursorIdx) =
|
||||
if startLine = curLine then
|
||||
helpIsCursorVisible (0, shd, stl, curIdx, maxW, maxH, 0, 0, newCursorIdx)
|
||||
else
|
||||
let
|
||||
val relativeLine = (curLine + Vector.length lhd) - startLine
|
||||
val lineIdx = Vector.sub (lhd, relativeLine)
|
||||
val absIdx = curIdx + lineIdx
|
||||
in
|
||||
helpIsCursorVisible
|
||||
(lineIdx, shd, stl, absIdx, maxW, maxH, 0, 0, newCursorIdx)
|
||||
end
|
||||
|
||||
(* Prerequisite: move LineGap.t to startLine *)
|
||||
fun isCursorVisible (lineGap: LineGap.t, newCursorIdx, startLine, maxW, maxH) =
|
||||
let
|
||||
val {rightStrings, rightLines, line = curLine, idx = curIdx, ...} = lineGap
|
||||
let
|
||||
val {rightStrings, rightLines, line = curLine, idx = curIdx, ...} =
|
||||
lineGap
|
||||
in
|
||||
case (rightStrings, rightLines) of
|
||||
(shd :: stl, lhd :: ltl) =>
|
||||
if startLine < curLine + Vector.length lhd then
|
||||
(* startLine in this node *)
|
||||
startIsCursorVisible
|
||||
( curIdx, shd, stl, lhd, startLine, curLine
|
||||
, maxW, maxH, newCursorIdx
|
||||
startIsCursorVisible
|
||||
( curIdx
|
||||
, shd
|
||||
, stl
|
||||
, lhd
|
||||
, startLine
|
||||
, curLine
|
||||
, maxW
|
||||
, maxH
|
||||
, newCursorIdx
|
||||
)
|
||||
else
|
||||
(* startLine is in stl *)
|
||||
(case (stl, ltl) of
|
||||
(stlhd :: stltl, ltlhd :: ltltl) =>
|
||||
startIsCursorVisible
|
||||
( curIdx, stlhd, stltl, ltlhd, startLine, curLine
|
||||
, maxW, maxH, newCursorIdx
|
||||
)
|
||||
| (_, _) =>
|
||||
true)
|
||||
| (_, _) =>
|
||||
true
|
||||
(stlhd :: stltl, ltlhd :: ltltl) =>
|
||||
startIsCursorVisible
|
||||
( curIdx
|
||||
, stlhd
|
||||
, stltl
|
||||
, ltlhd
|
||||
, startLine
|
||||
, curLine
|
||||
, maxW
|
||||
, maxH
|
||||
, newCursorIdx
|
||||
)
|
||||
| (_, _) => true)
|
||||
| (_, _) => true
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user