Editfield

module Editfield(EditField, moveField, replaceField, setFieldDir, getField,getField',
                 deselectField, getSelection, getLastLineNo, getAft, getBef, getLnoEdge,
                 createField, dirint, splitnl, nlines) where
import HbcUtils(breakAt)
import Edtypes

--export EditField,newline,nlines,splitnl,
data EditField = F EDirection String String String Int Int 
                 deriving (Eq, Ord)

--               bef     sel   aft     ^  lastlineno
--                            lno for selection edge

nlines s = length (filter (== newline) s)

splitnl = breakAt newline

dirint ERight = 1
dirint ELeft = -1

befaft dir bef sel aft =
    if dir == ELeft then (bef, sel ++ aft) else (sel ++ bef, aft)

createField s = F ERight [] [] s 0 (nlines s)
getLnoEdge (F dir bef sel aft elno lno) =
    (elno, befaft dir bef sel aft)
getBef (F dir bef sel aft elno lno) = bef
getAft (F dir bef sel aft elno lno) = aft
getLastLineNo (F dir bef sel aft elno lno) = lno
getSelection (F dir bef sel aft elno lno) =
    if dir == ELeft then sel else reverse sel

deselectField (F dir bef sel aft elno lno) =
    let (bef', aft') = befaft dir bef sel aft
    in  F dir bef' [] aft' elno lno

getField f = reverse (getBef f) ++ getSelection f ++ getAft f
getField' f = (reverse (getBef f),getSelection f,getAft f)

setFieldDir ndir field@(F dir bef sel aft elno lno) =
    if ndir == dir then
        field
    else
        let elno' = elno + dirint ndir * nlines sel
        in  F ndir bef (reverse sel) aft elno' lno

replaceField (F dir bef sel aft elno lno) s =
    let linessel = nlines sel
        liness = nlines s
        elno' = elno + liness - (if dir == ERight then linessel else 0)
        lno' = lno + (liness - linessel)
    in  F ERight (reverse s ++ bef) [] aft elno' lno'

moveField :: IsSelect -> EditField -> EditStopFn -> (EditField,String)
moveField issel (F dir bef sel aft elno lno) sf =
    let mo dir' bef' sel' aft' elno' acc sf =
            let stop = (F dir' bef' sel' aft' elno' lno, acc)
                (b, a) = befaft dir' bef' sel' aft'
            in case sf b a of 
		 EdStop -> stop
		 EdGo wdir sf' -> 
		    let next c dir'' bef'' sel'' aft'' =
			    let elno'' =
				    if c == newline then
					dirint wdir + elno'
				    else
					elno'
			    in  mo dir'' bef'' sel'' aft'' elno'' (c:acc) sf'
		    in  if wdir == dir' || null sel' then
			    case wdir of
			      ELeft -> case bef' of
					 [] -> stop
					 c:bef'' -> next c wdir bef'' (c:sel') aft'
			      ERight -> case aft' of
					  [] -> stop
					  c:aft'' -> next c wdir bef' (c:sel') aft''
			else
			    let c:sel'' = sel'
			    in  case dir' of
				  ELeft -> next c dir' (c:bef') sel'' aft'
				  ERight -> next c dir' bef' sel'' (c:aft')
        (field, acc) = mo dir bef sel aft elno [] sf
    in  if issel then (field, acc) else (deselectField field, [])