module DrawLex where import Monad(join) import List(groupBy) import Maybe(mapMaybe,fromMaybe) import Fudgets import FudDraw(ulineD') import GIFAltFile import OpTypes(eqBy) import PfePlumbing(Label(..),lblPos,Icons,CertsStatus,addRefPos,refPos,assertionDefLbl) import TokenTags as C import HsLexerPass1(nextPos1,Pos(..)) import HsTokens as T import HLexTagModuleNames import RefsTypes(merge{-,T(..)-}) import PFE_Certs(CertName,certAttrsPath) import CertServers(parseAttrs) import HsName(ModuleName(..)) import TypedIds(NameSpace(..)) -- only the position is significant when locating a Label in a drawing rootLabel = posLabel rootPos where rootPos = Pos (-1) (-1) (-1) -- not a valid file position posLabel p = Lbl ((TheRest,(p,"")),Nothing) origLabel orig = Lbl ((TheRest,(refPos orig,"")),Just orig) fakeLex = labelD rootLabel . vboxlD' 0 . map g . map (expand 1) . take 2500 . lines drawLex dir icons m colorGctx rs cs na = if quickfix then labelD rootLabel . vboxlD' 0 . map g . lines . concatMap (snd.snd) else labelD rootLabel . vboxlD' 0 . map (hboxD' 0 . map tokenD . autoAnnot {-. groupSpace-}) . take 2500 . -- Show at most 2500 lines !! groupBy sameLine . concatMap split . merge (map addRefPos rs) . convModuleNames where -- split tokens that span several lines: split ((t,(Pos n y x,s)),r) = [Lbl ((t,(Pos n y' x,l)),r)|(y',l)<-zip [y..] (lines (expand x s))] sameLine = eqBy (line.lblPos) tokenD lbl@(Lbl((t,(p,s)),r)) = markD . labelD lbl . colorD t . g $ s where markD = case r of Just (_,_,defs) | length defs/=1 -> ulineD' "red" _ -> id colorD t = case t of NestedComment -> case isCertAnnot s of Just cert -> const (drawCertIcon dir icons m cs cert) _ -> fgD C.Comment Commentstart -> fgD C.Comment T.Comment -> fgD C.Comment LiterateComment -> fgD C.Comment Reservedid -> fgD Reserved Reservedop -> fgD Reserved Special -> fgD Reserved Specialid -> fgD Reserved Conid -> con r Qconid -> con r Varsym -> fgD VarOp Qvarsym -> fgD VarOp Consym -> fgD ConOp Qconsym -> fgD ConOp IntLit -> fgD Lit FloatLit -> fgD Lit StringLit -> fgD Lit CharLit -> fgD Lit _ -> id fgD = hardAttribD . colorGctx con = maybe id (fgD . rcolor) rcolor ((_,sp),_,_) = if sp==ValueNames then Con else TCon autoAnnot ts = ts++autoannots where autoannots = map (nestedComment dummyPos.certAnnot) certs certs = concatMap (fromMaybe [] . flip lookup na) as as = mapMaybe assertionDefLbl ts dummyPos = lblPos (last ts) certAnnot cert = "{-#cert:"++cert++"#-}" nestedComment p s = Lbl ((NestedComment,(p,s)),Nothing) {- groupSpace [] = [] groupSpace (lbl@(Lbl((t,(p,s)),r)):ts) = if isWhite lbl then case span isWhite ts of (ws,ts') -> Lbl((t,(p,s++concatMap str ws)),r):groupSpace ts' else lbl:groupSpace ts where str (Lbl((_,(_,s)),_)) = s isWhite (Lbl((Whitespace,(p,s)),r)) = all isSpace s isWhite _ = False -} drawCertIcon :: FilePath -> Icons -> ModuleName -> CertsStatus -> CertName -> Drawing lbl Gfx drawCertIcon dir (sad,icons) m cstatus cert = g (fileGfxAlt certIcon (certAttrsPath m cert dir) sad) where certIcon s = case (`lookup` icons) =<< lookup "type" (parseAttrs s) of Just cicons -> Right (cstatusIcon cicons (join (lookup cert cstatus))) _ -> Left "bad cert/unknown cert type" certIcon (sad,icons) (cert,(Just attrs,cstatus)) = case (`lookup` icons) =<< lookup "type" attrs of Just icons -> cstatusIcon icons cstatus _ -> sad certIcon (sad,_) _ = sad cstatusIcon (valid,invalid,unknown) cstatus = case cstatus of Just (isvalid,_) -> if isvalid then valid else invalid _ -> unknown -- isCertAnnot :: Monad m => String -> m CertName isCertAnnot s = do '{':'-':'#':'c':'e':'r':'t':':':r <- return s '}':'-':'#':f <- return (reverse r) return (reverse f) {- Why use "case" when you can use "do"? :-) isCertAnnot s = case s of '{':'-':'#':'c':'e':'r':'t':':':r -> case reverse r of '}':'-':'#':f -> Just (reverse f) _ -> Nothing _ -> Nothing -} expand x "" = "" expand x (c:s) = case c of '\t' -> replicate (x'-x) ' '++expand x' s _ -> c:expand x' s where Pos _ _ x' = nextPos1 (Pos 0 1 x) c quickfix = argFlag "quickfix" False