implicit-hie (empty) → 0.1.0.0
raw patch · 10 files changed
+747/−0 lines, 10 filesdep +attoparsecdep +basedep +directorysetup-changed
Dependencies added: attoparsec, base, directory, filepath, filepattern, hspec, hspec-attoparsec, implicit-hie, text, transformers, yaml
Files
- ChangeLog.md +3/−0
- LICENSE +30/−0
- README.md +69/−0
- Setup.hs +2/−0
- app/Main.hs +37/−0
- implicit-hie.cabal +96/−0
- src/Hie/Cabal/Parser.hs +188/−0
- src/Hie/Locate.hs +85/−0
- src/Hie/Yaml.hs +64/−0
- test/Spec.hs +173/−0
+ ChangeLog.md view
@@ -0,0 +1,3 @@+# Changelog for implicit-hie++## Unreleased changes
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Avi Dessauer (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Avi Dessauer nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,69 @@+# implicit-hie+```bash+cd your-stack-or-cabal-package+gen-hie > hie.yaml+```+`gen-hie` should be run the root of a cabal or stack project.+The config type (cabal or stack) is determined by the existence of+`dist-newstyle`, `.stack-work`, `stack.yaml`, if none are found the default is cabal.++# Cabal Multi project example+```bash+❯ git clone https://github.com/well-typed/optics.git+❯ cd optics+❯ gen-hie+cradle:+ cabal:+ - path: "indexed-profunctors/src"+ component: "lib:indexed-profunctors"++ - path: "optics-th/src"+ component: "lib:optics-th"++ - path: "optics-th/tests"+ component: "optics-th:test:optics-th-tests"++ - path: "optics-vl/src"+ component: "lib:optics-vl"++ - path: "codegen/./Subtypes.hs"+ component: "optics-codegen:exe:optics-codegen-subtypes"++ - path: "optics-core/src"+ component: "lib:optics-core"++ - path: "optics-sop/src"+ component: "lib:optics-sop"++ - path: "optics-extra/src"+ component: "lib:optics-extra"++ - path: "template-haskell-optics/src"+ component: "lib:template-haskell-optics"++ - path: "optics/src"+ component: "lib:optics"++ - path: "optics/tests"+ component: "optics:test:optics-tests"++ - path: "metametapost/src/Cli.hs"+ component: "metametapost:exe:metametapost-optics"++```++## Features++All common Cabal and Stack configurations should just work.+If you use more advanced features, the generated config may not be complete.++- [x] multi component cabal, stack projects+- [x] multiple executables under a single path+- [x] multiple paths provided to `hs-source-dirs`+- [x] lookup nested packages in `cabal.project` or `stack.yaml`+- [x] Handle Exe and Bench `other-modules`+- [ ] common stanzas++### Work, Twitter+- I'm currently looking for work as a Haskell or Rust developer. I can be reached via email or a twitter message.+- Follow me on twitter [@AviDessauer](https://twitter.com/AviDessauer).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE MultiWayIf #-}++module Main where++import Control.Monad+import Control.Monad.Trans.Maybe+import Data.Attoparsec.Text+import Data.List+import Data.Maybe+import qualified Data.Text as T+import qualified Data.Text.IO as T+import Hie.Cabal.Parser+import Hie.Locate+import Hie.Yaml+import System.Directory+import System.Directory.Internal+import System.FilePath.Posix++main :: IO ()+main = do+ pwd <- getCurrentDirectory+ files <- listDirectory pwd+ let name =+ if | any (("dist-newstyle" ==) . takeFileName) files -> "cabal"+ | any ((".stack-work" ==) . takeFileName) files -> "stack"+ | any (("cabal.project" ==) . takeFileName) files -> "cabal"+ | any (("stack.yaml" ==) . takeFileName) files -> "stack"+ | otherwise -> "cabal"+ cfs <- runMaybeT $ case name of+ "cabal" -> cabalPkgs pwd+ _ -> stackYamlPkgs pwd+ when (null cfs) $ error $+ "No .cabal files found under"+ <> pwd+ <> "\n You may need to run stack build."+ pkgs <- catMaybes <$> mapM (nestedPkg pwd) (concat cfs)+ putStr <$> hieYaml name $ fmtPkgs name pkgs
+ implicit-hie.cabal view
@@ -0,0 +1,96 @@+cabal-version: 2.0++-- This file has been generated from package.yaml by hpack version 0.33.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 18f92037a7863d121ac45e847f7dc6177adf0ebc7951dfa1588340f86e64456b++name: implicit-hie+version: 0.1.0.0+description: Auto generate a stack or cabal multi component hie.yaml file+category: Development, Tools, Hie, HLS+synopsis: Auto generate hie-bios cradles & hie.yaml+homepage: https://github.com/Avi-D-coder/implicit-hie#readme+bug-reports: https://github.com/Avi-D-coder/implicit-hie/issues+author: Avi Dessauer+maintainer: avi.the.coder@gmail.com+copyright: 2020+license: BSD3+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md+ ChangeLog.md++source-repository head+ type: git+ location: https://github.com/Avi-D-coder/implicit-hie++library+ exposed-modules:+ Hie.Cabal.Parser+ Hie.Locate+ Hie.Yaml+ other-modules:+ Paths_implicit_hie+ autogen-modules:+ Paths_implicit_hie+ hs-source-dirs:+ src+ ghc-options: -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-name-shadowing -fwarn-redundant-constraints+ build-depends:+ attoparsec >= 0.13+ , base >=4.7 && <5+ , directory >= 1.3+ , filepath >= 1.4+ , filepattern >= 0.1+ , text >= 1.2+ , transformers >= 0.5+ , yaml >= 0.5+ default-language: Haskell2010++executable gen-hie+ main-is: Main.hs+ other-modules:+ Paths_implicit_hie+ autogen-modules:+ Paths_implicit_hie+ hs-source-dirs:+ app+ ghc-options: -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-name-shadowing -fwarn-redundant-constraints -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ attoparsec+ , base >=4.7 && <5+ , directory+ , filepath+ , filepattern+ , implicit-hie+ , text+ , transformers+ , yaml+ default-language: Haskell2010++test-suite implicit-hie-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Paths_implicit_hie+ autogen-modules:+ Paths_implicit_hie+ hs-source-dirs:+ test+ ghc-options: -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-name-shadowing -fwarn-redundant-constraints -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ attoparsec+ , base >=4.7 && <5+ , directory+ , filepath+ , filepattern+ , hspec+ , hspec-attoparsec+ , implicit-hie+ , text+ , transformers+ , yaml+ default-language: Haskell2010
+ src/Hie/Cabal/Parser.hs view
@@ -0,0 +1,188 @@+{-# LANGUAGE OverloadedStrings #-}++module Hie.Cabal.Parser where++import Control.Applicative+import Control.Monad+import Data.Attoparsec.Text+import Data.Char+import Data.Maybe+import Data.Text (Text)+import qualified Data.Text as T+import System.FilePath.Posix ((</>))++type Name = Text++type Path = Text++type Indent = Int++data Package = Package Name [Component]+ deriving (Show, Eq, Ord)++data CompType = Lib | Exe | Test | Bench+ deriving (Show, Eq, Ord)++data Component+ = Comp CompType Name Path+ deriving (Show, Eq, Ord)++parsePackage' :: Text -> Either String Package+parsePackage' = parseOnly parsePackage++parsePackage :: Parser Package+parsePackage =+ ( do+ n <- field 0 "name" $ const parseString+ (Package _ t) <- parsePackage+ pure $ Package n t+ )+ <|> ( do+ h <- parseComponent 0+ (Package n t) <- parsePackage+ pure $ Package n (h <> t)+ )+ <|> (skipToNextLine >> parsePackage)+ <|> pure (Package "" [])++componentHeader :: Indent -> Text -> Parser Name+componentHeader i t = do+ _ <- indent i+ _ <- asciiCI t+ skipMany tabOrSpace+ n <- parseString <|> pure ""+ skipToNextLine+ pure n++parseComponent :: Indent -> Parser [Component]+parseComponent i =+ parseExe i+ <|> parseLib i+ <|> parseBench i+ <|> parseTestSuite i++parseLib :: Indent -> Parser [Component]+parseLib i = parseSec i "library" $ Comp Lib++parseTestSuite :: Indent -> Parser [Component]+parseTestSuite i = parseSec i "test-suite" $ Comp Test++parseExe :: Indent -> Parser [Component]+parseExe = parseSecMain (Comp Exe) "executable"++parseBench :: Indent -> Parser [Component]+parseBench = parseSecMain (Comp Bench) "benchmark"++parseSecMain :: (Name -> Path -> Component) -> Text -> Indent -> Parser [Component]+parseSecMain c s i = do+ n <- componentHeader i s+ p <- pathMain (i + 1) ["./"] "" [] []+ pure $ map (c n) p++parseQuoted :: Parser Text+parseQuoted = do+ q <- char '"' <|> char '\''+ s <- takeTill (== q)+ _ <- char q+ pure s++parseString :: Parser Name+parseString = parseQuoted <|> unqualName++unqualName :: Parser Text+unqualName = takeWhile1 (not . (\c -> isSpace c || c == ','))++parseList :: Indent -> Parser [Text]+parseList i = items <|> (emptyOrComLine >> indent i >> items)+ where+ items = do+ skipMany tabOrSpace+ h <- parseString+ skipMany tabOrSpace+ skipMany (char ',')+ t <-+ items+ <|> (skipToNextLine >> indent i >> parseList i)+ <|> pure []+ pure $ h : t++pathMain :: Indent -> [Text] -> Text -> [Text] -> [Text] -> Parser [Text]+pathMain i p m o a =+ (hsSourceDir i >>= (\p' -> pathMain i p' m o a))+ <|> (field i "main-is" (const parseString) >>= (\m' -> pathMain i p m' o a))+ <|> (field i "other-modules" parseList >>= flip (pathMain i p m) a)+ <|> (field i "autogen-modules" parseList >>= pathMain i p m o)+ <|> (skipBlockLine i >> pathMain i p m o a)+ <|> pure+ ( map (<//> m) p+ <> [ p' <//> (o' <> ".hs")+ | p' <- p,+ o' <- filter (`notElem` a) o+ ]+ )++(<//>) :: Text -> Text -> Text+a <//> b = T.pack (T.unpack a </> T.unpack b)++infixr 5 <//>++parseSec :: Indent -> Text -> (Name -> Path -> Component) -> Parser [Component]+parseSec i compType compCon = do+ n <- componentHeader i compType+ p <- extractPath (i + 1) []+ let p' = if null p then ["./"] else p+ pure $ map (compCon n) p'++skipToNextLine :: Parser ()+skipToNextLine = skipWhile (not . isEndOfLine) >> endOfLine++skipBlock :: Indent -> Parser ()+skipBlock i = skipMany $ skipBlockLine i++comment :: Parser ()+comment = skipMany tabOrSpace >> "--" >> skipToNextLine++skipBlockLine :: Indent -> Parser ()+skipBlockLine i = (indent i >> skipToNextLine) <|> emptyOrComLine++emptyOrComLine :: Parser ()+emptyOrComLine = skipMany tabOrSpace >> endOfLine <|> comment++tabOrSpace :: Parser Char+tabOrSpace = char ' ' <|> char '\t'++hsSourceDir :: Indent -> Parser [Text]+hsSourceDir i = field i "hs-source-dirs" parseList++-- field :: Indent -> Text -> Parser Text+field ::+ Indent ->+ Text ->+ (Indent -> Parser a) ->+ Parser a+field i f p =+ do+ i' <- indent i+ _ <- asciiCI f+ skipSpace+ _ <- char ':'+ skipSpace+ p' <- p $ i' + 1+ skipToNextLine+ pure p'++extractPath :: Indent -> [Path] -> Parser [Path]+extractPath i ps =+ (field i "hs-source-dirs" parseList >>= (\p -> extractPath i $ ps <> p))+ <|> (skipBlockLine i >> extractPath i ps)+ <|> (comment >> extractPath i ps)+ <|> pure ps++-- | Skip at least n spaces+indent :: Indent -> Parser Int+indent i = do+ c <- length <$> many' tabOrSpace+ if c >= i then pure c else fail "insufficient indent"++extractPkgs :: Parser [T.Text]+extractPkgs = join . catMaybes <$> many' (Just <$> field 0 "packages" parseList <|> (skipToNextLine >> pure Nothing))
+ src/Hie/Locate.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Hie.Locate+ ( nestedPkg,+ stackYamlPkgs,+ cabalPkgs,+ )+where++import Control.Applicative+import Control.Exception+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Maybe+import Data.Attoparsec.Text (parseOnly)+import Data.Either+import Data.List+import Data.Maybe+import qualified Data.Text as T+import qualified Data.Text.IO as T+import Data.Yaml+import GHC.Generics+import Hie.Cabal.Parser+import Hie.Yaml+import System.Directory+import System.FilePath.Posix+import System.FilePattern.Directory (getDirectoryFiles)++newtype Pkgs = Pkgs [FilePath]+ deriving (Eq, Ord)++instance FromJSON Pkgs where+ parseJSON (Object v) = Pkgs <$> v .: "packages"+ parseJSON _ = fail "could not read packages from stack.yaml"++stackYamlPkgs :: FilePath -> MaybeT IO [FilePath]+stackYamlPkgs p = liftIO $+ decodeFileEither (p </> "stack.yaml") >>= \case+ Right (Pkgs f) ->+ liftIO $+ map (p </>)+ <$> getDirectoryFiles p (map (</> "*.cabal") f)+ Left e -> fail $ show e++cabalPkgs :: FilePath -> MaybeT IO [FilePath]+cabalPkgs p = do+ cp <- cabalP "cabal.project"+ cl <- cabalP "cabal.project.local"+ case concat . rights $ map (parseOnly extractPkgs) $ rights [cp, cl] of+ [] -> liftIO (cfs p) >>= \case+ [] -> fail "no cabal files found"+ h : _ -> pure [p </> h]+ xs -> do+ cd <- liftIO $ map (p </>) <$> getDirectoryFiles p (map (matchDirs . T.unpack) xs)+ cf <-+ liftIO $+ mapM (\p -> if takeExtension p == ".cabal" then pure [p] else cfs p) cd+ pure $ concat cf+ where+ cabalP n = liftIO (try $ T.readFile $ p </> n :: IO (Either IOException T.Text))+ cfs d = filter ((".cabal" ==) . takeExtension) <$> listDirectory d+ matchDirs "." = "./*.cabal"+ matchDirs p | "/" `isSuffixOf` p || p == "." = p <> "*.cabal"+ matchDirs p | "*" `isSuffixOf` p || takeExtension p == "" = p <> "/*.cabal"+ matchDirs p = p++nestedPkg :: FilePath -> FilePath -> IO (Maybe Package)+nestedPkg parrent child = do+ f' <- T.readFile child+ case parsePackage' f' of+ Right (Package n cs) -> do+ let dir =+ fromJust $ stripPrefix (splitDirectories parrent)+ $ splitDirectories+ $ fst (splitFileName child)+ pkg =+ Package n $+ map+ ( \(Comp t n p) ->+ Comp t n (T.pack $ joinPath dir </> T.unpack p)+ )+ cs+ pure $ Just pkg+ _ -> pure Nothing
+ src/Hie/Yaml.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE OverloadedStrings #-}++module Hie.Yaml+ ( hieYaml,+ fmtComponent,+ fmtPkgs,+ cabalComponent,+ stackComponent,+ )+where++import qualified Data.Text as T+import Hie.Cabal.Parser++hieYaml :: String -> String -> String+hieYaml sOrC pkgs =+ "cradle:\n"+ <> indent'+ (sOrC <> ":\n" <> indent' pkgs)++indent' :: String -> String+indent' =+ unlines+ . map+ ( \l -> case l of+ "" -> ""+ _ -> " " <> l+ )+ . lines++cabalComponent :: Name -> Component -> (FilePath, String)+cabalComponent n (Comp Lib "" p) = (T.unpack p, T.unpack $ "lib:" <> n)+cabalComponent n (Comp Lib cn p) = (T.unpack p, T.unpack $ n <> ":lib:" <> cn)+cabalComponent n (Comp Exe cn p) = (T.unpack p, T.unpack $ n <> ":exe:" <> cn)+cabalComponent n (Comp Bench cn p) = (T.unpack p, T.unpack $ n <> ":bench:" <> cn)+cabalComponent n (Comp Test cn p) = (T.unpack p, T.unpack $ n <> ":test:" <> cn)++stackComponent :: Name -> Component -> (FilePath, String)+stackComponent n (Comp Lib "" p) = (T.unpack p, T.unpack $ n <> ":lib")+stackComponent n (Comp Lib cn p) = (T.unpack p, T.unpack $ n <> ":lib:" <> cn)+stackComponent n (Comp Exe cn p) = (T.unpack p, T.unpack $ n <> ":exe:" <> cn)+stackComponent n (Comp Bench cn p) = (T.unpack p, T.unpack $ n <> ":bench:" <> cn)+stackComponent n (Comp Test cn p) = (T.unpack p, T.unpack $ n <> ":test:" <> cn)++fmtComponent :: (FilePath, String) -> String+fmtComponent (p, c) =+ "- path: "+ <> dQuote p+ <> "\n "+ <> "component: "+ <> dQuote c++dropLast :: [a] -> [a]+dropLast l = take (length l - 1) l++fmtPkgs :: String -> [Package] -> String+fmtPkgs sOrC pkgs = dropLast $ unlines l+ where+ comp = if sOrC == "cabal" then cabalComponent else stackComponent+ f (Package n cs) = map ((<> "\n") . fmtComponent . comp n) cs+ l = concatMap f pkgs++dQuote :: String -> String+dQuote t = '"' : t <> "\""
+ test/Spec.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE OverloadedStrings #-}++import Data.Attoparsec.Text+import qualified Data.Text as T+import Data.Text (Text)+import qualified Data.Text.IO as T+import Hie.Cabal.Parser+import Hie.Yaml+import Test.Hspec+import Test.Hspec.Attoparsec++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "Should Succeed"+ $ it "successfully parses executable section"+ $ exeSection ~> parseExe 0+ `shouldParse` [Comp Exe "gen-hie" "app/Main.hs"]+ describe "Should Succeed"+ $ it "successfully parses test section"+ $ testSection ~> parseTestSuite 0+ `shouldParse` [Comp Test "implicit-hie-test" "test"]+ describe "Should Succeed"+ $ it "successfully parses library section"+ $ libSection ~> parseLib 0+ `shouldParse` [Comp Lib "" "src"]+ describe "Should Succeed"+ $ it "successfully parses library section with 2 hs-source-dirs"+ $ libSection2 ~> parseLib 0+ `shouldParse` [Comp Lib "" "src", Comp Lib "" "src2"]+ describe "Should Succeed"+ $ it "successfully parses library section with 2 paths under hs-source-dirs"+ $ libSection3 ~> parseLib 0+ `shouldParse` [Comp Lib "" "src", Comp Lib "" "src2"]+ describe "Should Succeed"+ $ it "successfully parses bench section"+ $ do+ bs <- T.readFile "test/benchSection"+ bs ~> parseBench 0+ `shouldParse` [Comp Bench "folds" "benchmarks/folds.hs"]+ describe "Should Succeed"+ $ it "successfully parses package"+ $ do+ cf <- T.readFile "implicit-hie.cabal"+ cf ~> parsePackage+ `shouldParse` Package+ "implicit-hie"+ [ Comp Lib "" "src",+ Comp Exe "gen-hie" "app/Main.hs",+ Comp Test "implicit-hie-test" "test"+ ]+ describe "Should Succeed"+ $ it+ "skips to end of block section"+ $ let r = "test\n"+ in (libSection <> r) ~?> parseLib 0+ `leavesUnconsumed` r+ describe "Should Succeed"+ $ it "successfully generates stack hie.yaml"+ $ do+ sf <- readFile "test/stackHie.yaml"+ cf <- T.readFile "implicit-hie.cabal"+ (hieYaml "stack" . fmtPkgs "stack" . (: []) <$> parseOnly parsePackage cf)+ `shouldBe` Right sf+ describe "Should Succeed"+ $ it "successfully generates cabal hie.yaml for haskell-language-server"+ $ do+ f <- T.readFile "test/haskell-language-server-cabal"+ o <- readFile "test/hie.yaml.cbl"+ (hieYaml "cabal" . fmtPkgs "cabal" . (: []) <$> parseOnly parsePackage f)+ `shouldBe` Right o+ describe "Should Succeed"+ $ it "successfully parses comma list"+ $ ("one, two" :: Text) ~> parseList 1 `shouldParse` ["one", "two"]+ describe "Should Succeed"+ $ it "successfully parses newline list"+ $ ("one\n two \n three3" :: Text) ~> parseList 1+ `shouldParse` ["one", "two", "three3"]+ describe "Should Succeed"+ $ it "successfully parses newline comma list"+ $ ("one\n two, three3" :: Text) ~> parseList 1+ `shouldParse` ["one", "two", "three3"]+ describe "Should Succeed"+ $ it "quoted list"+ $ ("\"one\"\n two\n three3" :: Text) ~> parseList 1+ `shouldParse` ["one", "two", "three3"]++exeSection :: Text+exeSection =+ "executable gen-hie\n\+ \ other-modules:\n\+ \ Paths_implicit_hie\n\+ \ autogen-modules:\n\+ \ Paths_implicit_hie\n\+ \ hs-source-dirs:\n\+ \ app\n\+ \ ghc-options: -O2\n\+ \ main-is: Main.hs \n"++testSection :: Text+testSection =+ "test-suite implicit-hie-test\n\+ \ type: exitcode-stdio-1.0\n\+ \ other-modules:\n\+ \ Paths_implicit_hie\n\+ \ hs-source-dirs:\n\+ \ test\n\+ \ ghc-options: -fspecialize-aggressively -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-name-shadowing -fwarn-redundant-constraints -threaded -rtsopts -with-rtsopts=-N\n\+ \ main-is: Spec.hs\n\+ \ build-depends:\n\+ \ attoparsec\n\+ \ , base >=4.7 && <5\n\+ \ , hspec\n\+ \ , hspec-attoparsec\n\+ \ , implicit-hie\n\+ \ , text\n\+ \ default-language: Haskell2010\n"++libSection :: Text+libSection =+ "library\n\+ \ exposed-modules:\n\+ \ Lib\n\+ \ other-modules:\n\+ \ Paths_implicit_hie\n\+ \ hs-source-dirs:\n\+ \ src\n\+ \ ghc-options: -fspecialize-aggressively -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-name-shadowing -fwarn-redundant-constraints\n\+ \ build-depends:\n\+ \ attoparsec\n\+ \ , base >=4.7 && <5\n\+ \ , text\n\+ \ default-language: Haskell2010\n\+ \"++libSection2 :: Text+libSection2 =+ "library\n\+ \ exposed-modules:\n\+ \ Lib\n\+ \ other-modules:\n\+ \ Paths_implicit_hie\n\+ \ hs-source-dirs:\n\+ \ src\n\+ \ hs-source-dirs:\n\+ \ src2\n\+ \ ghc-options: -fspecialize-aggressively -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-name-shadowing -fwarn-redundant-constraints\n\+ \ build-depends:\n\+ \ attoparsec\n\+ \ , base >=4.7 && <5\n\+ \ , text\n\+ \ default-language: Haskell2010\n\+ \"++libSection3 :: Text+libSection3 =+ "library\n\+ \ exposed-modules:\n\+ \ Lib\n\+ \ other-modules:\n\+ \ Paths_implicit_hie\n\+ \ hs-source-dirs:\n\+ \ src,\n\+ \ src2\n\+ \ ghc-options: -fspecialize-aggressively -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-name-shadowing -fwarn-redundant-constraints\n\+ \ build-depends:\n\+ \ attoparsec\n\+ \ , base >=4.7 && <5\n\+ \ , text\n\+ \ default-language: Haskell2010\n\+ \"