cmd_colour :: String -> IP.IdrisParser (Either String Command)
cmd_colour name = fmap Right pSetColourCmd

    where
        colours :: [(String, Maybe Color)]
        colours = [ ("black", Just Black)
                  , ("red", Just Red)
                  , ("green", Just Green)
                  , ("yellow", Just Yellow)
                  , ("blue", Just Blue)
                  , ("magenta", Just Magenta)
                  , ("cyan", Just Cyan)
                  , ("white", Just White)
                  , ("default", Nothing)
                  ]

        pSetColourCmd :: IP.IdrisParser Command
        pSetColourCmd = (do c <- pColourType
                            let defaultColour = IdrisColour Nothing True False False False
                            opts <- P.sepBy pColourMod (IP.whiteSpace)
                            let colour = foldr ($) defaultColour $ reverse opts
                            return $ SetColour c colour)
                    <|> P.try (IP.symbol "on" >> return ColourOn)
                    <|> P.try (IP.symbol "off" >> return ColourOff)

        pColour :: IP.IdrisParser (Maybe Color)
        pColour = doColour colours
            where doColour [] = fail "Unknown colour"
                  doColour ((s, c):cs) = (P.try (IP.symbol s) >> return c) <|> doColour cs

        pColourMod :: IP.IdrisParser (IdrisColour -> IdrisColour)
        pColourMod = P.try (doVivid <$ IP.symbol "vivid")
                 <|> P.try (doDull <$ IP.symbol "dull")
                 <|> P.try (doUnderline <$ IP.symbol "underline")
                 <|> P.try (doNoUnderline <$ IP.symbol "nounderline")
                 <|> P.try (doBold <$ IP.symbol "bold")
                 <|> P.try (doNoBold <$ IP.symbol "nobold")
                 <|> P.try (doItalic <$ IP.symbol "italic")
                 <|> P.try (doNoItalic <$ IP.symbol "noitalic")
                 <|> P.try (pColour >>= return . doSetColour)
            where doVivid i       = i { vivid = True }
                  doDull i        = i { vivid = False }
                  doUnderline i   = i { underline = True }
                  doNoUnderline i = i { underline = False }
                  doBold i        = i { bold = True }
                  doNoBold i      = i { bold = False }
                  doItalic i      = i { italic = True }
                  doNoItalic i    = i { italic = False }
                  doSetColour c i = i { colour = c }

        -- | Generate the colour type names using the default Show instance.
        colourTypes :: [(String, ColourType)]
        colourTypes = map (\x -> ((map toLower . reverse . drop 6 . reverse . show) x, x)) $
                      enumFromTo minBound maxBound

        pColourType :: IP.IdrisParser ColourType
        pColourType = doColourType colourTypes
            where doColourType [] = fail $ "Unknown colour category. Options: " ++
                                           (concat . intersperse ", " . map fst) colourTypes
                  doColourType ((s,ct):cts) = (P.try (IP.symbol s) >> return ct) <|> doColourType cts
