content: module Skylighting.Core (
      lookupSyntax
    , syntaxByName
    , syntaxByShortName
    , syntaxesByExtension
    , syntaxesByFilename
    , module Skylighting.Types
    , module Skylighting.Tokenizer
    , module Skylighting.Parser
    , module Skylighting.Regex
    , module Skylighting.Styles
    , module Skylighting.Loader
    ) where
  import Control.Monad
  import Data.List (tails)
  import qualified Data.Map as Map
  import Data.Maybe (listToMaybe)
  import Data.Text (Text)
  import qualified Data.Text as Text
  import Skylighting.Loader
  import Skylighting.Parser
  import Skylighting.Regex
  import Skylighting.Styles
  import Skylighting.Tokenizer
  import Skylighting.Types
  
  -- | Returns a list of syntaxes appropriate for the given file extension.
  syntaxesByExtension :: SyntaxMap -> String -> [Syntax]
  syntaxesByExtension syntaxmap ('.':ext) =
    syntaxesByFilename syntaxmap ("*." ++ ext)
  syntaxesByExtension syntaxmap ext =
    syntaxesByFilename syntaxmap ("*." ++ ext)
  
  -- | Returns a list of syntaxes appropriate for the given filename.
  syntaxesByFilename :: SyntaxMap -> String -> [Syntax]
  syntaxesByFilename syntaxmap fn = [s | s <- Map.elems syntaxmap
                                  , matchGlobs fn (sExtensions s)]
  
  -- | Lookup a syntax by full name (case insensitive).
  syntaxByName :: SyntaxMap -> Text -> Maybe Syntax
  syntaxByName syntaxmap name =
    Map.lookup (Text.toLower name) (Map.mapKeys Text.toLower syntaxmap)
  
  -- | Lookup a syntax by short name (case insensitive).
  syntaxByShortName :: SyntaxMap -> Text -> Maybe Syntax
  syntaxByShortName syntaxmap name = listToMaybe
    [s | s <- Map.elems syntaxmap
       , Text.toLower (sShortname s) == Text.toLower name ]
  
  -- | Lookup syntax by (in order) full name (case insensitive),
  -- short name (case insensitive), extension.
  lookupSyntax :: Text -> SyntaxMap -> Maybe Syntax
  lookupSyntax lang syntaxmap
    -- special cases:
    | lang == Text.pack "csharp" = lookupSyntax (Text.pack "cs") syntaxmap
    | lang == Text.pack "fortran" = lookupSyntax (Text.pack "for")
                syntaxmap
    | otherwise =
      syntaxByName syntaxmap lang `mplus`
      syntaxByShortName syntaxmap lang `mplus`
      listToMaybe (syntaxesByExtension syntaxmap (Text.unpack lang))
  
  -- | Match filename against a list of globs contained in a semicolon-separated
  -- string.
  matchGlobs :: String -> [String] -> Bool
  matchGlobs fn globs = any (flip matchGlob fn) globs
  
  -- | Match filename against a glob pattern with asterisks.
  matchGlob :: String -> String -> Bool
  matchGlob ('*':xs) fn   = any (matchGlob xs) (tails fn)
  matchGlob (x:xs) (y:ys) = x == y && matchGlob xs ys
  matchGlob "" ""         = True
  matchGlob _ _           = False
  