module Text.Highlighting.Kate.Syntax.Python ( highlight, parseExpression, syntaxName, syntaxExtensions ) where
import Text.Highlighting.Kate.Definitions
import Text.Highlighting.Kate.Common
import Text.ParserCombinators.Parsec
import Data.List (nub)
import Data.Map (fromList)
import Data.Maybe (fromMaybe)
syntaxName :: String
syntaxName = "Python"
syntaxExtensions :: String
syntaxExtensions = "*.py;*.pyw"
highlight :: String -> Either String [SourceLine]
highlight input =
case runParser parseSource startingState "source" input of
Left err -> Left $ show err
Right result -> Right result
parseExpression :: GenParser Char SyntaxState LabeledSource
parseExpression = do
st <- getState
let oldLang = synStLanguage st
setState $ st { synStLanguage = "Python" }
context <- currentContext <|> (pushContext "Normal" >> 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 [("Python",["Normal"])], synStLanguage = "Python", synStCurrentLine = "", synStCharsParsedInLine = 0, synStCaseSensitive = True, synStKeywordCaseSensitive = True, synStCaptures = []}
parseSourceLine = manyTill parseExpressionInternal pEndLine
pEndLine = do
newline <|> (eof >> return '\n')
context <- currentContext
case context of
"Normal" -> return ()
"parenthesised" -> return ()
"Tripple A-comment" -> return ()
"Tripple Q-comment" -> return ()
"Tripple A-string" -> return ()
"Raw Tripple A-string" -> return ()
"Tripple Q-string" -> return ()
"Raw Tripple Q-string" -> return ()
"Single A-comment" -> return ()
"Single Q-comment" -> return ()
"Single A-string" -> return ()
"Single Q-string" -> return ()
"Raw A-string" -> return ()
"Raw Q-string" -> 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"),("Definition Keyword","Keyword"),("Operator","Normal"),("String Substitution","Normal"),("Command Keyword","Keyword"),("Flow Control Keyword","Keyword"),("Builtin Function","DataType"),("Special Variable","Others"),("Extensions","Others"),("Preprocessor","Char"),("String Char","Char"),("Long","Others"),("Float","Float"),("Int","DecVal"),("Hex","Others"),("Octal","Others"),("Complex","Others"),("Comment","Comment"),("String","String"),("Raw String","String")]
parseExpressionInternal = do
context <- currentContext
parseRules context <|> (pDefault >>= withAttribute (fromMaybe "" $ lookup context defaultAttributes))
defaultAttributes = [("Normal","Normal Text"),("parenthesised","Normal Text"),("Tripple A-comment","Comment"),("Tripple Q-comment","Comment"),("Tripple A-string","String"),("Raw Tripple A-string","Raw String"),("Tripple Q-string","String"),("Raw Tripple Q-string","Raw String"),("Single A-comment","Comment"),("Single Q-comment","Comment"),("Single A-string","String"),("Single Q-string","String"),("Raw A-string","Raw String"),("Raw Q-string","Raw String")]
parseRules "Normal" =
do (attr, result) <- (((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" ["import","from","as"] >>= withAttribute "Preprocessor"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" ["class","def","del","global","lambda"] >>= withAttribute "Definition Keyword"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" ["and","assert","in","is","not","or"] >>= withAttribute "Operator"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" ["exec","print"] >>= withAttribute "Command Keyword"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" ["break","continue","elif","else","except","finally","for","if","pass","raise","return","try","while","yield"] >>= withAttribute "Flow Control Keyword"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" ["__import__","abs","all","any","apply","basestring","bool","buffer","callable","chr","classmethod","cmp","coerce","compile","complex","delattr","dict","dir","divmod","enumerate","eval","execfile","file","filter","float","frozenset","getattr","globals","hasattr","hash","hex","id","input","int","intern","isinstance","issubclass","iter","len","list","locals","long","map","max","min","object","oct","open","ord","pow","property","range","raw_input","reduce","reload","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","unichr","unicode","vars","xrange","zip"] >>= withAttribute "Builtin Function"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" ["None","self","True","False","NotImplemented","Ellipsis"] >>= withAttribute "Special Variable"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" ["SIGNAL","SLOT","connect"] >>= withAttribute "Extensions"))
<|>
((pRegExpr (compileRegex "[a-zA-Z_][a-zA-Z_0-9]+") >>= withAttribute "Normal"))
<|>
((pRegExpr (compileRegex " ((([0-9]*\\.[0-9]+|[0-9]+\\.)|([0-9]+|([0-9]*\\.[0-9]+|[0-9]+\\.))[eE](\\+|-)?[0-9]+)|[0-9]+)[jJ]") >>= withAttribute "Complex"))
<|>
((pRegExpr (compileRegex "([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][0-9]+)?") >>= withAttribute "Float"))
<|>
((pRegExpr (compileRegex "([1-9][0-9]*([eE][0-9]+)?|0)") >>= withAttribute "Int"))
<|>
((pRegExpr (compileRegex "[1-9][0-9]*([eE][0-9.]+)?[Ll]") >>= withAttribute "Long"))
<|>
((pRegExpr (compileRegex "0[Xx][0-9a-fA-F]+") >>= withAttribute "Hex"))
<|>
((pRegExpr (compileRegex "0[1-9][0-9]*") >>= withAttribute "Octal"))
<|>
((pRegExpr (compileRegex "[rR]'''") >>= withAttribute "Raw String") >>~ pushContext "Raw Tripple A-string")
<|>
((pRegExpr (compileRegex "[rR]\"\"\"") >>= withAttribute "Raw String") >>~ pushContext "Raw Tripple Q-string")
<|>
((pRegExpr (compileRegex "[rR]'") >>= withAttribute "Raw String") >>~ pushContext "Raw A-string")
<|>
((pRegExpr (compileRegex "[rR]\"") >>= withAttribute "Raw String") >>~ pushContext "Raw Q-string")
<|>
((pRegExpr (compileRegex "#.*$") >>= withAttribute "Comment"))
<|>
((pColumn 0 >> pRegExpr (compileRegex "\\s*'''") >>= withAttribute "Comment") >>~ pushContext "Tripple A-comment")
<|>
((pColumn 0 >> pRegExpr (compileRegex "\\s*\"\"\"") >>= withAttribute "Comment") >>~ pushContext "Tripple Q-comment")
<|>
((pString False "'''" >>= withAttribute "String") >>~ pushContext "Tripple A-string")
<|>
((pString False "\"\"\"" >>= withAttribute "String") >>~ pushContext "Tripple Q-string")
<|>
((pDetectChar False '\'' >>= withAttribute "String") >>~ pushContext "Single A-string")
<|>
((pDetectChar False '"' >>= withAttribute "String") >>~ pushContext "Single Q-string")
<|>
((pDetectChar False '(' >>= withAttribute "Operator") >>~ pushContext "parenthesised")
<|>
((pDetectChar False ')' >>= withAttribute "Operator") >>~ (popContext >> return ()))
<|>
((pRegExpr (compileRegex "[+*/%\\|=;\\!<>!^&~-]") >>= withAttribute "Operator"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution")))
return (attr, result)
parseRules "parenthesised" =
do (attr, result) <- ((parseRules "Normal"))
return (attr, result)
parseRules "Tripple A-comment" =
do (attr, result) <- ((pString False "'''" >>= withAttribute "Comment") >>~ (popContext >> return ()))
return (attr, result)
parseRules "Tripple Q-comment" =
do (attr, result) <- (((pHlCChar >>= withAttribute "Comment"))
<|>
((pRegExpr (compileRegex "\"\"\"") >>= withAttribute "Comment") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Tripple A-string" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "String Char"))
<|>
((pRegExpr (compileRegex "%\\([a-zA-Z0-9_]+\\)[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "'''") >>= withAttribute "String") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Raw Tripple A-string" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "Raw String"))
<|>
((pRegExpr (compileRegex "%\\([a-zA-Z0-9_]+\\)[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "'''") >>= withAttribute "String") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Tripple Q-string" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "String Char"))
<|>
((pRegExpr (compileRegex "%\\([a-zA-Z0-9_]+\\)[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "\"\"\"") >>= withAttribute "String") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Raw Tripple Q-string" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "Raw String"))
<|>
((pRegExpr (compileRegex "%\\([a-zA-Z0-9_]+\\)[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "\"\"\"") >>= withAttribute "String") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Single A-comment" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "Comment"))
<|>
((pDetectChar False '\'' >>= withAttribute "Comment") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Single Q-comment" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "Comment"))
<|>
((pDetectChar False '"' >>= withAttribute "Comment") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Single A-string" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "String Char"))
<|>
((pRegExpr (compileRegex "%\\([a-zA-Z0-9_]+\\)[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pDetectChar False '\'' >>= withAttribute "String") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Single Q-string" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "String Char"))
<|>
((pRegExpr (compileRegex "%\\([a-zA-Z0-9_]+\\)[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pDetectChar False '"' >>= withAttribute "String") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Raw A-string" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "Raw String"))
<|>
((pRegExpr (compileRegex "%\\([a-zA-Z0-9_]+\\)[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pDetectChar False '\'' >>= withAttribute "Raw String") >>~ (popContext >> return ())))
return (attr, result)
parseRules "Raw Q-string" =
do (attr, result) <- (((pHlCStringChar >>= withAttribute "Raw String"))
<|>
((pRegExpr (compileRegex "%\\([a-zA-Z0-9_]+\\)[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pRegExpr (compileRegex "%[a-zA-Z]") >>= withAttribute "String Substitution"))
<|>
((pDetectChar False '"' >>= withAttribute "Raw String") >>~ (popContext >> return ())))
return (attr, result)
parseRules x = fail $ "Unknown context" ++ x