diff options
Diffstat (limited to 'src/Xmobar')
-rw-r--r-- | src/Xmobar/Config/Template.hs | 63 |
1 files changed, 28 insertions, 35 deletions
diff --git a/src/Xmobar/Config/Template.hs b/src/Xmobar/Config/Template.hs index 407771d..2a5b3d7 100644 --- a/src/Xmobar/Config/Template.hs +++ b/src/Xmobar/Config/Template.hs @@ -17,8 +17,8 @@ module Xmobar.Config.Template (parseString) where -import Control.Monad (guard, mzero) import Data.Maybe (fromMaybe) +import qualified Control.Monad as CM import Text.Parsec ((<|>)) import Text.Read (readMaybe) @@ -35,7 +35,8 @@ type Context = (T.TextRenderInfo, T.FontIndex, Maybe [T.Action]) retSegment :: Context -> T.Widget -> Parser [T.Segment] retSegment (i, idx, as) widget = return [(widget, i, idx, as)] --- | Run the template string parser +-- | Run the template string parser for the given config, producing a list of +-- drawable segment specifications. parseString :: T.Config -> String -> [T.Segment] parseString c s = case P.parse (stringParser ci) "" s of @@ -44,38 +45,37 @@ parseString c s = where ci = (ti , 0, Nothing) ti = T.TextRenderInfo (T.fgColor c) 0 0 [] --- | Top level parser reading the full template string +-- Top level parser reading the full template string stringParser :: Context -> Parser [[T.Segment]] stringParser c = C.manyTill (allParsers c) C.eof allParsers :: Context -> Parser [T.Segment] -allParsers c = foldl (\p fn -> p <|> P.try (fn c)) (textParser c) - [ iconParser, hspaceParser, rawParser, actionParser - , fontParser, boxParser, colorParser] +allParsers c = C.choice (textParser c:map (\f -> P.try (f c)) parsers) + where parsers = [ iconParser, hspaceParser, rawParser, actionParser + , fontParser, boxParser, colorParser ] --- | Wrapper for notFollowedBy that returns the result of the first parser. --- Also works around the issue that, at least in Parsec 3.0.0, notFollowedBy --- accepts only parsers with return type Char. +-- Wrapper for notFollowedBy that returns the result of the first parser. +-- Also works around the issue that, at least in Parsec 3.0.0, notFollowedBy +-- accepts only parsers with return type Char. notFollowedBy' :: Parser a -> Parser b -> Parser a notFollowedBy' p e = do x <- p C.notFollowedBy $ P.try (e >> return '*') return x --- | Parse a maximal string without markup +-- Parse a maximal string without markup textParser :: Context -> Parser [T.Segment] textParser c = - C.many1 (P.noneOf "<" <|> P.try (notFollowedBy' (P.char '<') trys')) + C.many1 (P.noneOf "<" <|> P.try (notFollowedBy' (P.char '<') suffixes)) >>= retSegment c . T.Text - where trys = P.try . P.string - trys' = foldl (\p s -> p <|> trys s) (trys "fc=") - [ "box", "fn=", "action=", "/action>", "icon=" - , "hspace=", "raw=", "/fn>", "/box>", "/fc>"] - --- | Parse a "raw" tag, which we use to prevent other tags from creeping in. --- The format here is net-string-esque: a literal "<raw=" followed by a --- string of digits (base 10) denoting the length of the raw string, --- a literal ":" as digit-string-terminator, the raw string itself, and --- then a literal "/>". + where suffixes = C.choice $ map (P.try . P.string) + [ "icon=" , "hspace=", "raw=" + , "action=", "/action>", "fn=", "/fn>" + , "box", "/box>", "fc=", "/fc>" ] + +-- Parse a "raw" tag, which we use to prevent other tags from creeping in. +-- The format here is net-string-esque: a literal "<raw=" followed by a string +-- of digits (base 10) denoting the length of the raw string, a literal ":" as +-- digit-string-terminator, the raw string itself, and then a literal "/>". rawParser :: Context -> Parser [T.Segment] rawParser c = do P.string "<raw=" @@ -83,11 +83,11 @@ rawParser c = do P.char ':' case reads lenstr of [(len,[])] -> do - guard ((len :: Integer) <= fromIntegral (maxBound :: Int)) + CM.guard ((len :: Integer) <= fromIntegral (maxBound :: Int)) s <- C.count (fromIntegral len) P.anyChar P.string "/>" retSegment c (T.Text s) - _ -> mzero + _ -> CM.mzero iconParser :: Context -> Parser [T.Segment] iconParser c = do @@ -104,8 +104,8 @@ hspaceParser c = do actionParser :: Context -> Parser [T.Segment] actionParser (ti, fi, act) = do P.string "<action=" - command <- C.choice [C.between (P.char '`') (P.char '`') (C.many1 (P.noneOf "`")), - C.many1 (P.noneOf ">")] + command <- C.choice [C.between (P.char '`') (P.char '`') (C.many1 (P.noneOf "`")) + , C.many1 (P.noneOf ">")] buttons <- (P.char '>' >> return "1") <|> (P.space >> P.spaces >> C.between (P.string "button=") (P.string ">") (C.many1 (P.oneOf "12345"))) let a = T.Spawn (toButtons buttons) command @@ -118,10 +118,9 @@ actionParser (ti, fi, act) = do toButtons :: String -> [T.Button] toButtons = map (\x -> read [x]) --- | Parse a string wrapped in a color specification colorParser :: Context -> Parser [T.Segment] colorParser (T.TextRenderInfo _ _ _ bs, fidx, a) = do - c <- C.between (P.string "<fc=") (P.string ">") colors + c <- C.between (P.string "<fc=") (P.string ">") (C.many1 colorc) let colorParts = break (==':') c let (ot,ob) = case break (==',') (drop 1 $ snd colorParts) of (top,',':btm) -> (top, btm) @@ -132,17 +131,12 @@ colorParser (T.TextRenderInfo _ _ _ bs, fidx, a) = do bs s <- C.manyTill (allParsers (tri, fidx, a)) (P.try $ P.string "</fc>") return (concat s) - where colors = C.many1 (P.alphaNum <|> P.char ',' <|> P.char ':' <|> P.char '#') + where colorc = P.alphaNum <|> P.oneOf ",:#" --- | Parse a string wrapped in a box specification boxParser :: Context -> Parser [T.Segment] boxParser (T.TextRenderInfo cs ot ob bs, f, a) = do c <- C.between (P.string "<box") (P.string ">") - (C.option "" (C.many1 (P.alphaNum - <|> P.char '=' - <|> P.char ' ' - <|> P.char '#' - <|> P.char ','))) + (C.option "" (C.many1 (P.alphaNum <|> P.oneOf "= #,"))) let b = T.Box T.BBFull (T.BoxOffset T.C 0) 1 cs (T.BoxMargins 0 0 0 0) let g = boxReader b (words c) s <- C.manyTill @@ -186,7 +180,6 @@ boxParamReader (T.Box bb off lw fc mgs@(T.BoxMargins mt mr mb ml)) ('m':pos) v = boxParamReader b _ _ = b --- | Parse a string wrapped in a font specification fontParser :: Context -> Parser [T.Segment] fontParser (i, _, a) = do f <- C.between (P.string "<fn=") (P.string ">") (C.many1 P.digit) |