CompletionStringF

module CompletionStringF
    (stdcc,completeFromList,
     completionStringF,completionStringF',completionStringF'')
  where
import Fudgets
import Data.List(isPrefixOf) 
import HbcUtils(mapSnd)

completionStringF = completionStringF' stdcc standard

stdcc = argReadKey "stdcc" ' ' -- standard completion char

completionStringF' cc cust = completionStringF'' cc cust >=^< mapEither id Right

completionStringF'' cc cust =  -- cc = completion character
    loopThroughRightF (absF completeSP0) (stringF'' cust)
  where
    completeSP0 = completeSP (const []) ([],[]) ""

    completeSP listfun updownlist current =
        getSP $ either fromStringF fromOutside
      where
        list = listfun current

        same = completeSP listfun updownlist current
	newList listfun' = completeSP listfun' ([],[]) current
	newString' p s = putSP (toOutput (InputChange s)) $
			 completeSP listfun p s
	newString = newString' ([],[])


        toStringF'' = Left
        toString = toStringF'' . Right
	toCustomiser = toStringF'' . Left
	toOutput = Right . Right
	toCompletionList = Right . Left

	fromOutside = either newList inputToStringF''
	inputToStringF'' msg = putSP (toStringF'' msg) same

        fromStringF msg = 
	  case msg of
	    InputDone "Up"   _ -> goto above
	    InputDone "Down" _ -> goto below
	    InputDone "Tab"  _ -> doCompletion
	    InputDone _ _ -> putSP (toOutput msg) same
	    InputChange s ->
	      if s==current++[cc]
	      then doCompletion
	      else if fromupdownlist s
	           then same
		   else newString s -- erase completion list?

        fromupdownlist s =
 	    case updownlist of
	      (_,(_,s'):_) -> s==s'
	      _ -> False

        goto (_,[]) = same
        goto l@(_,item@(_,s):_) =
	    putSP (toString s) $
	    putSP (toCompletionList [item]) $
	    putSP (toOutput (InputChange s)) $
	    newString' l current

	above = case updownlist of
		  ([],[]) -> case reverse updownlist' of
			       x:xs -> (xs,[x])
			       _ -> ([],[])
		  (x:xs,ys) -> (xs,x:ys)
		  _ -> updownlist

        below = case updownlist of
		  ([],[]) -> ([],updownlist')
		  (xs,x1:x2:ys) -> (x1:xs,x2:ys)
		  _ -> updownlist

        updownlist' = mapSnd (current++) list

        doCompletion =
	    putSP (toCompletionList list) $
	    putNewString (current++commonPrefix (map snd list))

        putNewString new =
	  putSP (toString new) $
	  putSP (toCustomiser (setCursorPos (length new))) $
	  newString new

commonPrefix ((c:s):ss) =
  case filter ((/=[c]).take 1) ss of
    [] -> c:commonPrefix (s:map tail ss)
    _ -> []
commonPrefix _ = []

pos y xs =
  case [ix|ix@(i,x)<-number 0 xs,y `isPrefixOf` x] of
    []      -> (0,False)
    (i,x):_ -> (i,x==y)

completeFromList list current =
    [(current,compl)|(pre,compl)<-splits,pre==current]
  where
    splits = map (splitAt n) list
    n = length current