cmd_colour :: String -> IP.IdrisParser (Either String Command)
cmd_colour name = fmap Right pSetColourCmd

    where
        colours :: [(String, Maybe Color)]
        colours = [ ("black", Just Black)
                  , ("red", Just Red)
                  , ("green", Just Green)
                  , ("yellow", Just Yellow)
                  , ("blue", Just Blue)
                  , ("magenta", Just Magenta)
                  , ("cyan", Just Cyan)
                  , ("white", Just White)
                  , ("default", Nothing)
                  ]

        pSetColourCmd :: IP.IdrisParser Command
        pSetColourCmd = (do c <- pColourType
                            let defaultColour = IdrisColour Nothing True False False False
                            opts <- P.sepBy pColourMod (IP.whiteSpace)
                            let colour = foldr ($) defaultColour $ reverse opts
                            return $ SetColour c colour)
                    <|> P.try (IP.symbol "on" >> return ColourOn)
                    <|> P.try (IP.symbol "off" >> return ColourOff)

        pColour :: IP.IdrisParser (Maybe Color)
        pColour = doColour colours
            where doColour [] = fail "Unknown colour"
                  doColour ((s, c):cs) = (P.try (IP.symbol s) >> return c) <|> doColour cs

        pColourMod :: IP.IdrisParser (IdrisColour -> IdrisColour)
        pColourMod = P.try (doVivid <$ IP.symbol "vivid")
                 <|> P.try (doDull <$ IP.symbol "dull")
                 <|> P.try (doUnderline <$ IP.symbol "underline")
                 <|> P.try (doNoUnderline <$ IP.symbol "nounderline")
                 <|> P.try (doBold <$ IP.symbol "bold")
                 <|> P.try (doNoBold <$ IP.symbol "nobold")
                 <|> P.try (doItalic <$ IP.symbol "italic")
                 <|> P.try (doNoItalic <$ IP.symbol "noitalic")
                 <|> P.try (pColour >>= return . doSetColour)
            where doVivid i       = i { vivid = True }
                  doDull i        = i { vivid = False }
                  doUnderline i   = i { underline = True }
                  doNoUnderline i = i { underline = False }
                  doBold i        = i { bold = True }
                  doNoBold i      = i { bold = False }
                  doItalic i      = i { italic = True }
                  doNoItalic i    = i { italic = False }
                  doSetColour c i = i { colour = c }

        -- | Generate the colour type names using the default Show instance.
        colourTypes :: [(String, ColourType)]
        colourTypes = map (\x -> ((map toLower . reverse . drop 6 . reverse . show) x, x)) $
                      enumFromTo minBound maxBound

        pColourType :: IP.IdrisParser ColourType
        pColourType = doColourType colourTypes
            where doColourType [] = fail $ "Unknown colour category. Options: " ++
                                           (concat . intersperse ", " . map fst) colourTypes
                  doColourType ((s,ct):cts) = (P.try (IP.symbol s) >> return ct) <|> doColourType cts
cmd_colour name = fmap Right pSetColourCmd

    where
        colours :: [(String, Maybe Color)]
        colours = [ ("black", Just Black)
                  , ("red", Just Red)
                  , ("green", Just Green)
                  , ("yellow", Just Yellow)
                  , ("blue", Just Blue)
                  , ("magenta", Just Magenta)
                  , ("cyan", Just Cyan)
                  , ("white", Just White)
                  , ("default", Nothing)
                  ]

        pSetColourCmd :: IP.IdrisParser Command
        pSetColourCmd = (do c <- pColourType
                            let defaultColour = IdrisColour Nothing True False False False
                            opts <- P.sepBy pColourMod (IP.whiteSpace)
                            let colour = foldr ($) defaultColour $ reverse opts
                            return $ SetColour c colour)
                    <|> P.try (IP.symbol "on" >> return ColourOn)
                    <|> P.try (IP.symbol "off" >> return ColourOff)

        pColour :: IP.IdrisParser (Maybe Color)
        pColour = doColour colours
            where doColour [] = fail "Unknown colour"
                  doColour ((s, c):cs) = (P.try (IP.symbol s) >> return c) <|> doColour cs

        pColourMod :: IP.IdrisParser (IdrisColour -> IdrisColour)
        pColourMod = P.try (doVivid <$ IP.symbol "vivid")
                 <|> P.try (doDull <$ IP.symbol "dull")
                 <|> P.try (doUnderline <$ IP.symbol "underline")
                 <|> P.try (doNoUnderline <$ IP.symbol "nounderline")
                 <|> P.try (doBold <$ IP.symbol "bold")
                 <|> P.try (doNoBold <$ IP.symbol "nobold")
                 <|> P.try (doItalic <$ IP.symbol "italic")
                 <|> P.try (doNoItalic <$ IP.symbol "noitalic")
                 <|> P.try (pColour >>= return . doSetColour)
            where doVivid i       = i { vivid = True }
                  doDull i        = i { vivid = False }
                  doUnderline i   = i { underline = True }
                  doNoUnderline i = i { underline = False }
                  doBold i        = i { bold = True }
                  doNoBold i      = i { bold = False }
                  doItalic i      = i { italic = True }
                  doNoItalic i    = i { italic = False }
                  doSetColour c i = i { colour = c }

        -- | Generate the colour type names using the default Show instance.
        colourTypes :: [(String, ColourType)]
        colourTypes = map (\x -> ((map toLower . reverse . drop 6 . reverse . show) x, x)) $
                      enumFromTo minBound maxBound

        pColourType :: IP.IdrisParser ColourType
        pColourType = doColourType colourTypes
            where doColourType [] = fail $ "Unknown colour category. Options: " ++
                                           (concat . intersperse ", " . map fst) colourTypes
                  doColourType ((s,ct):cts) = (P.try (IP.symbol s) >> return ct) <|> doColourType cts