packages feed

hsmodetweaks-0.1.0.0: app/Main.hs

{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}

module Main where
import           Data.List          (nub)
import qualified Data.Map.Strict    as Map
import qualified Data.Set           as Set
import qualified Data.Text          as T
import           GHC.Base           (String)
import           Hpack.Config       (Executable, Library, Package (..),
                                     Section (..), readPackageConfig)
import           Protolude
import           System.Directory   (canonicalizePath, getAppUserDataDirectory)
import           System.Environment (getArgs)
import           System.IO.Error    (userError)

genLocals :: FilePath -> Package -> [(FilePath, Text)]
genLocals f = map (second
                   $ (prologue <>)
                   . (<> "\n")
                   . parens
                   . parens
                   . ("haskell-mode " <>)
                   . parens
                   . ("intero-targets " <>)
                   . T.unwords
                   . map show
                   . Set.toList
                  )
              . extractTargets f
  where
    parens :: Text -> Text
    parens = ("(" <>) . (<> ")")

    prologue :: Text
    prologue = ";;; Directory Local Variables\n;;; For more information see (info \"(emacs) Directory Variables\")\n\n"

-- FIX these are all terrible names
extractTargets :: FilePath -> Package -> [(FilePath, Set Text)]
extractTargets root Package{..}
  = collapse
    [ex "exe" packageExecutables
    ,ex "test" packageTests
    ,ex "bench" packageBenchmarks
    , lib]
  where
    lib = f ["lib"] <$> maybeToList packageLibrary

    ex :: String -> Map String (Section Executable) -> [[(FilePath, [Text])]]
    ex ty = map (\(target,section) -> f [ty,target] section) . Map.toList

    f :: [String] -> Section a -> [(FilePath, [Text])]
    f pieces Section{..} =
      map (\name -> (root <> "/" <> name <> "/.dir-locals.el"
                   ,lib <> [mkTarget pieces])) sectionSourceDirs
      where lib = const (mkTarget ["lib"]) <$> maybeToList packageLibrary
    collapse = Map.toList . Map.fromListWith Set.intersection
             . map (second Set.fromList) . concat .  concat

    mkTarget = T.intercalate ":" . map T.pack . (packageName:)

abort :: String -> IO ()
abort = ioError . userError

main :: IO ()
main = getArgs >>= \case
  [f1] -> do
    c <- canonicalizePath f1
    getAppUserDataDirectory "hpack"
      >>= (`readPackageConfig` (c <> "/package.yaml"))
      >>= either abort (writeFiles c . fst)
  x -> abort $ "exactly one argument needed, got " <> show x

  where
    writeFiles f = mapM_ (uncurry writeFile) . genLocals f
--    writeFiles f = print . extractTargets f