have functionality for cursor to scroll down a line when cursor moves down one line working, but it only seems to work perfectly when there are no visual line breaks

This commit is contained in:
2024-10-28 21:56:07 +00:00
parent 0ed5a23ade
commit bff4c006ed
5 changed files with 75 additions and 304 deletions

View File

@@ -25,13 +25,15 @@ struct
val {windowWidth, windowHeight, startLine, ...} = app val {windowWidth, windowHeight, startLine, ...} = app
(* move LineGap to first line displayed on screen, and build new text *) (* move LineGap to first line displayed on screen, and build new text *)
val buffer = LineGap.goToLine (startLine, buffer) val buffer =
LineGap.goToLine (startLine, buffer)
val startLine = TextWindow.getStartLine val startLine = TextWindow.getStartLine
(buffer, startLine, cursorIdx, windowWidth, windowHeight) (buffer, startLine, cursorIdx, windowWidth, windowHeight)
val drawMsg = TextBuilder.build val drawMsg =
(startLine, cursorIdx, buffer, windowWidth, windowHeight) TextBuilder.build
(startLine, cursorIdx, buffer, windowWidth, windowHeight)
val mode = NORMAL_MODE "" val mode = NORMAL_MODE ""
val newApp = AppWith.bufferAndCursorIdx val newApp = AppWith.bufferAndCursorIdx
@@ -132,6 +134,20 @@ struct
(newApp, []) (newApp, [])
end end
fun moveLine (app: app_type, f) =
let
val {cursorIdx, buffer, windowWidth, windowHeight, startLine, ...} = app
val startLine = f (startLine, 1)
val buffer = LineGap.goToLine (startLine, buffer)
val newApp = AppWith.startLine (app, startLine, buffer)
val drawMsg = TextBuilder.build
(startLine, cursorIdx, buffer, windowWidth, windowHeight)
in
(newApp, drawMsg)
end
fun handleChr (app: app_type, count, chr, str) = fun handleChr (app: app_type, count, chr, str) =
case chr of case chr of
#"h" => moveBackward (app, count, Cursor.viH) #"h" => moveBackward (app, count, Cursor.viH)
@@ -144,6 +160,9 @@ struct
| #"B" => moveBackward (app, count, Cursor.prevWORD) | #"B" => moveBackward (app, count, Cursor.prevWORD)
| #"e" => moveForwards (app, count, Cursor.endOfWord) | #"e" => moveForwards (app, count, Cursor.endOfWord)
| #"E" => moveForwards (app, count, Cursor.endOfWORD) | #"E" => moveForwards (app, count, Cursor.endOfWORD)
(* PLACEHOLDER *)
| #"," => moveLine (app, op+)
| #"." => moveLine (app, op-)
(* can only move to start or end of line once (* can only move to start or end of line once
* so hardcode count as 1 *) * so hardcode count as 1 *)
| #"0" => | #"0" =>

View File

@@ -2,6 +2,26 @@ structure AppWith =
struct struct
open AppType open AppType
fun startLine (app: app_type, startLine, newBuffer) =
let
val
{ startLine = _
, buffer = _
, mode
, windowWidth
, windowHeight
, cursorIdx
} = app
in
{ startLine = startLine
, buffer = newBuffer
, mode = mode
, windowWidth = windowWidth
, windowHeight = windowHeight
, cursorIdx = cursorIdx
}
end
fun bufferAndSize (app: app_type, newBuffer, newWidth, newHeight) = fun bufferAndSize (app: app_type, newBuffer, newWidth, newHeight) =
let let
val val

View File

