diff --git a/fcore/app-update.sml b/fcore/app-update.sml index e46bf3a..1487098 100644 --- a/fcore/app-update.sml +++ b/fcore/app-update.sml @@ -59,6 +59,30 @@ struct (newApp, drawMsg) end + fun firstNonSpaceChr (app: app_type) = + let + val {buffer, windowWidth, windowHeight, startLine, cursorIdx, ...} = app + + (* move LineGap and buffer to start of line *) + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val cursorIdx = Cursor.vi0 (buffer, cursorIdx) + + (* move cursorIdx to first character on line *) + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val cursorIdx = Cursor.firstNonSpaceChr (buffer, cursorIdx) + + (* todo: get new startLine if cursor has moved out of screen *) + + (* move LineGap to first line displayed on screen, and build new text *) + val buffer = LineGap.goToLine (startLine, buffer) + val drawMsg = TextBuilder.build + (startLine, cursorIdx, buffer, windowWidth, windowHeight) + + val newApp = AppWith.bufferAndCursorIdx (app, buffer, cursorIdx) + in + (newApp, drawMsg) + end + fun handleChr (app: app_type, chr) = case chr of #"h" => moveBackward (app, Cursor.viH) @@ -73,6 +97,7 @@ struct | #"B" => moveBackward (app, Cursor.prevWORD) | #"e" => moveFowrards (app, Cursor.endOfWord) | #"E" => moveFowrards (app, Cursor.endOfWORD) + | #"^" => firstNonSpaceChr app | _ => (app, []) fun update (app, msg) = diff --git a/fcore/cursor.sml b/fcore/cursor.sml index 212b42c..9e5ed86 100644 --- a/fcore/cursor.sml +++ b/fcore/cursor.sml @@ -1196,4 +1196,70 @@ struct (* equivalent of vi's `E` command *) fun endOfWORD (lineGap, cursorIdx) = toEndOfWord (lineGap, cursorIdx, helpEndOfWORD) + + fun helpFirstNonSpaceChr + (strPos, str, absIdx, stl, ltl) = + if strPos = String.size str then + case (stl, ltl) of + (shd :: stl, lhd :: ltl) => + helpFirstNonSpaceChr + (0, shd, absIdx, stl, ltl) + | (_, _) => + absIdx - 1 + else + let + val chr = String.sub (str, strPos) + in + if Char.isSpace chr then + helpFirstNonSpaceChr + (strPos + 1, str, absIdx + 1, stl, ltl) + else + absIdx + end + + fun startFirstNonSpaceChr + (shd, strIdx, absIdx, stl, ltl) = + if strIdx < String.size shd then + helpFirstNonSpaceChr + (strIdx, shd, absIdx, stl, ltl) + else + case (stl, ltl) of + (stlhd :: stltl, ltlhd :: ltltl) => + helpFirstNonSpaceChr + (0, stlhd, absIdx, stltl, ltltl) + | (_, _) => + (* tl is empty; just return absIdx *) + absIdx + + (* Prerequisite: + * LineGap has been moved to start of line (provided with vi0). *) + fun firstNonSpaceChr (lineGap: LineGap.t, cursorIdx) = + let + val {rightStrings, rightLines, idx = bufferIdx, ...} = 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 this string *) + startFirstNonSpaceChr + (shd, strIdx, cursorIdx, stl, ltl) + else + (* strIdx is in tl *) + (case (stl, ltl) of + (stlhd :: stltl, ltlhd :: ltltl) => + let + val strIdx = strIdx - String.size shd + in + startFirstNonSpaceChr + (stlhd, strIdx, cursorIdx, stltl, ltltl) + end + | (_, _) => cursorIdx) + end + | (_, _) => + cursorIdx + end end diff --git a/shf b/shf index faa1f62..8b391a1 100755 Binary files a/shf and b/shf differ