diff --git a/library/Neovim/BuildTool.hs b/library/Neovim/BuildTool.hs
new file mode 100644
--- /dev/null
+++ b/library/Neovim/BuildTool.hs
@@ -0,0 +1,146 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE DeriveGeneric #-}
+{- |
+Module      :  Neovim.BuildTool
+Description :  Utilities and types to manage build tool dependent things
+Copyright   :  (c) Sebastian Witte
+License     :  Apache-2.0
+
+Maintainer  :  woozletoff@gmail.com
+Stability   :  experimental
+Portability :  GHC
+
+-}
+module Neovim.BuildTool
+    where
+
+import Neovim
+import Data.List (isSuffixOf)
+import Control.Monad.IO.Class
+import GHC.Generics
+import Data.Yaml
+import System.Directory
+import System.FilePath (takeDirectory, (</>))
+
+data BuildTool
+    = Stack
+    | Cabal CabalType
+    | Shake
+    | Make
+    | Cmake
+    | Ninja
+    | Scons
+    | Custom
+    deriving (Show, Read, Eq, Ord, Generic)
+
+instance ToJSON BuildTool
+instance FromJSON BuildTool
+
+data CabalType
+    = Plain
+    | Sandbox
+    | NewBuild
+    deriving (Show, Read, Eq, Ord, Enum, Generic)
+
+instance ToJSON CabalType
+instance FromJSON CabalType
+
+newtype Directory = Directory { getDirectory :: FilePath }
+    deriving (Show, Eq, Ord)
+
+
+-- | If the monadic boolean predicate returns true, wrap the given object in a
+-- 'Just' constructor, otherwise return 'Nothing'.
+partialM :: Monad m => (a -> m Bool) -> a -> m (Maybe a)
+partialM fp a = fp a >>= \case
+    True -> return (Just a)
+    False -> return Nothing
+
+-- | Create 'Just' a 'Directory' value if the given filepath exists and
+-- otherwise return 'Nothing'. This method does not create an actual directory
+-- on your file system.
+mkDirectory :: MonadIO io => FilePath -> io (Maybe Directory)
+mkDirectory mdir =
+    fmap Directory <$> partialM (liftIO . doesDirectoryExist) mdir
+
+newtype File = File { getFile :: FilePath }
+    deriving (Show, Eq, Ord)
+
+-- | Create 'Just' a 'File' value if the given file exists and is not a
+-- directory. Otherwise return 'Nothing'. This function does not alter your
+-- filesystem.
+mkFile :: MonadIO io => Maybe Directory -> FilePath -> io (Maybe File)
+mkFile mdir mfile =
+    let f = maybe mfile (\d -> getDirectory d </> mfile) mdir
+    in fmap File <$> partialM (liftIO . doesFileExist) f
+
+-- | Calculate the list of all parent directories for the given directory. This
+-- function also returns the initially specified directory.
+thisAndParentDirectories :: Directory -> [Directory]
+thisAndParentDirectories dir
+    | parentDir == dir = [dir]
+    | otherwise = dir : thisAndParentDirectories parentDir
+  where
+    parentDir = Directory .  takeDirectory $ getDirectory dir
+
+
+-- | Given a list of build tool identifier functions, apply these to all the
+-- given directories and return the value of the first function that returns a
+-- 'BuildTool' value or 'Nothing' if no function ever returns a 'BuildTool'.
+-- The identifier functions and directories are tried in the order as supplied
+-- to this function.
+determineProjectSettings
+    :: MonadIO io
+    => [Directory -> io (Maybe BuildTool)]
+    -> [Directory]
+    -> io (Maybe (BuildTool, Directory))
+determineProjectSettings identifiers = go identifiers
+  where
+    go _ []             = return Nothing
+    go [] (_:ps)        = go identifiers ps
+    go (i:is) pps@(p:_) = i p >>= \case
+                        Just buildTool -> return (Just (buildTool, p))
+                        Nothing -> go is pps
+
+
+-- | This list contains some build tool identifier functions for usual setups.
+defaultProjectIdentifiers :: MonadIO io => [Directory -> io (Maybe BuildTool)]
+defaultProjectIdentifiers =
+    [ maybeCabalSandbox, maybeStack, maybeCabal ]
+
+-- | Same as 'determineProjectSettings' 'defaultProjetIdentifiers'.
+guessProjectSettings :: MonadIO io
+                     => [Directory]
+                     -> io (Maybe (BuildTool, Directory))
+guessProjectSettings = determineProjectSettings defaultProjectIdentifiers
+
+
+-- | Check if directory contains a @stack.yaml@ file and return 'Just' 'Stack'
+-- in this case.
+maybeStack :: MonadIO io => Directory -> io (Maybe BuildTool)
+maybeStack d = fmap (const Stack) <$> mkFile (Just d) "stack.yaml"
+
+
+-- | Check if the directory contains a @cabal.sandbox.config@ file and return
+-- 'Just' ('Cabal' 'Sandbox') in that case.
+maybeCabalSandbox :: MonadIO io => Directory -> io (Maybe BuildTool)
+maybeCabalSandbox d = fmap (const (Cabal Sandbox))
+    <$> mkFile (Just d) "cabal.sandbox.config"
+
+
+-- | Check if the directory contains a cabal file and return 'Just' ('Cabal'
+-- 'Plain') if present.
+maybeCabal :: MonadIO io => Directory -> io (Maybe BuildTool)
+maybeCabal d = do
+    ls <-  liftIO . getDirectoryContents $ getDirectory d
+    go $ filter (".cabal" `isSuffixOf`)ls
+  where
+      go [] = return Nothing
+      go (f:fs) = mkFile (Just d) f >>= \case
+                    Nothing -> go fs
+                    Just _ ->
+                        -- TODO if cabal version >= 1.24(?), use NewBuild here?
+                        return $ Just (Cabal Plain)
+
+
+
diff --git a/library/Neovim/User/Choice.hs b/library/Neovim/User/Choice.hs
--- a/library/Neovim/User/Choice.hs
+++ b/library/Neovim/User/Choice.hs
@@ -26,7 +26,7 @@
 oneOf :: Pretty a => [a] -> Neovim r st (Maybe a)
 oneOf cs = fmap (\i -> cs !! (i-1)) <$> askForIndex (zipWith mkChoice cs [1..])
   where