@@ -65,217 +65,10 @@ struct
* Todo: * Todo:
* - Possibly add visual horizontal indentation when char-wrap occurs * - Possibly add visual horizontal indentation when char-wrap occurs
* on an indented line *) * on an indented line *)
fun buildTextStringAfterCursor
( pos, str, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
) =
if pos < String.size str then
case String.sub (str, pos) of
#" " =>
(* if space, then proceed forward one char
* without adding to acc *)
buildTextStringAfterCursor
( pos + 1, str, acc, posX + xSpace, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
)
| #"\t" =>
(* if tab, proceed forward one char,
* and jump visually forwards three chars *)
buildTextStringAfterCursor
( pos + 1, str, acc, posX + xSpace3, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
)
| #"\n" =>
(* if \n, move down vertically, and move to start horizontally
* assuming we have not exceeded the window's height.
* If we have exceeded the window's height, just return acc. *)
if posY + ySpace < windowHeight then
buildTextStringAfterCursor
( pos + 1, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
)
else
(* return if there is no more vertical space after line break *)
accToDrawMsg (acc, cursorAcc)
| #"\r" =>
(* same as \n, except we also check if we are in a \r\n pair,
* and proceed two characters forward if so *)
if posY + ySpace < windowHeight then
if
pos < String.size str - 1
andalso String.sub (str, pos + 1) = #"\n"
then
buildTextStringAfterCursor
( pos + 2, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
)
else
buildTextStringAfterCursor
( pos + 1, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
)
else
(* return if there is no more vertical space after line break *)
accToDrawMsg (acc, cursorAcc)
| chr =>
(* for any other character, add it to acc if there is space,
* and proceed forward one character in the string *)
let
val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr)
in
if posX + xSpace < windowWidth then
(* if there is horizontal space, place char on the right *)
let
val chrVec = chrFun
(posX, posY, fontSize, fontSize, fWindowWidth, fWindowHeight, r, g, b)
val acc = chrVec :: acc
in
buildTextStringAfterCursor
( pos + 1, str, acc, posX + xSpace, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
)
end
else if posY + ySpace < windowHeight then
(* if there is vertical space, place char down below at startX *)
let
val chrVec = chrFun
( startX, posY + ySpace, fontSize, fontSize
, fWindowWidth, fWindowHeight
, r, g, b
)
val acc = chrVec :: acc
in
buildTextStringAfterCursor
( pos + 1, str, acc, startX + xSpace, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
)
end
else
(* return if no space horizontally or vertically *)
accToDrawMsg (acc, cursorAcc)
end
else
(* if we reached the end of the string,
* call function to build next string *)
continueBuildTextLineGapAfterCursor
( tl, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, cursorAcc
)
and continueBuildTextLineGapAfterCursor
( strList, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, cursorAcc
) =
case strList of
hd :: tl =>
buildTextStringAfterCursor
( 0, hd, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc
)
| [] => accToDrawMsg (acc, cursorAcc)
(* same as buildTextStringAfterCursor, except this keeps track of absolute (* same as buildTextStringAfterCursor, except this keeps track of absolute
* index and cursor pos too *) * index and cursor pos too *)
fun buildTextStringBeforeCursor
( pos, str, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx, cursorPos, hr, hg, hb
) =
if pos < String.size str then
case String.sub (str, pos) of
#" " =>
buildTextStringBeforeCursor
( pos + 1, str, acc, posX + xSpace, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, hr, hg, hb
)
| #"\t" =>
buildTextStringBeforeCursor
( pos + 1, str, acc, posX + xSpace3, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, hr, hg, hb
)
| #"\n" =>
if posY + ySpace < windowHeight then
buildTextStringBeforeCursor
( pos + 1, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, hr, hg, hb
)
else
accToDrawMsg (acc, [])
| #"\r" =>
if posY + ySpace < windowHeight then
if
pos < String.size str - 1
andalso String.sub (str, pos + 1) = #"\n"
then
buildTextStringBeforeCursor
( pos + 2, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 2, cursorPos, hr, hg, hb
)
else
buildTextStringBeforeCursor
( pos + 1, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, hr, hg, hb
)
else
accToDrawMsg (acc, [])
| chr =>
let
val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr)
in
if posX + xSpace < windowWidth then
let
val chrVec = chrFun
(posX, posY, fontSize, fontSize, fWindowWidth, fWindowHeight, r, g, b)
val acc = chrVec :: acc
in
buildTextStringBeforeCursor
( pos + 1, str, acc, posX + xSpace, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, hr, hg, hb
)
end
else if posY + ySpace < windowHeight then
let
val chrVec = chrFun
( startX, posY + ySpace, fontSize, fontSize
, fWindowWidth, fWindowHeight
, r, g, b
)
val acc = chrVec :: acc
in
buildTextStringBeforeCursor
( pos + 1, str, acc, startX + xSpace, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, hr, hg, hb
)
end
else
accToDrawMsg (acc, [])
end
else
continueBuildTextLineGapBeforeCursor
( tl, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, absIdx, cursorPos, hr, hg, hb
)
and buildTextStringWithinCursor fun buildTextString
( pos, str, acc, posX, posY, startX ( pos, str, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx, cursorPos, cursorAcc, hr, hg, hb , r, g, b, tl, absIdx, cursorPos, cursorAcc, hr, hg, hb
@@ -287,7 +80,7 @@ struct
* else, just skip as usual *) * else, just skip as usual *)
if absIdx <> cursorPos then if absIdx <> cursorPos then
(* not in cursur *) (* not in cursur *)
buildTextStringWithinCursor buildTextString
( pos + 1, str, acc, posX + xSpace, posY, startX ( pos + 1, str, acc, posX + xSpace, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
@@ -297,32 +90,23 @@ struct
let let
val cursorAcc = buildCursor (posX, posY, fWindowWidth, fWindowHeight, r, g ,b) val cursorAcc = buildCursor (posX, posY, fWindowWidth, fWindowHeight, r, g ,b)
in in
buildTextStringAfterCursor buildTextString
( pos + 1, str, acc, posX + xSpace, posY, startX ( pos + 1, str, acc, posX + xSpace, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
) )
end end
| #"\t" =>
(* todo: draw cursor if cursor is on tab
* but this is not a priority right now *)
buildTextStringWithinCursor
( pos + 1, str, acc, posX + xSpace3, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
)
| #"\n" => | #"\n" =>
if posY + ySpace < windowHeight then if posY + ySpace < windowHeight then
if absIdx <> cursorPos then if absIdx <> cursorPos then
(* not in cursor position, so iterate like normal *) (* not in cursor position, so iterate like normal *)
buildTextStringWithinCursor buildTextString
( pos + 1, str, acc, startX, posY + ySpace, startX ( pos + 1, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
) )
else else
(* in cursor position, so build cursorAcc (* in cursor position, so build cursorAcc *)
* and call AfterCursor function *)
if pos = String.size str - 1 andalso tl = [] then if pos = String.size str - 1 andalso tl = [] then
(* if we are at end of lineGap, we want to build cursorAcc (* if we are at end of lineGap, we want to build cursorAcc
* at different coordinates than usual *) * at different coordinates than usual *)
@@ -336,33 +120,14 @@ struct
let let
val cursorAcc = buildCursor (posX, posY, fWindowWidth, fWindowHeight, r, g ,b) val cursorAcc = buildCursor (posX, posY, fWindowWidth, fWindowHeight, r, g ,b)
in in
buildTextStringAfterCursor buildTextString
( pos + 1, str, acc, startX, posY + ySpace, startX ( pos + 1, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
) )
end end
else else
accToDrawMsg (acc, cursorAcc) accToDrawMsg (acc, cursorAcc)
| #"\r" =>
if posY + ySpace < windowHeight then
if
pos < String.size str - 1
andalso String.sub (str, pos + 1) = #"\n"
then
buildTextStringWithinCursor
( pos + 2, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 2, cursorPos, cursorAcc, hr, hg, hb
)
else
buildTextStringWithinCursor
( pos + 1, str, acc, startX, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
)
else
accToDrawMsg (acc, cursorAcc)
| chr => | chr =>
let let
val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr) val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr)
@@ -375,7 +140,7 @@ struct
(posX, posY, fontSize, fontSize, fWindowWidth, fWindowHeight, r, g, b) (posX, posY, fontSize, fontSize, fWindowWidth, fWindowHeight, r, g, b)
val acc = chrVec :: acc val acc = chrVec :: acc
in in
buildTextStringWithinCursor buildTextString
( pos + 1, str, acc, posX + xSpace, posY, startX ( pos + 1, str, acc, posX + xSpace, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
@@ -390,7 +155,7 @@ struct
) )
val acc = chrVec :: acc val acc = chrVec :: acc
in in
buildTextStringWithinCursor buildTextString
( pos + 1, str, acc, startX + xSpace, posY + ySpace, startX ( pos + 1, str, acc, startX + xSpace, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
@@ -414,10 +179,10 @@ struct
in in
(* can start building after cursor now, (* can start building after cursor now,
* since cursor was built *) * since cursor was built *)
buildTextStringAfterCursor buildTextString
( pos + 1, str, acc, posX + xSpace, posY, startX ( pos + 1, str, acc, posX + xSpace, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
) )
end end
else if posY + ySpace < windowHeight then else if posY + ySpace < windowHeight then
@@ -431,48 +196,28 @@ struct
in in
(* can start building after cursor now, (* can start building after cursor now,
* since cursor was built *) * since cursor was built *)
buildTextStringAfterCursor buildTextString
( pos + 1, str, acc, startX + xSpace, posY + ySpace, startX ( pos + 1, str, acc, startX + xSpace, posY + ySpace, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, cursorAcc , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb
) )
end end
else else
accToDrawMsg (acc, cursorAcc) accToDrawMsg (acc, cursorAcc)
end end
end end
else else
(* we have built cursor now, so can call after-cursor function (* we have built cursor now, so can call after-cursor function
* to build rest of text *) * to build rest of text *)
continueBuildTextLineGapAfterCursor case tl of
( tl, acc, posX, posY, startX hd :: tl =>
, windowWidth, windowHeight, fWindowWidth, fWindowHeight buildTextString
, r, g, b, cursorAcc ( 0, hd, acc, posX, posY, startX
) , windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx, cursorPos, cursorAcc, hr, hg, hb
and continueBuildTextLineGapBeforeCursor )
( strList, acc, posX, posY, startX | [] =>
, windowWidth, windowHeight, fWindowWidth, fWindowHeight accToDrawMsg (acc, cursorAcc)
, r, g, b, absIdx, cursorPos, hr, hg, hb
) =
case strList of
hd :: tl =>
if cursorPos >= absIdx + cursorPos then
(* if end of string is before cursor *)
buildTextStringBeforeCursor
( 0, hd, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx, cursorPos, hr, hg, hb
)
else
(* if within cursor *)
buildTextStringWithinCursor
( 0, hd, acc, posX, posY, startX
, windowWidth, windowHeight, fWindowWidth, fWindowHeight
, r, g, b, tl, absIdx, cursorPos, [], hr, hg, hb
)
| [] => accToDrawMsg (acc, [])
fun build fun build
(startLine, cursorPos, lineGap: LineGap.t, windowWidth, windowHeight) = (startLine, cursorPos, lineGap: LineGap.t, windowWidth, windowHeight) =
@@ -502,28 +247,15 @@ struct
0 0
val absIdx = curIdx + startIdx val absIdx = curIdx + startIdx
in in
if cursorPos < curIdx + String.size rStrHd then buildTextString
(* if cursor is within string *) ( startIdx, rStrHd, []
buildTextStringWithinCursor , 5, 5, 5
( startIdx, rStrHd, [] , windowWidth, windowHeight
, 5, 5, 5 , Real32.fromInt windowWidth, Real32.fromInt windowHeight
, windowWidth, windowHeight , 0.67, 0.51, 0.83
, Real32.fromInt windowWidth, Real32.fromInt windowHeight , rStrTl, absIdx, cursorPos, []
, 0.67, 0.51, 0.83 , 0.211, 0.219, 0.25
, rStrTl, absIdx, cursorPos, [] )
, 0.211, 0.219, 0.25
)
else
(* if cursor is after string *)
buildTextStringBeforeCursor
( startIdx, rStrHd, []
, 5, 5, 5
, windowWidth, windowHeight
, Real32.fromInt windowWidth, Real32.fromInt windowHeight
, 0.67, 0.51, 0.83
, rStrTl, absIdx, cursorPos
, 0.211, 0.219, 0.25
)
end end
| (_, _) => | (_, _) =>
(* requested line goes beyond the buffer, (* requested line goes beyond the buffer,

BIN
shf

Binary file not shown.