content: module Unused.TagsSource
      ( TagSearchOutcome(..)
      , loadTagsFromFile
      , loadTagsFromPipe
      ) where
  
  import qualified Control.Exception as E
  import qualified Data.Bifunctor as BF
  import qualified Data.List as L
  import qualified Data.Text as T
  import qualified System.Directory as D
  import Unused.Util (safeReadFile)
  
  data TagSearchOutcome
      = TagsFileNotFound [String]
      | IOError E.IOException
  
  loadTagsFromPipe :: IO (Either TagSearchOutcome [String])
  loadTagsFromPipe = fmap (Right . tokensFromTags) getContents
  
  loadTagsFromFile :: IO (Either TagSearchOutcome [String])
  loadTagsFromFile = fmap (fmap tokensFromTags) tagsContent
  
  tokensFromTags :: String -> [String]
  tokensFromTags = filter validTokens . L.nub . tokenLocations
    where
      tokenLocations = map (token . T.splitOn "\t" . T.pack) . lines
      token = T.unpack . head
  
  validTokens :: String -> Bool
  validTokens = not . L.isPrefixOf "!_TAG"
  
  tagsContent :: IO (Either TagSearchOutcome String)
  tagsContent = D.findFile possibleTagsFileDirectories "tags" >>= eitherReadFile
  
  eitherReadFile :: Maybe String -> IO (Either TagSearchOutcome String)
  eitherReadFile Nothing = return $ Left $ TagsFileNotFound possibleTagsFileDirectories
  eitherReadFile (Just path) = BF.first IOError <$> safeReadFile path
  
  possibleTagsFileDirectories :: [String]
  possibleTagsFileDirectories = [".git", "tmp", "."]
  