content: module Ormolu.Utils.Glob
    ( Glob,
      mkGlob,
      matchesGlob,
    )
  where
  
  import Data.List (elemIndex, stripPrefix)
  import Data.Maybe (fromMaybe)
  
  newtype Glob = Glob [GlobPart]
    deriving (Eq, Show)
  
  data GlobPart
    = MatchExactly !String
    | SingleWildcard
    | DoubleWildcard
    deriving (Eq, Show)
  
  mkGlob :: String -> Glob
  mkGlob = Glob . parsePart
    where
      parsePart :: String -> [GlobPart]
      parsePart s = case s of
        [] ->
          []
        '*' : '*' : t ->
          DoubleWildcard : parsePart t
        '*' : t ->
          SingleWildcard : parsePart t
        t ->
          let (m, t') = break (== '*') t
           in MatchExactly m : parsePart t'
  
  matchesGlob :: String -> Glob -> Bool
  matchesGlob s (Glob ps) = s `matchesGlobParts` ps
  
  matchesGlobParts :: String -> [GlobPart] -> Bool
  matchesGlobParts s g = case g of
    [] ->
      null s
    MatchExactly p : g' ->
      case stripPrefix p s of
        Nothing -> False
        Just s' -> s' `matchesGlobParts` g'
    SingleWildcard : g' ->
      let l = fromMaybe (length s) (elemIndex '.' s)
       in or [s' `matchesGlobParts` g' | i <- [0 .. l], let s' = drop i s]
    DoubleWildcard : g' ->
      or [s' `matchesGlobParts` g' | i <- [0 .. length s], let s' = drop i s]
  