content: -- | This is a library which colourises Haskell code.
  --   It currently has six output formats:
  --
  -- * ANSI terminal codes
  --
  -- * LaTeX macros
  --
  -- * HTML 3.2 with font tags
  --
  -- * HTML 4.01 with external CSS.
  --
  -- * XHTML 1.0 with internal CSS.
  --
  -- * mIRC chat client colour codes.
  --
  module Language.Haskell.HsColour (Output(..), ColourPrefs(..),
                                    hscolour) where
  
  import Language.Haskell.HsColour.Colourise  (ColourPrefs(..))
  import qualified Language.Haskell.HsColour.TTY        as TTY
  import qualified Language.Haskell.HsColour.HTML       as HTML
  import qualified Language.Haskell.HsColour.CSS        as CSS
  import qualified Language.Haskell.HsColour.ACSS       as ACSS 
  import qualified Language.Haskell.HsColour.InlineCSS  as ICSS
  import qualified Language.Haskell.HsColour.LaTeX      as LaTeX
  import qualified Language.Haskell.HsColour.MIRC       as MIRC
  import Data.List(mapAccumL, isPrefixOf)
  import Data.Maybe
  import Language.Haskell.HsColour.Output
  --import Debug.Trace
  
  -- | Colourise Haskell source code with the given output format.
  hscolour :: Output      -- ^ Output format.
           -> ColourPrefs -- ^ Colour preferences (for formats that support them).
           -> Bool        -- ^ Whether to include anchors.
           -> Bool        -- ^ Whether output document is partial or complete.
           -> String	-- ^ Title for output.
           -> Bool        -- ^ Whether input document is literate haskell or not
           -> String      -- ^ Haskell source code.
           -> String      -- ^ Coloured Haskell source code.
  hscolour output pref anchor partial title False =
          (if partial then id else top'n'tail output title) .
          hscolour' output pref anchor
  hscolour output pref anchor partial title True  =
          (if partial then id else top'n'tail output title) .
          concatMap chunk . joinL . classify . inlines
    where
      chunk (Code c) = hscolour' output pref anchor c
      chunk (Lit c)  = c
  
  -- | The actual colourising worker, despatched on the chosen output format.
  hscolour' :: Output      -- ^ Output format.
            -> ColourPrefs -- ^ Colour preferences (for formats that support them)
            -> Bool        -- ^ Whether to include anchors.
            -> String      -- ^ Haskell source code.
            -> String      -- ^ Coloured Haskell source code.
  hscolour' TTY       pref _      = TTY.hscolour     pref
  hscolour' (TTYg tt) pref _      = TTY.hscolourG tt pref
  hscolour' MIRC      pref _      = MIRC.hscolour    pref
  hscolour' LaTeX     pref _      = LaTeX.hscolour   pref
  hscolour' HTML      pref anchor = HTML.hscolour    pref anchor
  hscolour' CSS       _    anchor = CSS.hscolour          anchor
  hscolour' ICSS      pref anchor = ICSS.hscolour    pref anchor
  hscolour' ACSS      _    anchor = ACSS.hscolour         anchor
  
  -- | Choose the right headers\/footers, depending on the output format.
  top'n'tail :: Output           -- ^ Output format
             -> String           -- ^ Title for output
             -> (String->String) -- ^ Output transformer
  top'n'tail TTY   _     = id
  top'n'tail (TTYg _) _  = id
  top'n'tail MIRC  _     = id
  top'n'tail LaTeX title = LaTeX.top'n'tail title
  top'n'tail HTML  title = HTML.top'n'tail title
  top'n'tail CSS   title = CSS.top'n'tail  title
  top'n'tail ICSS  title = ICSS.top'n'tail title
  top'n'tail ACSS  title = CSS.top'n'tail  title
  
  -- | Separating literate files into code\/comment chunks.
  data Lit = Code {unL :: String} | Lit {unL :: String} deriving (Show)
  
  -- Re-implementation of 'lines', for better efficiency (but decreased laziness).
  -- Also, importantly, accepts non-standard DOS and Mac line ending characters.
  -- And retains the trailing '\n' character in each resultant string.
  inlines :: String -> [String]
  inlines s = lines' s id
    where
    lines' []             acc = [acc []]
    lines' ('\^M':'\n':s) acc = acc ['\n'] : lines' s id	-- DOS
  --lines' ('\^M':s)      acc = acc ['\n'] : lines' s id	-- MacOS
    lines' ('\n':s)       acc = acc ['\n'] : lines' s id	-- Unix
    lines' (c:s)          acc = lines' s (acc . (c:))
  
  
  -- | The code for classify is largely stolen from Language.Preprocessor.Unlit.
  classify ::  [String] -> [Lit]
  classify []             = []
  classify (x:xs) | "\\begin{code}"`isPrefixOf`x
                          = Lit x: allProg xs
     where allProg []     = []  -- Should give an error message,
                                -- but I have no good position information.
           allProg (x:xs) | "\\end{code}"`isPrefixOf`x
                          = Lit x: classify xs
           allProg (x:xs) = Code x: allProg xs
  classify (('>':x):xs)   = Code ('>':x) : classify xs
  classify (x:xs)         = Lit x: classify xs
  
  -- | Join up chunks of code\/comment that are next to each other.
  joinL :: [Lit] -> [Lit]
  joinL []                  = []
  joinL (Code c:Code c2:xs) = joinL (Code (c++c2):xs)
  joinL (Lit c :Lit c2 :xs) = joinL (Lit  (c++c2):xs)
  joinL (any:xs)            = any: joinL xs
  
  