From 83e062eb60b2e9a01120c151669147c0ca6d3269 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Sun, 31 Aug 2025 00:05:48 +0100 Subject: [PATCH] fix visual bug resulting from 'TextBuilder.buildTextStringSearch' function. When we have a search string 'abc' and a file 'abcabc', there are two matches and it should also look like there are two matches, but it did not look like there were two matches prior to this commit. This commit fixes that by advancing the search position before adding to the text accumulator. --- fcore/text-builder.sml | 516 +++++++++++++++++++++------------------ shell/shell.sml | 2 +- temp.txt | 543 +---------------------------------------- 3 files changed, 274 insertions(+), 787 deletions(-) diff --git a/fcore/text-builder.sml b/fcore/text-builder.sml index fd385b7..164d0d3 100644 --- a/fcore/text-builder.sml +++ b/fcore/text-builder.sml @@ -324,6 +324,16 @@ struct in absIdx >= searchIdx + searchLen end + fun advanceSearchPos (absIdx, searchPos, searchHd, searchLen) = + let + val searchIdx = Vector.sub (searchHd, searchPos) + in + if absIdx >= searchIdx andalso absIdx < searchIdx + searchLen then + searchPos + else + searchPos + 1 + end + fun buildTextStringSearch ( pos , str @@ -357,158 +367,43 @@ struct , bgAcc , env ) - else if pos < String.size str then - case String.sub (str, pos) of - #" " => - (* if inside cursor, then create cursorAcc; - * else, just skip as usual *) - if absIdx <> cursorPos then - (* not in cursur *) - if isInSearchRange (absIdx, searchPos, searchHd, searchLen) then - (* draw *) - let - (* todo: temp colours *) - val r: Real32.real = 0.3 - val g: Real32.real = 0.1 - val b: Real32.real = 0.1 - val {fw, fh, ...} = env + else + let + val searchPos = + advanceSearchPos (absIdx, searchPos, searchHd, searchLen) + in + if searchPos = Vector.length searchHd then + (* exhausted search list so call normal build function *) + buildTextString + ( pos + , str + , acc + , posX + , posY + , startX + , tl + , absIdx + , cursorPos + , cursorAcc + , bgAcc + , env + ) - val space = makeRect (posX, posY, fw, fh, r, g, b) - val bgAcc = space :: bgAcc - in - buildTextStringSearch - ( pos + 1 - , str - , acc - , posX + xSpace - , posY - , startX - , tl - , absIdx + 1 - , cursorPos - , cursorAcc - , bgAcc - , env - , searchHd - , searchPos - , searchLen - ) - end - else - buildTextStringSearch - ( pos + 1 - , str - , acc - , posX + xSpace - , posY - , startX - , tl - , absIdx + 1 - , cursorPos - , cursorAcc - , bgAcc - , env - , searchHd - , searchPos - , searchLen - ) - else - (* in cursor *) - let - val {fw, fh, r, g, b, ...} = env - - val cursorAcc = makeRect (posX, posY, fw, fh, r, g, b) - in - buildTextStringSearch - ( pos + 1 - , str - , acc - , posX + xSpace - , posY - , startX - , tl - , absIdx + 1 - , cursorPos - , cursorAcc - , bgAcc - , env - , searchHd - , searchPos - , searchLen - ) - end - | #"\n" => - if posY + ySpace < #h env then - if absIdx <> cursorPos then - (* not in cursor position, so iterate like normal *) - buildTextStringSearch - ( pos + 1 - , str - , acc - , startX - , posY + ySpace - , startX - , tl - , absIdx + 1 - , cursorPos - , cursorAcc - , bgAcc - , env - , searchHd - , searchPos - , searchLen - ) - else - (* in cursor position, so build cursorAcc *) - let - val {fw, fh, r, g, b, ...} = env - - val cursorAcc = makeRect (posX, posY, fw, fh, r, g, b) - in - buildTextStringSearch - ( pos + 1 - , str - , acc - , startX - , posY + ySpace - , startX - , tl - , absIdx + 1 - , cursorPos - , cursorAcc - , bgAcc - , env - , searchHd - , searchPos - , searchLen - ) - end - else - accToDrawMsg (acc, cursorAcc, bgAcc, env) - | chr => - let - val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr) - in - if absIdx <> cursorPos then - (* not equal to cursor *) - if posX + xSpace < #w env then + else if pos < String.size str then + case String.sub (str, pos) of + #" " => + (* if inside cursor, then create cursorAcc; + * else, just skip as usual *) + if absIdx <> cursorPos then + (* not in cursur *) if isInSearchRange (absIdx, searchPos, searchHd, searchLen) then + (* draw *) let - val {fw, fh, ...} = env - (* todo: temp colours *) - val r: Real32.real = 0.7 - val g: Real32.real = 0.7 - val b: Real32.real = 0.7 - - (* build char vec *) - val chrVec = makeChr (chr, posX, posY, fw, fh, r, g, b) - val acc = chrVec :: acc - - (* build cursor (behind text) vec *) val r: Real32.real = 0.3 val g: Real32.real = 0.1 val b: Real32.real = 0.1 + val {fw, fh, ...} = env val space = makeRect (posX, posY, fw, fh, r, g, b) val bgAcc = space :: bgAcc @@ -532,50 +427,36 @@ struct ) end else - let - val {fw, fh, r, g, b, ...} = env - - val chrVec = makeChr (chr, posX, posY, fw, fh, r, g, b) - val acc = chrVec :: acc - val searchPos = - if - isAfterSearchRange - (absIdx, searchPos, searchHd, searchLen) - then searchPos + 1 - else searchPos - in - buildTextStringSearch - ( pos + 1 - , str - , acc - , posX + xSpace - , posY - , startX - , tl - , absIdx + 1 - , cursorPos - , cursorAcc - , bgAcc - , env - , searchHd - , searchPos - , searchLen - ) - end - else if posY + ySpace < #h env then + buildTextStringSearch + ( pos + 1 + , str + , acc + , posX + xSpace + , posY + , startX + , tl + , absIdx + 1 + , cursorPos + , cursorAcc + , bgAcc + , env + , searchHd + , searchPos + , searchLen + ) + else + (* in cursor *) let val {fw, fh, r, g, b, ...} = env - val chrVec = makeChr - (chr, startX, posY + ySpace, fw, fh, r, g, b) - val acc = chrVec :: acc + val cursorAcc = makeRect (posX, posY, fw, fh, r, g, b) in buildTextStringSearch ( pos + 1 , str , acc - , startX + xSpace - , posY + ySpace + , posX + xSpace + , posY , startX , tl , absIdx + 1 @@ -588,52 +469,39 @@ struct , searchLen ) end - else - accToDrawMsg (acc, cursorAcc, bgAcc, env) - else - (* equal to cursor *) - let - val {fw, fh, r, g, b, hr, hg, hb, ...} = env - val cursorAcc = makeRect (posX, posY, fw, fh, r, g, b) - in - if posX + xSpace < #w env then + | #"\n" => + if posY + ySpace < #h env then + if absIdx <> cursorPos then + (* not in cursor position, so iterate like normal *) + buildTextStringSearch + ( pos + 1 + , str + , acc + , startX + , posY + ySpace + , startX + , tl + , absIdx + 1 + , cursorPos + , cursorAcc + , bgAcc + , env + , searchHd + , searchPos + , searchLen + ) + else + (* in cursor position, so build cursorAcc *) let - val chrVec = makeChr (chr, posX, posY, fw, fh, hr, hg, hb) - val acc = chrVec :: acc + val {fw, fh, r, g, b, ...} = env + + val cursorAcc = makeRect (posX, posY, fw, fh, r, g, b) in - (* can start building after cursor now, - * since cursor was built *) buildTextStringSearch ( pos + 1 , str , acc - , posX + xSpace - , posY , startX - , tl - , absIdx + 1 - , cursorPos - , cursorAcc - , bgAcc - , env - , searchHd - , searchPos - , searchLen - ) - end - else if posY + ySpace < #h env then - let - val chrVec = makeChr - (chr, startX, posY + ySpace, fw, fh, hr, hg, hb) - val acc = chrVec :: acc - in - (* can start building after cursor now, - * since cursor was built *) - buildTextStringSearch - ( pos + 1 - , str - , acc - , startX + xSpace , posY + ySpace , startX , tl @@ -647,32 +515,192 @@ struct , searchLen ) end + else + accToDrawMsg (acc, cursorAcc, bgAcc, env) + | chr => + let + val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr) + in + if absIdx <> cursorPos then + (* not equal to cursor *) + if posX + xSpace < #w env then + if isInSearchRange (absIdx, searchPos, searchHd, searchLen) then + let + val {fw, fh, ...} = env + + (* todo: temp colours *) + val r: Real32.real = 0.7 + val g: Real32.real = 0.7 + val b: Real32.real = 0.7 + + (* build char vec *) + val chrVec = makeChr (chr, posX, posY, fw, fh, r, g, b) + val acc = chrVec :: acc + + (* build cursor (behind text) vec *) + val r: Real32.real = 0.3 + val g: Real32.real = 0.1 + val b: Real32.real = 0.1 + + val space = makeRect (posX, posY, fw, fh, r, g, b) + val bgAcc = space :: bgAcc + in + buildTextStringSearch + ( pos + 1 + , str + , acc + , posX + xSpace + , posY + , startX + , tl + , absIdx + 1 + , cursorPos + , cursorAcc + , bgAcc + , env + , searchHd + , searchPos + , searchLen + ) + end + else + let + val {fw, fh, r, g, b, ...} = env + + val chrVec = makeChr (chr, posX, posY, fw, fh, r, g, b) + val acc = chrVec :: acc + in + buildTextStringSearch + ( pos + 1 + , str + , acc + , posX + xSpace + , posY + , startX + , tl + , absIdx + 1 + , cursorPos + , cursorAcc + , bgAcc + , env + , searchHd + , searchPos + , searchLen + ) + end + else if posY + ySpace < #h env then + let + val {fw, fh, r, g, b, ...} = env + + val chrVec = makeChr + (chr, startX, posY + ySpace, fw, fh, r, g, b) + val acc = chrVec :: acc + in + buildTextStringSearch + ( pos + 1 + , str + , acc + , startX + xSpace + , posY + ySpace + , startX + , tl + , absIdx + 1 + , cursorPos + , cursorAcc + , bgAcc + , env + , searchHd + , searchPos + , searchLen + ) + end + else + accToDrawMsg (acc, cursorAcc, bgAcc, env) else - accToDrawMsg (acc, cursorAcc, bgAcc, env) + (* equal to cursor *) + let + val {fw, fh, r, g, b, hr, hg, hb, ...} = env + val cursorAcc = makeRect (posX, posY, fw, fh, r, g, b) + in + if posX + xSpace < #w env then + let + val chrVec = makeChr + (chr, posX, posY, fw, fh, hr, hg, hb) + val acc = chrVec :: acc + in + (* can start building after cursor now, + * since cursor was built *) + buildTextStringSearch + ( pos + 1 + , str + , acc + , posX + xSpace + , posY + , startX + , tl + , absIdx + 1 + , cursorPos + , cursorAcc + , bgAcc + , env + , searchHd + , searchPos + , searchLen + ) + end + else if posY + ySpace < #h env then + let + val chrVec = makeChr + (chr, startX, posY + ySpace, fw, fh, hr, hg, hb) + val acc = chrVec :: acc + in + (* can start building after cursor now, + * since cursor was built *) + buildTextStringSearch + ( pos + 1 + , str + , acc + , startX + xSpace + , posY + ySpace + , startX + , tl + , absIdx + 1 + , cursorPos + , cursorAcc + , bgAcc + , env + , searchHd + , searchPos + , searchLen + ) + end + else + accToDrawMsg (acc, cursorAcc, bgAcc, env) + end end - end - else - (* change to searching in string's tl *) - case tl of - hd :: tl => - buildTextStringSearch - ( 0 - , hd - , acc - , posX - , posY - , startX - , tl - , absIdx - , cursorPos - , cursorAcc - , bgAcc - , env - , searchHd - , searchPos - , searchLen - ) - | [] => accToDrawMsg (acc, cursorAcc, bgAcc, env) + else + (* change to searching in string's tl *) + case tl of + hd :: tl => + buildTextStringSearch + ( 0 + , hd + , acc + , posX + , posY + , startX + , tl + , absIdx + , cursorPos + , cursorAcc + , bgAcc + , env + , searchHd + , searchPos + , searchLen + ) + | [] => accToDrawMsg (acc, cursorAcc, bgAcc, env) + end (* gets line start idx, relative to right hd *) fun helpGetLineStartIdx (startLine, curLine, rLnHd) = diff --git a/shell/shell.sml b/shell/shell.sml index 0d6d1d1..f65eef4 100644 --- a/shell/shell.sml +++ b/shell/shell.sml @@ -69,7 +69,7 @@ struct let val buffer = #buffer app val buffer = LineGap.goToStart buffer - val searchString = "val " + val searchString = "abc" val searchList = SearchList.build (buffer, searchString) val buffer = LineGap.goToStart buffer in diff --git a/temp.txt b/temp.txt index d6ea8a2..db2fcbc 100644 --- a/temp.txt +++ b/temp.txt @@ -1,542 +1 @@ -signature TEXT_BUILDER = -aaron baron carrot durian - (* Prerequisite: LineGap is moved to requested line first. *) - val build: int * int * LineGap.t * int * int - -> MailboxType.t list -end - - - -structure TextBuilder :> TEXT_BUILDER = -struct - val xSpace = 13 - val xSpace3 = xSpace * 3 - val ySpace = 25 - val fontSize = 30.0 - - fun accToDrawMsg (textAcc, cursorAcc) = - let - open MailboxType - open DrawMsg - - val textAcc = Vector.concat textAcc - val cursorAcc = Vector.concat cursorAcc - - val textMsg = REDRAW_TEXT textAcc - val cursorMsg = REDRAW_CURSOR cursorAcc - in - [DRAW textMsg, DRAW cursorMsg] - end - - fun buildCursor (posX, posY, fWindowWidth, fWindowHeight, r, g, b) = - let - val left = posX + 9 - val left = Real32.fromInt left - val right = left + 12.0 - - val top = Real32.fromInt posY - val bottom = top + fontSize + 2.0 - - val halfHeight = fWindowHeight / 2.0 - val top = (~(top - halfHeight)) / halfHeight - val bottom = (~(bottom - halfHeight)) / halfHeight - - val halfWidth = fWindowWidth / 2.0 - val left = (left - halfWidth) / halfWidth - val right = (right - halfWidth) / halfWidth - - val vec = - #[ left, top, r, g, b - , right, top, r, g, b - , left, bottom, r, g, b - - , left, bottom, r, g, b - , right, bottom, r, g, b - , right, top, r, g, b - ] - in - [vec] - end - - (* builds text from a string with char-wrap. - * char-wrap is a similar concept to word-wrap, - * but it breaks on character in the middle of a word. - * - * Will likely want multiple versions of these two mutually recursive - * functions for each selection and cursor type: - * cursor over an individual character, - * range selection where multiple characters are selected, etc. - * - * Todo: - * - Possibly add visual horizontal indentation when char-wrap occurs - * 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 - * 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 - ( pos, str, acc, posX, posY, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , r, g, b, tl, absIdx, cursorPos, cursorAcc, hr, hg, hb - ) = - if pos < String.size str then - case String.sub (str, pos) of - #" " => - (* if inside cursor, then create cursorAcc; - * else, just skip as usual *) - if absIdx <> cursorPos then - (* not in cursur *) - buildTextStringWithinCursor - ( pos + 1, str, acc, posX + xSpace, posY, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb - ) - else - (* in cursor *) - let - val cursorAcc = buildCursor (posX, posY, fWindowWidth, fWindowHeight, r, g ,b) - in - buildTextStringAfterCursor - ( pos + 1, str, acc, posX + xSpace, posY, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , r, g, b, tl, cursorAcc - ) - 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" => - if posY + ySpace < windowHeight then - if absIdx <> cursorPos then - (* not in cursor position, so iterate like normal *) - 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 - (* in cursor position, so build cursorAcc - * and call AfterCursor function *) - if pos = String.size str - 1 andalso tl = [] then - (* if we are at end of lineGap, we want to build cursorAcc - * at different coordinates than usual *) - let - val cursorAcc = - buildCursor (startX, posY + ySpace, fWindowWidth, fWindowHeight, r, g, b) - in - accToDrawMsg (acc, cursorAcc) - end - else - let - val cursorAcc = buildCursor (posX, posY, fWindowWidth, fWindowHeight, r, g ,b) - in - buildTextStringAfterCursor - ( pos + 1, str, acc, startX, posY + ySpace, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , r, g, b, tl, cursorAcc - ) - end - else - 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 => - let - val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr) - in - if absIdx <> cursorPos then - (* not equal to cursor *) - if posX + xSpace < windowWidth then - let - val chrVec = chrFun - (posX, posY, fontSize, fontSize, fWindowWidth, fWindowHeight, r, g, b) - val acc = chrVec :: acc - in - buildTextStringWithinCursor - ( pos + 1, str, acc, posX + xSpace, posY, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, 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 - buildTextStringWithinCursor - ( pos + 1, str, acc, startX + xSpace, posY + ySpace, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , r, g, b, tl, absIdx + 1, cursorPos, cursorAcc, hr, hg, hb - ) - end - else - accToDrawMsg (acc, cursorAcc) - else - (* equal to cursor *) - let - val cursorAcc = buildCursor (posX, posY, fWindowWidth, fWindowHeight, r, g ,b) - in - if posX + xSpace < windowWidth then - let - val chrVec = chrFun - ( posX, posY, fontSize, fontSize - , fWindowWidth, fWindowHeight - , hr, hg, hb - ) - val acc = chrVec :: acc - in - (* can start building after cursor now, - * since cursor was built *) - 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 - let - val chrVec = chrFun - ( startX, posY + ySpace, fontSize, fontSize - , fWindowWidth, fWindowHeight - , hr, hg, hb - ) - val acc = chrVec :: acc - in - (* can start building after cursor now, - * since cursor was built *) - buildTextStringAfterCursor - ( pos + 1, str, acc, startX + xSpace, posY + ySpace, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , r, g, b, tl, cursorAcc - ) - end - else - accToDrawMsg (acc, cursorAcc) - end - end - - else - (* we have built cursor now, so can call after-cursor function - * to build rest of text *) - continueBuildTextLineGapAfterCursor - ( tl, acc, posX, posY, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , r, g, b, cursorAcc - ) - - and continueBuildTextLineGapBeforeCursor - ( strList, acc, posX, posY, startX - , windowWidth, windowHeight, fWindowWidth, fWindowHeight - , 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 - (startLine, cursorPos, lineGap: LineGap.t, windowWidth, windowHeight) = - let - val lineGap = LineGap.goToLine (startLine, lineGap) - val {rightStrings, rightLines, line = curLine, idx = curIdx, ...} = lineGap - in - case (rightStrings, rightLines) of - (rStrHd :: rStrTl, rLnHd :: _) => - let - (* get index of line to start building from *) - val startIdx = - if startLine > curLine then - let - val lnPos = startLine - curLine - 1 - val startIdx = Vector.sub (rLnHd, lnPos) - in - if - String.sub (rStrHd, startIdx) = #"\r" - andalso startIdx < String.size rStrHd - 1 - andalso String.sub (rStrHd, startIdx + 1) = #"\n" - then - (* handle \r\n pair *) - startIdx + 2 - else startIdx + 1 - end - else - 0 - - val absIdx = curIdx + startIdx - - in - if cursorPos < curIdx + String.size rStrHd then - (* if cursor is within string *) - buildTextStringWithinCursor - ( 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 - ) - 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 - | (_, _) => - (* requested line goes beyond the buffer, - * so just return empty list as there is nothig - * else we can do. *) - [] - end -end +abcabc