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 -> String -> [Syntax]
syntaxesByExtension SyntaxMap
syntaxmap (Char
'.':String
ext) =
  SyntaxMap -> String -> [Syntax]
syntaxesByFilename SyntaxMap
syntaxmap (String
"*." forall a. [a] -> [a] -> [a]
++ String
ext)
syntaxesByExtension SyntaxMap
syntaxmap String
ext =
  SyntaxMap -> String -> [Syntax]
syntaxesByFilename SyntaxMap
syntaxmap (String
"*." forall a. [a] -> [a] -> [a]
++ String
ext)

-- | Returns a list of syntaxes appropriate for the given filename.
syntaxesByFilename :: SyntaxMap -> String -> [Syntax]
syntaxesByFilename :: SyntaxMap -> String -> [Syntax]
syntaxesByFilename SyntaxMap
syntaxmap String
fn = [Syntax
s | Syntax
s <- forall k a. Map k a -> [a]
Map.elems SyntaxMap
syntaxmap
                                , String -> [String] -> Bool
matchGlobs String
fn (Syntax -> [String]
sExtensions Syntax
s)]

-- | Lookup a syntax by full name (case insensitive).
syntaxByName :: SyntaxMap -> Text -> Maybe Syntax
syntaxByName :: SyntaxMap -> Text -> Maybe Syntax
syntaxByName SyntaxMap
syntaxmap Text
name =
  forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (Text -> Text
Text.toLower Text
name) (forall k2 k1 a. Ord k2 => (k1 -> k2) -> Map k1 a -> Map k2 a
Map.mapKeys Text -> Text
Text.toLower SyntaxMap
syntaxmap)

-- | Lookup a syntax by short name (case insensitive).
syntaxByShortName :: SyntaxMap -> Text -> Maybe Syntax
syntaxByShortName :: SyntaxMap -> Text -> Maybe Syntax
syntaxByShortName SyntaxMap
syntaxmap Text
name = forall a. [a] -> Maybe a
listToMaybe
  [Syntax
s | Syntax
s <- forall k a. Map k a -> [a]
Map.elems SyntaxMap
syntaxmap
     , Text -> Text
Text.toLower (Syntax -> Text
sShortname Syntax
s) forall a. Eq a => a -> a -> Bool
== Text -> Text
Text.toLower Text
name ]

-- | Lookup syntax by (in order) full name (case insensitive),
-- short name (case insensitive), extension.
lookupSyntax :: Text -> SyntaxMap -> Maybe Syntax
lookupSyntax :: Text -> SyntaxMap -> Maybe Syntax
lookupSyntax Text
lang SyntaxMap
syntaxmap
  -- special cases:
  | Text
lang forall a. Eq a => a -> a -> Bool
== String -> Text
Text.pack String
"csharp" = Text -> SyntaxMap -> Maybe Syntax
lookupSyntax (String -> Text
Text.pack String
"cs") SyntaxMap
syntaxmap
  | Text
lang forall a. Eq a => a -> a -> Bool
== String -> Text
Text.pack String
"fortran" = Text -> SyntaxMap -> Maybe Syntax
lookupSyntax (String -> Text
Text.pack String
"for")
              SyntaxMap
syntaxmap
  | Bool
otherwise =
    SyntaxMap -> Text -> Maybe Syntax
syntaxByName SyntaxMap
syntaxmap Text
lang forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus`
    SyntaxMap -> Text -> Maybe Syntax
syntaxByShortName SyntaxMap
syntaxmap Text
lang forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus`
    forall a. [a] -> Maybe a
listToMaybe (SyntaxMap -> String -> [Syntax]
syntaxesByExtension SyntaxMap
syntaxmap (Text -> String
Text.unpack Text
lang))

-- | Match filename against a list of globs contained in a semicolon-separated
-- string.
matchGlobs :: String -> [String] -> Bool
matchGlobs :: String -> [String] -> Bool
matchGlobs String
fn [String]
globs = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> String -> Bool
matchGlob String
fn) [String]
globs

-- | Match filename against a glob pattern with asterisks.
matchGlob :: String -> String -> Bool
matchGlob :: String -> String -> Bool
matchGlob (Char
'*':String
xs) String
fn   = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> String -> Bool
matchGlob String
xs) (forall a. [a] -> [[a]]
tails String
fn)
matchGlob (Char
x:String
xs) (Char
y:String
ys) = Char
x forall a. Eq a => a -> a -> Bool
== Char
y Bool -> Bool -> Bool
&& String -> String -> Bool
matchGlob String
xs String
ys
matchGlob String
"" String
""         = Bool
True
matchGlob String
_ String
_           = Bool
False