{- This module was generated from data in the Kate syntax highlighting file css.xml, version 2.01,
   by  Wilbert Berendsen (wilbert@kde.nl) -}

module Text.Highlighting.Kate.Syntax.Css ( highlight, parseExpression, syntaxName, syntaxExtensions ) where
import Text.Highlighting.Kate.Definitions
import Text.Highlighting.Kate.Common
import qualified Text.Highlighting.Kate.Syntax.Alert
import Text.ParserCombinators.Parsec
import Data.List (nub)
import Data.Map (fromList)
import Data.Maybe (fromMaybe)

-- | Full name of language.
syntaxName :: String
syntaxName = "CSS"

-- | Filename extensions for this language.
syntaxExtensions :: String
syntaxExtensions = "*.css"

-- | Highlight source code using this syntax definition.
highlight :: String -> Either String [SourceLine]
highlight input =
  case runParser parseSource startingState "source" input of
    Left err     -> Left $ show err
    Right result -> Right result

-- | Parse an expression using appropriate local context.
parseExpression :: GenParser Char SyntaxState LabeledSource
parseExpression = do
  st <- getState
  let oldLang = synStLanguage st
  setState $ st { synStLanguage = "CSS" }
  context <- currentContext <|> (pushContext "Base" >> currentContext)
  result <- parseRules context
  updateState $ \st -> st { synStLanguage = oldLang }
  return result

parseSource = do 
  lineContents <- lookAhead wholeLine
  updateState $ \st -> st { synStCurrentLine = lineContents }
  result <- manyTill parseSourceLine eof
  return $ map normalizeHighlighting result

startingState = SyntaxState {synStContexts = fromList [("CSS",["Base"])], synStLanguage = "CSS", synStCurrentLine = "", synStCharsParsedInLine = 0, synStCaseSensitive = True, synStKeywordCaseSensitive = False, synStCaptures = []}

parseSourceLine = manyTill parseExpressionInternal pEndLine

pEndLine = do
  newline <|> (eof >> return '\n')
  context <- currentContext
  case context of
    "Base" -> return ()
    "FindRuleSets" -> return ()
    "FindValues" -> return ()
    "FindStrings" -> return ()
    "FindComments" -> return ()
    "Media" -> return ()
    "Media2" -> return ()
    "SelAttr" -> return ()
    "SelPseudo" -> (popContext >> return ())
    "Import" -> return ()
    "Comment" -> return ()
    "RuleSet" -> return ()
    "Rule" -> return ()
    "Rule2" -> return ()
    "PropParen" -> return ()
    "PropParen2" -> return ()
    "StringDQ" -> return ()
    "StringSQ" -> return ()
    "InsideString" -> return ()
    _ -> return ()
  lineContents <- lookAhead wholeLine
  updateState $ \st -> st { synStCurrentLine = lineContents, synStCharsParsedInLine = 0 }

withAttribute attr txt = do
  if null txt
     then fail "Parser matched no text"
     else return ()
  let style = fromMaybe "" $ lookup attr styles
  st <- getState
  let oldCharsParsed = synStCharsParsedInLine st
  updateState $ \st -> st { synStCharsParsedInLine = oldCharsParsed + length txt } 
  return (nub [style, attr], txt)

styles = [("Normal Text","Normal"),("Property","Keyword"),("Unknown Property","Keyword"),("Media","DecVal"),("At Rule","DecVal"),("String","String"),("Value","DataType"),("Important","Keyword"),("Selector Attr","Char"),("Selector Id","Float"),("Selector Class","Float"),("Selector Pseudo","DecVal"),("Comment","Comment"),("Region Marker","RegionMarker"),("Alert","Alert"),("Error","Error")]

parseExpressionInternal = do
  context <- currentContext
  parseRules context <|> (pDefault >>= withAttribute (fromMaybe "" $ lookup context defaultAttributes))

defaultAttributes = [("Base","Normal Text"),("FindRuleSets","Normal Text"),("FindValues","Normal Text"),("FindStrings","Normal Text"),("FindComments","Normal Text"),("Media","Normal Text"),("Media2","Normal Text"),("SelAttr","Selector Attr"),("SelPseudo","Selector Pseudo"),("Import","Normal Text"),("Comment","Comment"),("RuleSet","Normal Text"),("Rule","Normal Text"),("Rule2","Normal Text"),("PropParen","Normal Text"),("PropParen2","Normal Text"),("StringDQ","String"),("StringSQ","String"),("InsideString","String")]

