content: -----------------------------------------------------------------------------
  -- |
  -- Module      :  Distribution.Text
  -- Copyright   :  Duncan Coutts 2007
  --
  -- Maintainer  :  cabal-devel@haskell.org
  -- Portability :  portable
  --
  -- This defines a 'Text' class which is a bit like the 'Read' and 'Show'
  -- classes. The difference is that is uses a modern pretty printer and parser
  -- system and the format is not expected to be Haskell concrete syntax but
  -- rather the external human readable representation used by Cabal.
  --
  module Distribution.Text (
    Text(..),
    display,
    simpleParse,
    ) where
  
  import qualified Distribution.Compat.ReadP as Parse
  import qualified Text.PrettyPrint          as Disp
  
  import Data.Version (Version(Version))
  import qualified Data.Char as Char (isDigit, isAlphaNum, isSpace)
  
  class Text a where
    disp  :: a -> Disp.Doc
    parse :: Parse.ReadP r a
  
  display :: Text a => a -> String
  display = Disp.renderStyle style . disp
    where style = Disp.Style {
            Disp.mode            = Disp.PageMode,
            Disp.lineLength      = 79,
            Disp.ribbonsPerLine  = 1.0
          }
  
  simpleParse :: Text a => String -> Maybe a
  simpleParse str = case [ p | (p, s) <- Parse.readP_to_S parse str
                         , all Char.isSpace s ] of
    []    -> Nothing
    (p:_) -> Just p
  
  -- -----------------------------------------------------------------------------
  -- Instances for types from the base package
  
  instance Text Bool where
    disp  = Disp.text . show
    parse = Parse.choice [ (Parse.string "True" Parse.+++
                            Parse.string "true") >> return True
                         , (Parse.string "False" Parse.+++
                            Parse.string "false") >> return False ]
  
  instance Text Version where
    disp (Version branch _tags)     -- Death to version tags!!
      = Disp.hcat (Disp.punctuate (Disp.char '.') (map Disp.int branch))
  
    parse = do
        branch <- Parse.sepBy1 digits (Parse.char '.')
        tags   <- Parse.many (Parse.char '-' >> Parse.munch1 Char.isAlphaNum)
        return (Version branch tags)  --TODO: should we ignore the tags?
      where
        digits = do
          first <- Parse.satisfy Char.isDigit
          if first == '0'
            then return 0
            else do rest <- Parse.munch Char.isDigit
                    return (read (first : rest))
  