splitModes ::
  ModeTypes {- ^ mode interpretation -} ->
  ByteString   {- ^ modes               -} ->
  [ByteString] {- ^ arguments           -} ->
  Maybe [(Bool,Char,ByteString)]
splitModes icm modes0 =
  foldr aux (\_ args -> [] <$ guard (null args)) (B8.unpack modes0) True
  where
  aux ::
    Char                                        {- current mode -} ->
    (Bool -> [ByteString] -> Maybe [(Bool,Char,ByteString)])
           {- continuation with updated polarity and arguments -} ->
    Bool                                        {- current polarity -} ->
    [ByteString]                                {- current arguments -} ->
    Maybe [(Bool,Char,ByteString)]
  aux m rec polarity args =
    case m of
      '+' -> rec True  args
      '-' -> rec False args

      _ |             m `elem` view modesAlwaysArg icm
       || polarity && m `elem` view modesSetArg icm
       ||             m `elem` views modesPrefixModes (map fst) icm
       ||             m `elem` view modesLists icm ->
           do x:xs <- Just args
              fmap (cons (polarity,m,x)) (rec polarity xs)

        | otherwise -> -- default to no arg
              fmap (cons (polarity,m,"")) (rec polarity args)
splitModes ::
  ModeTypes {- ^ mode interpretation -} ->
  ByteString   {- ^ modes               -} ->
  [ByteString] {- ^ arguments           -} ->
  Maybe [(Bool,Char,ByteString)]
splitModes icm modes0 =
  foldr aux (\_ args -> [] <$ guard (null args)) (B8.unpack modes0) True
  where
  aux ::
    Char                                        {- current mode -} ->
    (Bool -> [ByteString] -> Maybe [(Bool,Char,ByteString)])
           {- continuation with updated polarity and arguments -} ->
    Bool                                        {- current polarity -} ->
    [ByteString]                                {- current arguments -} ->
    Maybe [(Bool,Char,ByteString)]
  aux m rec polarity args =
    case m of
      '+' -> rec True  args
      '-' -> rec False args

      _ |             m `elem` view modesAlwaysArg icm
       || polarity && m `elem` view modesSetArg icm
       ||             m `elem` views modesPrefixModes (map fst) icm
       ||             m `elem` view modesLists icm ->
           do x:xs <- Just args
              fmap (cons (polarity,m,x)) (rec polarity xs)

        | otherwise -> -- default to no arg
              fmap (cons (polarity,m,"")) (rec polarity args)
splitModes icm modes0 =
  foldr aux (\_ args -> [] <$ guard (null args)) (B8.unpack modes0) True
  where
  aux ::
    Char                                        {- current mode -} ->
    (Bool -> [ByteString] -> Maybe [(Bool,Char,ByteString)])
           {- continuation with updated polarity and arguments -} ->
    Bool                                        {- current polarity -} ->
    [ByteString]                                {- current arguments -} ->
    Maybe [(Bool,Char,ByteString)]
  aux m rec polarity args =
    case m of
      '+' -> rec True  args
      '-' -> rec False args

      _ |             m `elem` view modesAlwaysArg icm
       || polarity && m `elem` view modesSetArg icm
       ||             m `elem` views modesPrefixModes (map fst) icm
       ||             m `elem` view modesLists icm ->
           do x:xs <- Just args
              fmap (cons (polarity,m,x)) (rec polarity xs)

        | otherwise -> -- default to no arg
              fmap (cons (polarity,m,"")) (rec polarity args)