parseRules "Base" = 
  do (attr, result) <- (((pLineContinue >>= withAttribute "Normal Text"))
                        <|>
                        ((pDetectSpaces >>= withAttribute "Normal Text"))
                        <|>
                        ((parseRules "FindRuleSets")))
     return (attr, result)

parseRules "FindRuleSets" = 
  do (attr, result) <- (((pRegExpr (compileRegex "@media\\b") >>= withAttribute "Media") >>~ pushContext "Media")
                        <|>
                        ((pRegExpr (compileRegex "@import\\b") >>= withAttribute "At Rule") >>~ pushContext "Import")
                        <|>
                        ((pRegExpr (compileRegex "@(font-face|charset)\\b") >>= withAttribute "At Rule"))
                        <|>
                        ((pDetectChar False '{' >>= withAttribute "Property") >>~ pushContext "RuleSet")
                        <|>
                        ((pDetectChar False '[' >>= withAttribute "Selector Attr") >>~ pushContext "SelAttr")
                        <|>
                        ((pRegExpr (compileRegex "#([a-zA-Z0-9\\-_]|[\\x80-\\xFF]|\\\\[0-9A-Fa-f]{1,6})*") >>= withAttribute "Selector Id"))
                        <|>
                        ((pRegExpr (compileRegex "\\.([a-zA-Z0-9\\-_]|[\\x80-\\xFF]|\\\\[0-9A-Fa-f]{1,6})*") >>= withAttribute "Selector Class"))
                        <|>
                        ((pRegExpr (compileRegex ":lang\\([\\w_-]+\\)") >>= withAttribute "Selector Pseudo"))
                        <|>
                        ((pDetectChar False ':' >>= withAttribute "Selector Pseudo") >>~ pushContext "SelPseudo")
                        <|>
                        ((parseRules "FindStrings"))
                        <|>
                        ((parseRules "FindComments")))
     return (attr, result)

parseRules "FindValues" = 
  do (attr, result) <- (((pRegExpr (compileRegex "[-+]?[0-9.]+(em|ex|px|in|cm|mm|pt|pc|deg|rad|grad|ms|s|Hz|kHz)\\b") >>= withAttribute "Value"))
                        <|>
                        ((pRegExpr (compileRegex "[-+]?[0-9.]+[%]?") >>= withAttribute "Value"))
                        <|>
                        ((pRegExpr (compileRegex "[\\w\\-]+") >>= withAttribute "Normal Text")))
     return (attr, result)

parseRules "FindStrings" = 
  do (attr, result) <- (((pDetectChar False '"' >>= withAttribute "String") >>~ pushContext "StringDQ")
                        <|>
                        ((pDetectChar False '\'' >>= withAttribute "String") >>~ pushContext "StringSQ"))
     return (attr, result)

parseRules "FindComments" = 
  do (attr, result) <- (((pRegExpr (compileRegex "/\\*BEGIN.*\\*/") >>= withAttribute "Region Marker"))
                        <|>
                        ((pRegExpr (compileRegex "/\\*END.*\\*/") >>= withAttribute "Region Marker"))
                        <|>
                        ((pDetect2Chars False '/' '*' >>= withAttribute "Comment") >>~ pushContext "Comment"))
     return (attr, result)

parseRules "Media" = 
  do (attr, result) <- (((pDetectChar False '{' >>= withAttribute "Media") >>~ pushContext "Media2")
                        <|>
                        ((pKeyword " \n\t.():!+,<=>&*/;?[]^{|}~\\" ["all","aural","braille","embossed","handheld","print","projection","screen","tty","tv"] >>= withAttribute "Media"))
                        <|>
                        ((pDetectChar False ',' >>= withAttribute "Media"))
                        <|>
                        ((parseRules "FindComments"))
                        <|>
                        ((pRegExpr (compileRegex "\\S+") >>= withAttribute "Error")))
     return (attr, result)

parseRules "Media2" = 
  do (attr, result) <- (((pDetectChar False '}' >>= withAttribute "Media") >>~ (popContext >> popContext >> return ()))
                        <|>
                        ((parseRules "FindRuleSets")))
     return (attr, result)

parseRules "SelAttr" = 
  do (attr, result) <- (((pDetectChar False ']' >>= withAttribute "Selector Attr") >>~ (popContext >> return ()))
                        <|>
                        ((parseRules "FindStrings")))
     return (attr, result)

