This seems to be how the process for handling up/down works.


So, the approach seems to be:

- pressing up/down without shift

* find the cell that we are in.
{ findSpot }
* identify what the context is. Continue if:
 - we are not on a br from parent or self.
 - we are on a br, and the adjacent element is either at edge of same cell, or in a different cell (non-x overlapping) ... continue with edge of cell
{ scan }: 
* shift the cursor position from our continuing position and repeat until we are finding an element that contains our caret and has a different y position
* find the element under the new caret (scrolling if necessary)
* check how it compares with the initial element
 - in different row and different cell, and x-overlapping --- SUCCESS! Move there.
 - in different cell (same row or non-overlapping diff row) or edge of cell, repeat SCANNING from edge of cell
 - otherwise ... do nothing.



If the user presses up/down without Shift

  VerticalMovement.navigate
    VerticalMovement.simulate {
      start <- find the cell that we are in
      range <- TableKeys.handle
      finish <- find cell range finishes in
    } yield (start, finish, range)
      
      

  TableKeys.handle {  
    spot <- findSpot
    targetRange <- scan(spot)
    range <- deriveExact(targetRange)
  } yield (range)
  
  
  TableKeys.findSpot {
    selection <- getSelection (** fussy **)
    _ <- tryBr match {
      NONE: (finish, foffset)
      SOME(neighbour situs): processBr of BeforeAfter verification of situs
    }           
  } yield _
  
  
  BeforeAfter
   None if 
     * not both in cells
     * in the same cell and not now at end of cell
   Success if
     * in different cells and different rows and rectangles overlap x-wise
   Failure if
     * in different cells and different rows but rectangles do not overlap x-wise (so it's probably jumped to the end of the previous row if we started at the first cell of the row)
     * in different cells but the same row
     * in the same cell but now at the end of the cell
 
  
  tryBr :: (SelectionRange.write situs)
  
  * if the element is a br itself
   - situ.before either sibling or gathered text
  * if the element is a parent and (element, offset) or (element, offset-1) is br, then do situ.before(text) or situ.on(parent, indexOf(sibling))
  
  
  processBr :: fold(None, None, CellStart, CellFinish)
  
  
  
  tryCursor :: 
  
  
  
  scan :: 
  
   - try to get a new caret position with a situ range
   - get the exact range
   - do the before after analysis
     None => don't do anything
     Success => return the successful thing
     Failure => scan again from the extremity of the cell
  
  
 Retries.retry
  - get the current position
  - shift the position by the jump size
  - adjust (up to 100 times) ... defaulting back to shifted position
    - get the rectangle of the element at the shifted point
    - run the adjuster over it:
        we have the same (relevant) y, retry with a caret that is shifted again
        we have a rectangle that doesn't include the shifted caret, move the shifted caret into the rectangle and use it
        use the original otherwise
  - with the new caret, scroll if necessary and find the range under the (x, y) coordinate
