implementation module EdTab /* * functions that deal with those annoying tab characters o Unfortunately doesn't work with proportional fonts... Probably inevitable with an 'editor' view of tabs. */ import StdArray, StdBool, StdClass, StdEnum, StdList import StdIOCommon, StdPicture, StdPSt import EdMonad, syncol splitAtTabs :: !String -> .[String] splitAtTabs string = splitAtTabs` 0 0 where maxIndex = size string - 1 splitAtTabs` startIndex currentIndex | currentIndex > maxIndex // has the end been reached? = [ string % (startIndex, maxIndex) ] # newIndex = currentIndex + 1 | string.[currentIndex] == '\t' // is the current character a tab character? = [ string % (startIndex, currentIndex - 1) : splitAtTabs` newIndex newIndex ] // no, it's a normal character = splitAtTabs` startIndex newIndex tabTake :: !Int [String] -> [String] tabTake 0 _ = [""] tabTake _ [] = [] tabTake n [string:strings] | n <= len = [ string % (0, n - 1) ] = [ string : tabTake (n - len - 1) strings ] where len = size string alignAtTab` x tabSize charWidth | tabSize <= 0 = x + charWidth // sensible result for silly value = tabWidth * (inc (x / tabWidth)) where tabWidth = tabSize * charWidth tabDrawString :: !Point2 !String !FontInfo !*Picture -> *Picture tabDrawString point string {thefont, showTabs,tabSize,charWidth} picture #! strings = splitAtTabs string = tabDrawString` point strings picture where tabDrawString` :: !Point2 [String] !*Picture -> *Picture tabDrawString` _ [] picture = picture tabDrawString` point [ string : [] ] picture # picture = setPenPos point picture # picture = draw string picture = picture tabDrawString` point [ string : strings ] picture # picture = setPenPos point picture # picture = draw string picture (newPoint,picture) = getPenPos picture newX = alignAtTab` newPoint.x tabSize charWidth | not showTabs = tabDrawString` { point & x = newX } strings picture # picture = setPenColour Red picture picture = draw '~' picture picture = setPenColour Black picture = tabDrawString` { point & x = newX } strings picture :: CommentLevel = N Int // normal comment nesting level | L // comment till end of line... | S // in string constant... | C // in char constant... | T Int // in typedef | D Int // in typedecl import ospicture // for optimized drawfuns... optDrawS :== pictdrawstring // use non-optimised versions optDrawC :== pictdrawchar // " tabDrawStringC :: !Point2 !(!Info,!String) !FontInfo !*Picture -> *Picture tabDrawStringC point ({comment_level=clevel,is_typedef=typedef,is_typedecl=typedecl},string) {tabSize,charWidth,thefont, showTabs, syntaxColours={textColour, backgroundColour,tabColour, commentColour, stringColour, charColour, keywordColour, typedefColour, typedeclColour}} picture #! strings = splitAtTabs string | typedef = tabDrawString` /*True*/ (T clevel) point strings picture | typedecl = tabDrawString` (D clevel) point strings picture = tabDrawString` /*True*/ (N clevel) point strings picture where tabDrawString` :: /*!Bool*/ !CommentLevel !Point2 !.[String] !*Picture -> *Picture // hmm, need to get if column 0 into local funs... tabDrawString` /*_*/ _ _ [] picture // #! (_,picture) = optGetPenPos picture = picture tabDrawString` /*ini*/ clevel point [string : []] picture // #! (_,picture) = optGetPenPos picture #! picture = setPenPos point picture #! (_,picture) = drawC /*ini*/ clevel string picture // #! (_,picture) = optGetPenPos picture = picture tabDrawString` /*ini*/ clevel point [string : strings] picture // #! (_,picture) = optGetPenPos picture #! picture = setPenPos point picture #! (clevel,picture) = drawC /*ini*/ clevel string picture // #! (newPoint,picture) = optGetPenPos picture #! (newPoint,picture) = getPenPos picture #! newX = alignAtTab` newPoint.x tabSize charWidth | not showTabs = tabDrawString` /*False*/ clevel {point & x = newX} strings picture #! picture = setPenColour tabColour picture #! picture = optDrawC '~' picture #! picture = setPenColour textColour picture = tabDrawString` /*False*/ clevel {point & x = newX} strings picture drawC :: /*!Bool*/ !CommentLevel !.String !*Picture -> (!CommentLevel,!*Picture) drawC /*ini*/ c s pic = drawC c pic where drawC :: !CommentLevel !*Picture -> (!CommentLevel,!*Picture) drawC S pic // string literal # pic = setPenColour stringColour pic = dS 0 pic drawC C pic // char literal # pic = setPenColour charColour pic = dC 0 pic drawC L pic // line comment # pic = setPenColour commentColour pic # pic = optDrawS s pic = (L,pic) drawC (N cl) pic // normal # pic = (if (cl==0) (setPenColour textColour) (setPenColour commentColour)) pic = dL /*ini*/ (N cl) 0 pic drawC (T cl) pic # pic = (if (cl==0) (setPenColour typedefColour) (setPenColour commentColour)) pic = dL /*ini*/ (T cl) 0 pic drawC (D cl) pic # pic = (if (cl==0) (setPenColour typedeclColour) (setPenColour commentColour)) pic = dL (D cl) 0 pic l = size s funnyChar i = isStringMember s.[i] (dec funnySize) funnyChars isStringMember :: !Char !Int !{#Char} -> Bool isStringMember x i s | i < 0 = False | s.[i] == x = True = isStringMember x (dec i) s funnyChars = "~@#$%^?!+-*<>\\/|&=:." funnySize = 20 dL :: /*!Bool*/ !CommentLevel !.Int !*Picture -> (!CommentLevel,!*Picture) dL /*ini*/ cl i pic | i >= l = (cl,pic) /* | ini && s.[i] == ':' && not (in_comment cl) # i` = inc i | i` >= l # (cl,pic) = normalise ini i cl pic # pic = optDrawC ':' pic = (N 0,pic) | s.[i`] == ':' # i`` = inc i` | i`` < l && funnyChar i`` # j = scanfunny i # r = s%(i,dec j) # pic = optDrawS r pic = dL False (N 0) j pic # pic = setPenColour typedefColour pic # pic = optDrawS "::" pic = dL False (T 0) i`` pic | s.[i`] == '=' # i`` = inc i` | i`` < l && funnyChar i`` # j = scanfunny i # r = s%(i,dec j) # (cl,pic) = case r of ":==" -> (cl,pic) _ -> normalise ini i cl pic # pic = optDrawS r pic = dL False cl j pic # (cl,pic) = normalise ini i cl pic # pic = optDrawS ":=" pic = dL False (N 0) i`` pic # (cl,pic) = normalise ini i cl pic # pic = optDrawC ':' pic = dL False (N 0) i` pic */ | s.[i] == '*' # i` = inc i | i` >= l // # (cl,pic) = normalise ini i cl pic # pic = optDrawC '*' pic = (cl,pic) | s.[i`] == '/' # i`` = inc i` | in_comment cl //cl <> 0 # pic = setPenColour commentColour pic // idiot proof for trickery at start of text... # pic = optDrawS "*/" pic # cl = dec_comment cl | not (in_comment cl) //cl == 0 # pic = setPenColour (non_comment_colour cl)/*textColour*/ pic = dL /*False*/ cl i`` pic = dL /*False*/ cl i`` pic | i`` < l && funnyChar i`` // eat till end of funnyid substring... # j = scanfunny i`` # r = s%(i``,dec j) // # (cl,pic) = normalise ini i cl pic # pic = optDrawS "*/" pic # pic = optDrawS r pic = dL /*False*/ cl j pic # pic = setPenColour commentColour pic // idiot proof for trickery at start of text... # pic = optDrawS "*/" pic # cl = dec_comment cl | not (in_comment cl) //cl == 0 # pic = setPenColour (non_comment_colour cl)/*textColour*/ pic = dL /*False*/ cl i`` pic = dL /*False*/ cl i`` pic // # (cl,pic) = normalise ini i cl pic # pic = optDrawC '*' pic = dL /*False*/ cl i` pic | s.[i] == '/' # i` = inc i | i` >= l // # (cl,pic) = normalise ini i cl pic # pic = optDrawC '/' pic = (cl,pic) | s.[i`] == '/' # pic = setPenColour commentColour pic # pic = optDrawS "//" pic # r = s%(inc i`,l) # pic = optDrawS r pic = (L,pic) | s.[i`] == '*' # pic = setPenColour commentColour pic # pic = optDrawS "/*" pic # cl = inc_comment cl | in_comment cl = dL cl (inc i`) pic # pic = setPenColour (non_comment_colour cl) pic = dL /*False*/ cl (inc i`) pic // # (cl,pic) = normalise ini i cl pic # pic = optDrawC '/' pic = dL /*False*/ cl i` pic | (s.[i] == '"') && (not (in_comment cl)) //(cl == 0) # pic = setPenColour stringColour pic # pic = optDrawC '"' pic = dS (inc i) pic | (s.[i] == '\'') && (not (in_comment cl)) //(cl == 0) # pic = setPenColour charColour pic # pic = optDrawC '\'' pic = dC (inc i) pic | /*(cl == 0)*/ (not (in_comment cl)) && (funnyChar i) # j = scanfunny i # r = s%(i,dec j) /* # (cl,pic) = case r of "|" -> (cl,pic) "=" -> (cl,pic) _ -> normalise ini i cl pic */ # pic = optDrawS r pic = dL /*False*/ cl j pic /* # (cl,pic) = case WhiteSpace s.[i] of True -> (cl,pic) _ -> normalise ini i cl pic */ # (key,j) = scankeyword s i | key && (not (in_comment cl)) //cl == 0 # r = s%(i,dec j) # (c,pic) = getPenColour pic # pic = setPenColour keywordColour pic # pic = optDrawS r pic # pic = setPenColour c pic = dL /*False*/ cl j pic # r = s%(i,dec j) # pic = optDrawS r pic = dL /*False*/ cl j pic where /* normalise True 0 (T 0) pic # pic = setPenColour textColour pic = (N 0,pic) normalise _ _ cl pic = (cl,pic) in_typedef cl = case cl of T l -> l == 0 _ -> False */ in_comment cl = case cl of N l -> l <> 0 T l -> l <> 0 D l -> l <> 0 _ -> False dec_comment cl = case cl of N l -> N (dec l) T l -> T (dec l) D l -> D (dec l) inc_comment cl = case cl of N l -> N (inc l) T l -> T (inc l) D l -> D (inc l) non_comment_colour cl = case cl of N _ -> textColour T _ -> typedefColour D _ -> typedeclColour scankeyword :: !.String !Int -> (!Bool,!Int) scankeyword s i # c = s.[i] | not (isAlpha c || (c == '_')) # j = inc i = (False,j) # j = scanalpha (inc i) | c == 'f' // from | (j == i+4) && (s%(i,i+3)=="from") = (True,j) = (False,j) | c == 'g' // generic | (j == i+7) && (s%(i,i+6)=="generic") = (True,j) = (False,j) | c == 'd' // definition, derive, dynamic | j == i+10 = (s % (i,i+9)=="definition",j) | j == i+6 = (s % (i,i+5)=="derive",j) | j == i+7 = (s % (i,i+6)=="dynamic",j) = (False,j) | c == 'i' // implementation, import, if, in, infix, infixl, infixr, instance | (j == i+14) && (s%(i,i+13)=="implementation") = (True,j) | (j == i+8) && (s%(i,i+7)=="instance") = (True,j) // only in typedef! | (j == i+6) && (s%(i,i+5)=="import") = (True,j) | (j == i+6) && (s%(i,i+5)=="infixl") = (True,j) | (j == i+6) && (s%(i,i+5)=="infixr") = (True,j) | (j == i+5) && (s%(i,i+4)=="infix") = (True,j) | (j == i+2) && (s%(i,i+1)=="if") = (True,j) | (j == i+2) && (s%(i,i+1)=="in") = (True,j) = (False,j) | c == 'e' // export | (j == i+6) && (s%(i,i+5)=="export") = (True,j) = (False,j) | c == 'm' // module | (j == i+6) && (s%(i,i+5)=="module") = (True,j) = (False,j) | c == 's' // system | (j == i+6) && (s%(i,i+5)=="system") = (True,j) = (False,j) | c == 'c' // case, code, class | (j == i+5) && (s%(i,i+4)=="class") = (True,j) | (j == i+4) | (s%(i,i+3)=="case") = (True,j) | (s%(i,i+3)=="code") = (True,j) = (False,j) = (False,j) | c == 'l' // let, let! | (j == i+4) && (s%(i,i+3)=="let!") = (True,j) // doesn't work! | (j == i+3) && (s%(i,i+2)=="let") = (True,j) = (False,j) | c == 'o' // of | (j == i+2) && (s%(i,i+1)=="of") = (True,j) = (False,j) | c == 'w' // where, with | (j == i+4) && (s%(i,i+3)=="with") = (True,j) | (j == i+5) && (s%(i,i+4)=="where") = (True,j) = (False,j) = (False,j) scanalpha i | i >= l = l # c = s.[i] | isAlphanum c = scanalpha (inc i) | c == '_' = scanalpha (inc i) | c == '`' = scanalpha (inc i) = i scanfunny i | i >= l = l | funnyChar i = scanfunny (inc i) = i dS :: !Int !*Picture -> (!CommentLevel,!*Picture) dS i pic | i >= l = (S,pic) | s.[i] == '"' # pic = optDrawC '"' pic # pic = setPenColour textColour pic = dL /*False*/ (N 0) (inc i) pic | s.[i] == '\\' # pic = optDrawC '\\' pic # i = inc i | i >= l = (S,pic) # pic = optDrawC s.[i] pic = dS (inc i) pic # pic = optDrawC s.[i] pic = dS (inc i) pic dC :: !Int !*Picture -> (!CommentLevel,!*Picture) dC i pic | i >= l = (C,pic) | s.[i] == '\'' # pic = optDrawC '\'' pic # pic = setPenColour textColour pic = dL /*False*/ (N 0) (inc i) pic | s.[i] == '\\' # pic = optDrawC '\\' pic # i = inc i | i >= l = (C,pic) # pic = optDrawC s.[i] pic = dC (inc i) pic # pic = optDrawC s.[i] pic = dC (inc i) pic WhiteSpace c :== c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f';