dot-linker-0.1.0.0: src/DotLinker/Parsers.hs
{-# LANGUAGE OverloadedStrings #-}
module DotLinker.Parsers
( lineMapParser
, envParser
, fileMapParser
, Entry
, EnvOrLit(..)
) where
import Control.Applicative
import Data.Attoparsec.ByteString.Char8
import Data.ByteString (ByteString)
import Data.Maybe (catMaybes)
import Data.Text (Text)
import Data.Text.Encoding (decodeUtf8)
import Filesystem.Path.CurrentOS (FilePath, decode)
import Prelude hiding (takeWhile, FilePath)
type Entry = (Text, [FilePath])
-- | Parser for a single line in the file
--
-- Example:
--
-- vimrc: /home/rar/.vimrc,/home/rar/.config/nvim/init.vim
lineMapParser :: Parser Entry
lineMapParser = do
src <- dotName <* char ':'
ts <- filePath `sepBy1` char ','
return (decodeUtf8 src, ts)
where
dotName = takeTill (== ':')
filePath =
strip $ decode <$> takeTill (inClass ",\n\r")
strip str = many' space *> str <* many' space
-- | Parser for a whole file
fileMapParser :: Parser [Entry]
fileMapParser = catMaybes <$> optLineMapParser `manyTill` endOfInput
where
optLineMapParser = (string "-- " *> skip1 lineMapParser *> return Nothing) <|> (Just <$> lineMapParser)
skip1 p = sc
where sc = (p *> pure ()) <|> pure ()
data EnvOrLit = Env ByteString -- ^ Represents an enviroment variable
| Lit ByteString -- ^ A literal path part
-- | Parser that parses a path with variables into parts
--
-- Example: $HOME/.dotfiles -> [Env HOME, Lit .dotfiles]
--
-- This will later be used by @expandPath@ to create:
--
-- [Env Home, Lit .dotfiles] -> /home/me/.dotfiles
envParser :: Parser [EnvOrLit]
envParser = secParser `sepBy1` char '/'
where
secParser =
let env = char '$' *> takeWhile (inClass "a-zA-Z_") <?> "env variable"
lit = takeTill (== '/') <?> "literal path part"
in (Env <$> env) <|> (Lit <$> lit)