parseRules "SelPseudo" = 
  do (attr, result) <- (((pKeyword " \n\t.():!+,<=>&*/;?[]^{|}~\\" ["hover","link","visited","active","focus","first-child","last-child","only-child","first-of-type","last-of-type","only-of-type","first-letter","first-line","before","after","selection","root","empty","target","enabled","disabled","checked","indeterminate","nth-child","nth-last-child","nth-of-type","nth-last-of-type","not"] >>= withAttribute "Selector Pseudo") >>~ (popContext >> return ()))
                        <|>
                        ((popContext >> return ()) >> return ([], "")))
     return (attr, result)

parseRules "Import" = 
  do (attr, result) <- (((pDetectChar False ';' >>= withAttribute "At Rule") >>~ (popContext >> return ()))
                        <|>
                        ((pKeyword " \n\t.():!+,<=>&*/;?[]^{|}~\\" ["all","aural","braille","embossed","handheld","print","projection","screen","tty","tv"] >>= withAttribute "Media"))
                        <|>
                        ((parseRules "FindValues"))
                        <|>
                        ((parseRules "FindStrings"))
                        <|>
                        ((parseRules "FindComments")))
     return (attr, result)

parseRules "Comment" = 
  do (attr, result) <- (((pDetectSpaces >>= withAttribute "Comment"))
                        <|>
                        ((pDetect2Chars False '*' '/' >>= withAttribute "Comment") >>~ (popContext >> return ()))
                        <|>
                        ((Text.Highlighting.Kate.Syntax.Alert.parseExpression >>= ((withAttribute "") . snd)))
                        <|>
                        ((pDetectIdentifier >>= withAttribute "Comment")))
     return (attr, result)

parseRules "RuleSet" = 
  do (attr, result) <- (((pDetectChar False '}' >>= withAttribute "Property") >>~ (popContext >> return ()))
                        <|>
                        ((pKeyword " \n\t.():!+,<=>&*/;?[]^{|}~\\" ["azimuth","background","background-attachment","background-color","background-image","background-position","background-repeat","border","border-bottom","border-bottom-color","border-bottom-style","border-bottom-width","border-collapse","border-color","border-left","border-left-color","border-left-style","border-left-width","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-style","border-top-width","border-width","bottom","caption-side","clear","clip","color","content","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","elevation","empty-cells","float","font","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","height","left","letter-spacing","line-height","list-style","list-style-image","list-style-keyword","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","max-height","max-width","min-height","min-width","orphans","outline","outline-color","outline-style","outline-width","overflow","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","pitch","pitch-range","play-during","position","quotes","richness","right","size","speak","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","table-layout","text-align","text-decoration","text-decoration-color","text-indent","text-shadow","text-transform","top","unicode-bidi","vertical-align","visibility","voice-family","volume","white-space","widows","width","word-spacing","z-index","border-radius","box-sizing","opacity","text-shadow","-moz-border-radius","-moz-box-flex","konq_bgpos_x","konq_bgpos_y","font-family","font-size","font-stretch","font-style","font-variant","font-weight","unicode-range","units-per-em","src","panose-1","stemv","stemh","slope","cap-height","x-height","ascent","descent","widths","bbox","definition-src","baseline","centerline","mathline","topline"] >>= withAttribute "Property") >>~ pushContext "Rule")
                        <|>
                        ((pRegExpr (compileRegex "-?[A-Za-z_-]+(?=\\s*:)") >>= withAttribute "Unknown Property") >>~ pushContext "Rule")
                        <|>
                        ((parseRules "FindComments"))
                        <|>
                        ((pRegExpr (compileRegex "\\S") >>= withAttribute "Error")))
     return (attr, result)

parseRules "Rule" = 
  do (attr, result) <- (((pDetectChar False ':' >>= withAttribute "Property") >>~ pushContext "Rule2")
                        <|>
                        ((pRegExpr (compileRegex "\\S") >>= withAttribute "Error")))
     return (attr, result)

