diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for implicit-hie
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -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).
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -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
diff --git a/implicit-hie.cabal b/implicit-hie.cabal
new file mode 100644
--- /dev/null
+++ b/implicit-hie.cabal
@@ -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
diff --git a/src/Hie/Cabal/Parser.hs b/src/Hie/Cabal/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Hie/Cabal/Parser.hs
@@ -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))
diff --git a/src/Hie/Locate.hs b/src/Hie/Locate.hs
new file mode 100644
--- /dev/null
+++ b/src/Hie/Locate.hs
@@ -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
diff --git a/src/Hie/Yaml.hs b/src/Hie/Yaml.hs
new file mode 100644
--- /dev/null
+++ b/src/Hie/Yaml.hs
@@ -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 <> "\""
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -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\
+  \"
