diff --git a/fcore/app-update.sml b/fcore/app-update.sml index cc19a9f..08e2cbb 100644 --- a/fcore/app-update.sml +++ b/fcore/app-update.sml @@ -24,6 +24,8 @@ struct let val {windowWidth, windowHeight, startLine, ...} = app (* todo: get new startLine if cursor has moved out of screen *) + val startLine = TextWindow.getStartLine + (buffer, startLine, cursorIdx, windowWidth, windowHeight) (* move LineGap to first line displayed on screen, and build new text *) val buffer = LineGap.goToLine (startLine, buffer) @@ -31,7 +33,8 @@ struct (startLine, cursorIdx, buffer, windowWidth, windowHeight) val mode = NORMAL_MODE "" - val newApp = AppWith.bufferAndCursorIdx (app, buffer, cursorIdx, mode) + val newApp = AppWith.bufferAndCursorIdx + (app, buffer, cursorIdx, mode, startLine) in (newApp, drawMsg) end @@ -61,7 +64,8 @@ struct (startLine, cursorIdx, buffer, windowWidth, windowHeight) val mode = NORMAL_MODE "" - val newApp = AppWith.bufferAndCursorIdx (app, buffer, cursorIdx, mode) + val newApp = AppWith.bufferAndCursorIdx + (app, buffer, cursorIdx, mode, startLine) in (newApp, drawMsg) end @@ -99,7 +103,8 @@ struct (startLine, cursorIdx, buffer, windowWidth, windowHeight) val mode = NORMAL_MODE "" - val newApp = AppWith.bufferAndCursorIdx (app, buffer, cursorIdx, mode) + val newApp = AppWith.bufferAndCursorIdx + (app, buffer, cursorIdx, mode, startLine) in (newApp, drawMsg) end @@ -109,11 +114,8 @@ struct if pos = String.size str then pos else - let - val chr = String.sub (str, pos) - in - if Char.isDigit chr then getNumLength (pos + 1, str) - else pos + let val chr = String.sub (str, pos) + in if Char.isDigit chr then getNumLength (pos + 1, str) else pos end fun appendChr (app: app_type, chr, str) = @@ -139,7 +141,7 @@ struct | #"E" => moveForwards (app, count, Cursor.endOfWORD) (* can only move to start or end of line once * so hardcode count as 1 *) - | #"0" => + | #"0" => (* 0 is a bit of a special case. * If 0 is pressed without any preceding characters, * then it should move cursor to the start of the line. @@ -180,10 +182,7 @@ struct * such as "2dw" to delete two word * so add current chr to mode, and save it in the app state *) let - val str = - if Char.isDigit chr - then str ^ Char.toString chr - else "" + val str = if Char.isDigit chr then str ^ Char.toString chr else "" val mode = NORMAL_MODE str val newApp = AppWith.mode (app, mode) in @@ -202,7 +201,8 @@ struct (startLine, cursorIdx, buffer, windowWidth, windowHeight) val mode = NORMAL_MODE "" - val newApp = AppWith.bufferAndCursorIdx (app, buffer, cursorIdx, mode) + val newApp = AppWith.bufferAndCursorIdx + (app, buffer, cursorIdx, mode, startLine) in (newApp, drawMsg) end @@ -236,7 +236,7 @@ struct fun handleGo (count, app, newCmd) = case newCmd of - CHAR_EVENT chr => + CHAR_EVENT chr => (case chr of #"e" => moveBackward (app, count, Cursor.endOfPrevWord) | #"E" => moveBackward (app, count, Cursor.endOfPrevWORD) @@ -259,27 +259,19 @@ struct * as tillNextChr with any count above 1 * so just hardcode 1 *) handleNextChr (1, app, Cursor.tillNextChr, newCmd) - | #"T" => - (* to just before chr, backward *) + | #"T" => + (* to just before chr, backward *) handleNextChr (1, app, Cursor.tillPrevChr, newCmd) - | #"y" => - (* yank *) - clearMode app - | #"d" => - (* delete *) - clearMode app + | #"y" => (* yank *) clearMode app + | #"d" => (* delete *) clearMode app | #"f" => (* to chr, forward *) handleNextChr (count, app, Cursor.toNextChr, newCmd) - | #"F" => - (* to chr, backward *) + | #"F" => + (* to chr, backward *) handleNextChr (count, app, Cursor.toPrevChr, newCmd) - | #"g" => - (* go *) - handleGo (count, app, newCmd) - | #"c" => - (* change *) - clearMode app + | #"g" => (* go *) handleGo (count, app, newCmd) + | #"c" => (* change *) clearMode app | _ => (* isn't a non-terminal cmd * this case should never happen*) diff --git a/fcore/app-with.sml b/fcore/app-with.sml index 632974c..4b60553 100644 --- a/fcore/app-with.sml +++ b/fcore/app-with.sml @@ -22,7 +22,8 @@ struct } end - fun bufferAndCursorIdx (app: app_type, newBuffer, newCursorIdx, newMode) = + fun bufferAndCursorIdx + (app: app_type, newBuffer, newCursorIdx, newMode, newStartLine) = let val { mode = _ @@ -30,15 +31,15 @@ struct , cursorIdx = _ , windowWidth , windowHeight - , startLine + , startLine = _ } = app in { mode = newMode , buffer = newBuffer , cursorIdx = newCursorIdx + , startLine = newStartLine , windowWidth = windowWidth , windowHeight = windowHeight - , startLine = startLine } end diff --git a/fcore/text-builder.sml b/fcore/text-builder.sml index cc99065..a2a29dc 100644 --- a/fcore/text-builder.sml +++ b/fcore/text-builder.sml @@ -7,10 +7,7 @@ end structure TextBuilder :> TEXT_BUILDER = struct - val xSpace = 13 - val xSpace3 = xSpace * 3 - val ySpace = 25 - val fontSize = 30.0 + open TextConstants fun accToDrawMsg (textAcc, cursorAcc) = let @@ -480,7 +477,6 @@ struct 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 @@ -504,9 +500,7 @@ struct end else 0 - val absIdx = curIdx + startIdx - in if cursorPos < curIdx + String.size rStrHd then (* if cursor is within string *) diff --git a/fcore/text-constants.sml b/fcore/text-constants.sml new file mode 100644 index 0000000..36b207b --- /dev/null +++ b/fcore/text-constants.sml @@ -0,0 +1,7 @@ +structure TextConstants = +struct + val xSpace = 13 + val xSpace3 = xSpace * 3 + val ySpace = 25 + val fontSize : Real32.real = 30.0 +end diff --git a/fcore/text-window.sml b/fcore/text-window.sml new file mode 100644 index 0000000..2bf6479 --- /dev/null +++ b/fcore/text-window.sml @@ -0,0 +1,81 @@ +structure TextWindow = +struct + open TextConstants + + fun isPrevChrLn (str, strPos, strTl) = + if strPos > 0 then + String.sub (str, strPos - 1) = #"\n" + else + case strTl of + hd :: _ => + String.sub (hd, String.size hd - 1) = #"\n" + | [] => false + + fun getStartLineBefore (sIdx, shd, lineNum, absIdx, cursorIdx, stl) = + if sIdx < 0 then + case stl of + hd :: tl => + getStartLineBefore + (String.size hd - 1, hd, lineNum, absIdx, cursorIdx, tl) + | [] => + 0 + else + let + val chr = String.sub (shd, sIdx) + in + if chr = #"\n" then + if absIdx <> cursorIdx then + getStartLineBefore + (sIdx - 1, shd, lineNum - 1, absIdx - 1, cursorIdx, stl) + else + (* we have found cursor, and it is at \n *) + lineNum - 1 + else + if absIdx <> cursorIdx then + getStartLineBefore + (sIdx - 1, shd, lineNum, absIdx - 1, cursorIdx, stl) + else + (* we have found cursor; return line *) + lineNum - 1 + 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 + in + case (rightStrings, rightLines) of + (rStrHd :: rStrTl, rLnHd :: _) => + let + (* get index of line to start building from *) + val startIdx = + if oldLine > curLine then + let + val lnPos = oldLine - curLine - 1 + val startIdx = Vector.sub (rLnHd, lnPos) + in + startIdx - 1 + end + else + 0 + val absIdx = curIdx + startIdx + in + if cursorIdx < absIdx then + (* move upwards *) + getStartLineBefore + (startIdx, rStrHd, oldLine, absIdx, cursorIdx, leftStrings) + else if cursorIdx = absIdx + 1 then + (* double linebreak *) + getStartLineBefore + (startIdx + 1, rStrHd, oldLine, absIdx + 1, cursorIdx, leftStrings) + else if cursorIdx > absIdx then + (* possibly move downwards *) + oldLine + else + (* keep current line *) + Int.max (oldLine - 1, 0) + end + | (_, _) => + oldLine + end +end diff --git a/shf b/shf index b3a08cb..acd24c3 100755 Binary files a/shf and b/shf differ diff --git a/shf.mlb b/shf.mlb index 4cc3913..bc9f4eb 100644 --- a/shf.mlb +++ b/shf.mlb @@ -11,11 +11,15 @@ message-types/mailbox-type.sml fcore/app-type.sml fcore/app-with.sml + +fcore/text-constants.sml ann "allowVectorExps true" in fcore/text-builder.sml end +fcore/text-window.sml + fcore/cursor.sml fcore/app-update.sml