-    mkChoice c i = toObject $ int i P.<> text "." <+> pretty c
+    mkChoice c i = docToObject $ int i P.<> text "." <+> pretty c
 
 
 -- | Ask user for a choice and 'Maybe' return the index of that choice
diff --git a/library/Neovim/User/Input.hs b/library/Neovim/User/Input.hs
--- a/library/Neovim/User/Input.hs
+++ b/library/Neovim/User/Input.hs
@@ -23,7 +23,7 @@
 input :: String -- ^ Message to display
       -> Maybe String -- ^ Input fiiled in
       -> Maybe String -- ^ Completion mode
-      -> Neovim r st (Either Object Object)
+      -> Neovim r st (Either NeovimException Object)
 input message mPrefilled mCompletion = vim_call_function "input" $
     (message <> " ")
     +: maybe "" id mPrefilled
diff --git a/nvim-hs-contrib.cabal b/nvim-hs-contrib.cabal
--- a/nvim-hs-contrib.cabal
+++ b/nvim-hs-contrib.cabal
@@ -1,5 +1,5 @@
 name:                nvim-hs-contrib
-version:             0.1.0
+version:             0.2.0
 synopsis:            Haskell plugin backend for neovim
 description:
   Library for nvim-hs.
@@ -18,29 +18,25 @@
     location:        https://github.com/neovimhaskell/nvim-hs
 
 library
-  exposed-modules:      Neovim.User.Choice
+  exposed-modules:      Neovim.BuildTool
+                      , Neovim.User.Choice
                       , Neovim.User.Input
 
   -- other-extensions:
   build-depends:        base >=4.6 && < 5
-                      , nvim-hs >= 0.1.0
+                      , nvim-hs >= 0.2.0
                       , ansi-wl-pprint
                       , bytestring
                       , data-default
                       , directory
                       , exceptions
+                      , filepath
                       , messagepack >= 0.4
                       , mtl >= 2.2.1 && < 2.3
-                      , parsec >= 3.1.9
-                      , process
-                      , resourcet
-                      , setenv >= 0.1.1.3
-                      , stm
                       , text
                       , time
-                      , transformers
-                      , transformers-base
                       , utf8-string
+                      , yaml
 
   hs-source-dirs:       library
   default-language:     Haskell2010
@@ -58,23 +54,6 @@
                       , hspec ==2.*
                       , hspec-discover
                       , QuickCheck >=2.6
-
-                      , ansi-wl-pprint
-                      , bytestring
-                      , data-default
-                      , exceptions
-                      , messagepack >= 0.4
-                      , mtl >= 2.2.1 && < 2.3
-                      , parsec >= 3.1.9
-                      , process
-                      , resourcet
-                      , setenv >= 0.1.1.3
-                      , stm
-                      , text
-                      , time
-                      , transformers
-                      , transformers-base
-                      , utf8-string
 
   ghc-options:          -threaded -rtsopts -with-rtsopts=-N
 
