text editor inspired vim and yi
import ViE.State
import ViE.Key.Handler
import ViE.Key.Input

namespace ViE

/-- Parse a character into a list of keys, handling escape sequences statefully. -/
def parseKey (state : EditorState) (c : Char) (currentTime : Nat) : (EditorState × List Key) :=
  ViE.Key.parseKey state c currentTime

/-- Check for escape sequence timeout. -/
def checkTimeout (state : EditorState) (currentTime : Nat) : (EditorState × List Key) :=
  ViE.Key.checkTimeout state currentTime

def enforceScroll (state : EditorState) : EditorState :=
  let (h, w) := state.getActiveWindowScrollBounds
  -- Active window height. Reserve 1 line for status bar?
  -- UI logic reserves 1 for status bar in split rendering.
  let linesInView := if h > 1 then h - 1 else 1

  -- Vertical Scroll
  let (sRow, sCol) := state.getScroll
  let cursor := state.getCursor

  let state :=
    if cursor.row.val < sRow.val then
      state.setScroll cursor.row sCol
    else if cursor.row.val >= sRow.val + linesInView then
      let newScrollRow : Row := ⟨cursor.row.val - linesInView + 1⟩
      state.setScroll newScrollRow sCol
    else
      state

  -- Refresh scroll after potential update
  let (sRow, sCol) := state.getScroll

  -- Horizontal Scroll
  let lnWidth := if state.config.showLineNumbers then 4 else 0
  let colsInView := if w > lnWidth then w - lnWidth else 1

  let state :=
    if cursor.col.val < sCol.val then
      state.setScroll sRow cursor.col
    else if cursor.col.val >= sCol.val + colsInView then
      let newScrollCol : Col := ⟨cursor.col.val - colsInView + 1⟩
      state.setScroll sRow newScrollCol
    else
      state

  state

def update (config : Config) (state : EditorState) (k : Key) : IO EditorState := do
  let newState ← match state.mode with
  | .normal => config.bindings.normal state k
  | .insert => config.bindings.insert state k
  | .command => config.bindings.command state k
  | .searchForward => ViE.Key.handleSearchInput state k
  | .searchBackward => ViE.Key.handleSearchInput state k
  | .visual => config.bindings.visual state k
  | .visualBlock => config.bindings.visualBlock state k

  return enforceScroll newState

end ViE