parseRules "Rule2" = 
  do (attr, result) <- (((pDetectChar False ';' >>= withAttribute "Property") >>~ (popContext >> popContext >> return ()))
                        <|>
                        ((pDetectChar False '}' >>= withAttribute "Property") >>~ (popContext >> popContext >> popContext >> return ()))
                        <|>
                        ((pKeyword " \n\t.():!+,<=>&*/;?[]^{|}~\\" ["inherit","none","hidden","dotted","dashed","solid","double","groove","ridge","inset","outset","xx-small","x-small","small","medium","large","x-large","xx-large","smaller","larger","italic","oblique","small-caps","normal","bold","bolder","lighter","light","100","200","300","400","500","600","700","800","900","transparent","repeat","repeat-x","repeat-y","no-repeat","baseline","sub","super","top","text-top","middle","bottom","text-bottom","left","right","center","justify","konq-center","disc","circle","square","box","decimal","decimal-leading-zero","lower-roman","upper-roman","lower-greek","lower-alpha","lower-latin","upper-alpha","upper-latin","hebrew","armenian","georgian","cjk-ideographic","hiragana","katakana","hiragana-iroha","katakana-iroha","inline","inline-block","block","list-item","run-in","compact","marker","table","inline-table","table-row-group","table-header-group","table-footer-group","table-row","table-column-group","table-column","table-cell","table-caption","auto","crosshair","default","pointer","move","e-resize","ne-resize","nw-resize","n-resize","se-resize","sw-resize","s-resize","w-resize","text","wait","help","above","absolute","always","avoid","below","bidi-override","blink","both","capitalize","caption","close-quote","collapse","condensed","crop","cross","embed","expanded","extra-condensed","extra-expanded","fixed","hand","hide","higher","icon","inside","invert","landscape","level","line-through","loud","lower","lowercase","ltr","menu","message-box","mix","narrower","no-close-quote","no-open-quote","nowrap","open-quote","outside","overline","portrait","pre","pre-line","pre-wrap","relative","rtl","scroll","semi-condensed","semi-expanded","separate","show","small-caption","static","static-position","status-bar","thick","thin","ultra-condensed","ultra-expanded","underline","uppercase","visible","wider","break","serif","sans-serif","cursive","fantasy","monospace","border-box","content-box","-moz-box"] >>= withAttribute "Value"))
                        <|>
                        ((pKeyword " \n\t.():!+,<=>&*/;?[]^{|}~\\" ["aqua","black","blue","fuchsia","gray","green","lime","maroon","navy","olive","purple","red","silver","teal","white","yellow","ActiveBorder","ActiveCaption","AppWorkspace","Background","ButtonFace","ButtonHighlight","ButtonShadow","ButtonText","CaptionText","GrayText","Highlight","HighlightText","InactiveBorder","InactiveCaption","InactiveCaptionText","InfoBackground","InfoText","Menu","MenuText","Scrollbar","ThreeDDarkShadow","ThreeDFace","ThreeDHighlight","ThreeDLightShadow","ThreeDShadow","Window","WindowFrame","WindowText"] >>= withAttribute "Value"))
                        <|>
                        ((pRegExpr (compileRegex "#([0-9A-Fa-f]{3}){1,4}\\b") >>= withAttribute "Value"))
                        <|>
                        ((pKeyword " \n\t.():!+,<=>&*/;?[]^{|}~\\" ["url","attr","rect","rgb","counter","counters","local","format","expression"] >>= withAttribute "Value") >>~ pushContext "PropParen")
                        <|>
                        ((pRegExpr (compileRegex "!important\\b") >>= withAttribute "Important"))
                        <|>
                        ((parseRules "FindValues"))
                        <|>
                        ((parseRules "FindStrings"))
                        <|>
                        ((parseRules "FindComments")))
     return (attr, result)

parseRules "PropParen" = 
  do (attr, result) <- (((pDetectChar False '(' >>= withAttribute "Value") >>~ pushContext "PropParen2")
                        <|>
                        ((parseRules "FindComments"))
                        <|>
                        ((pRegExpr (compileRegex "\\S") >>= withAttribute "Error")))
     return (attr, result)

parseRules "PropParen2" = 
  do (attr, result) <- (((pDetectChar False ')' >>= withAttribute "Value") >>~ (popContext >> popContext >> return ()))
                        <|>
                        ((parseRules "FindValues"))
                        <|>
                        ((parseRules "FindStrings"))
                        <|>
                        ((parseRules "FindComments")))
     return (attr, result)

parseRules "StringDQ" = 
  do (attr, result) <- (((pDetectChar False '"' >>= withAttribute "String") >>~ (popContext >> return ()))
                        <|>
                        ((parseRules "InsideString")))
     return (attr, result)

parseRules "StringSQ" = 
  do (attr, result) <- (((pDetectChar False '\'' >>= withAttribute "String") >>~ (popContext >> return ()))
                        <|>
                        ((parseRules "InsideString")))
     return (attr, result)

parseRules "InsideString" = 
  do (attr, result) <- (((pRegExpr (compileRegex "\\\\[\"']") >>= withAttribute "String"))
                        <|>
                        ((pDetectIdentifier >>= withAttribute "String")))
     return (attr, result)

parseRules x = fail $ "Unknown context" ++ x