diff --git a/Language/Haskell/Modules.hs b/Language/Haskell/Modules.hs
--- a/Language/Haskell/Modules.hs
+++ b/Language/Haskell/Modules.hs
@@ -69,17 +69,10 @@
 --
 -- * Split a module where one of the result modules needs to import the instances:
 --
---   @runCleanT $
+--  @runCleanT $
 --      putModule (ModuleName \"Main\") >>
 --      extraImport (ModuleName \"Main.GetPasteById\") (ModuleName \"Main.Instances\") >>
 --      splitModuleDecls \"Main.hs\"@
---
--- * Use 'mergeModules' to rename a module:
---
---   @findHsModules [\"Language\", \"Tests.hs\", \"Tests\"] >>= \\ modules -> runCleanT $
---      mapM putModule modules >>
---      mergeModules [ModuleName \"Language.Haskell.Modules.Util.Symbols\"]
---                   (ModuleName \"Language.Haskell.Modules.Symbols\")@
 module Language.Haskell.Modules
     (
     -- * Entry points
diff --git a/Language/Haskell/Modules/Fold.hs b/Language/Haskell/Modules/Fold.hs
--- a/Language/Haskell/Modules/Fold.hs
+++ b/Language/Haskell/Modules/Fold.hs
@@ -24,7 +24,7 @@
 import Language.Haskell.Exts.Comments (Comment(..))
 import Language.Haskell.Exts.SrcLoc (SrcLoc(..), SrcSpan(..), SrcSpanInfo(..))
 import Language.Haskell.Modules.ModuVerse (ModuleInfo(ModuleInfo))
-import Language.Haskell.Modules.SrcLoc (endLoc, HasSpanInfo(..), increaseSrcLoc, srcLoc, srcPairText)
+import Language.Haskell.Modules.Util.SrcLoc (endLoc, HasSpanInfo(..), increaseSrcLoc, srcLoc, srcPairText)
 
 --type Module = A.Module SrcSpanInfo
 --type ModuleHead = A.ModuleHead SrcSpanInfo
diff --git a/Language/Haskell/Modules/Imports.hs b/Language/Haskell/Modules/Imports.hs
--- a/Language/Haskell/Modules/Imports.hs
+++ b/Language/Haskell/Modules/Imports.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE PackageImports, ScopedTypeVariables, StandaloneDeriving, TupleSections #-}
+{-# LANGUAGE CPP, PackageImports, ScopedTypeVariables, StandaloneDeriving, TupleSections #-}
 {-# OPTIONS_GHC -Wall #-}
 module Language.Haskell.Modules.Imports
     ( cleanImports
@@ -25,15 +25,19 @@
 import Language.Haskell.Modules.Fold (foldDecls, foldExports, foldHeader, foldImports)
 import Language.Haskell.Modules.ModuVerse (findModule, getExtensions, loadModule, ModuleInfo(..), moduleName, parseModule)
 import Language.Haskell.Modules.Params (markForDelete, MonadClean(getParams), Params(hsFlags, removeEmptyImports, scratchDir, testMode))
-import Language.Haskell.Modules.SourceDirs (APath(..), modifyDirs, pathKey, PathKey(..), PathKey(unPathKey), SourceDirs(getDirs, putDirs))
-import Language.Haskell.Modules.SrcLoc (srcLoc)
-import Language.Haskell.Modules.Symbols (symbols)
+import Language.Haskell.Modules.SourceDirs (modifyDirs, pathKey, APath(..), PathKey(..), PathKey(unPathKey), SourceDirs(getDirs, putDirs))
 import Language.Haskell.Modules.Util.DryIO (replaceFile, tildeBackup)
 import Language.Haskell.Modules.Util.QIO (qLnPutStr, quietly)
+import Language.Haskell.Modules.Util.SrcLoc (srcLoc)
+import Language.Haskell.Modules.Util.Symbols (symbols)
 import System.Directory (createDirectoryIfMissing, getCurrentDirectory)
 import System.Exit (ExitCode(..))
 import System.Process (readProcessWithExitCode, showCommandForUser)
 
+#if MIN_VERSION_haskell_src_exts(1,14,0)
+import Language.Haskell.Exts.Extension (Extension(..))
+#endif
+
 {-
 -- | This is designed to be called from the postConf script of your
 -- Setup file, it cleans up the imports of all the source files in the
@@ -108,7 +112,7 @@
       -- turn it back into Created.
       toCreated (JustModified name key) = JustCreated name key
       toCreated x@(JustCreated {}) = x
-      toCreated x = error $ "toCreated: " ++ show x
+      toCreated _ = error "toCreated"
       -- Update the cached version of the now modified module and then
       -- clean its import list.
       doModule key =
@@ -126,12 +130,20 @@
        exts <- getExtensions
        let args' = args ++
                    ["--make", "-c", "-ddump-minimal-imports", "-outputdir", scratch, "-i" ++ intercalate ":" dirs] ++
-                   map (("-X" ++) . show) exts ++
+                   concatMap ppExtension exts ++
                    map unPathKey (toList keys)
        (code, _out, err) <- liftIO $ readProcessWithExitCode cmd args' ""
        case code of
          ExitSuccess -> quietly (qLnPutStr (showCommandForUser cmd args' ++ " -> Ok")) >> return ()
          ExitFailure _ -> error ("dumpImports: compile failed\n " ++ showCommandForUser cmd args' ++ " ->\n" ++ err)
+
+    where
+#if MIN_VERSION_haskell_src_exts(1,14,0)
+    ppExtension (EnableExtension x) = ["-X"++ show x]
+    ppExtension _ = []
+#else
+    ppExtension = (:[]) . ("-X" ++) . show
+#endif
 
 -- | Parse the import list generated by GHC, parse the original source
 -- file, and if all goes well insert the new imports into the old
diff --git a/Language/Haskell/Modules/ModuVerse.hs b/Language/Haskell/Modules/ModuVerse.hs
--- a/Language/Haskell/Modules/ModuVerse.hs
+++ b/Language/Haskell/Modules/ModuVerse.hs
@@ -32,8 +32,11 @@
 import Data.Set as Set (fromList, Set)
 import qualified Language.Haskell.Exts.Annotated as A (Module(..), ModuleHead(..), ModuleName(..), parseFileWithComments)
 import Language.Haskell.Exts.Comments (Comment(..))
+#if MIN_VERSION_haskell_src_exts(1,14,0)
+import Language.Haskell.Exts.Extension (Extension(..), KnownExtension(..))
+#else
 import Language.Haskell.Exts.Extension (Extension(..))
-import Language.Haskell.Exts.Fixity (baseFixities)
+#endif
 import qualified Language.Haskell.Exts.Parser as Exts (defaultParseMode, fromParseResult, ParseMode(extensions, parseFilename, fixities), ParseResult)
 import Language.Haskell.Exts.SrcLoc (SrcSpanInfo)
 import Language.Haskell.Exts.Syntax as S (ModuleName(..))
@@ -41,6 +44,14 @@
 import Language.Haskell.Modules.Util.QIO (MonadVerbosity, qLnPutStr, quietly)
 import System.IO.Error (isDoesNotExistError, isUserError)
 
+#if MIN_VERSION_haskell_src_exts(1,14,0)
+deriving instance Ord Extension
+deriving instance Ord KnownExtension
+nameToExtension x = EnableExtension x
+#else
+nameToExtension x = id x
+#endif
+
 deriving instance Ord Comment
 
 data ModuleInfo
@@ -77,18 +88,21 @@
 moduVerseInit =
     ModuVerseState { moduleNames_ = Nothing
                    , moduleInfo_ = Map.empty
-                   , extensions_ = Exts.extensions Exts.defaultParseMode ++ [StandaloneDeriving] -- allExtensions
+                   , extensions_ = Exts.extensions Exts.defaultParseMode ++ [nameToExtension StandaloneDeriving] -- allExtensions
                    , sourceDirs_ = ["."] }
 
 -- | From hsx2hs, but removing Arrows because it makes test case fold3c and others fail.
--- The TransformListComp makes group, by, and using into keywords.
 hseExtensions :: [Extension]
-hseExtensions =
+hseExtensions = map nameToExtension
     [ RecursiveDo, ParallelListComp, MultiParamTypeClasses, FunctionalDependencies, RankNTypes, ExistentialQuantification
     , ScopedTypeVariables, ImplicitParams, FlexibleContexts, FlexibleInstances, EmptyDataDecls, KindSignatures
     , BangPatterns, TemplateHaskell, ForeignFunctionInterface, {- Arrows, -} Generics, NamedFieldPuns, PatternGuards
     , MagicHash, TypeFamilies, StandaloneDeriving, TypeOperators, RecordWildCards, GADTs, UnboxedTuples
-    , PackageImports, QuasiQuotes, {-TransformListComp,-} ViewPatterns, XmlSyntax, RegularPatterns ]
+    , PackageImports, QuasiQuotes, TransformListComp, ViewPatterns, XmlSyntax, RegularPatterns, TupleSections
+#if MIN_VERSION_haskell_src_exts(1,14,0)
+    , ExplicitNamespaces
+#endif
+    ]
 
 getNames :: ModuVerse m => m (Set S.ModuleName)
 getNames = getModuVerse >>= return . Set.fromList . keys . fromMaybe (error "No modules in ModuVerse, use putModule") . moduleNames_
@@ -175,4 +189,4 @@
 parseFileWithComments path =
     liftIO (A.parseFileWithComments mode path)
     where
-      mode = Exts.defaultParseMode {Exts.extensions = hseExtensions, Exts.parseFilename = path, Exts.fixities = Just baseFixities}
+      mode = Exts.defaultParseMode {Exts.extensions = hseExtensions, Exts.parseFilename = path, Exts.fixities = Nothing }
diff --git a/Language/Haskell/Modules/SourceDirs.hs b/Language/Haskell/Modules/SourceDirs.hs
--- a/Language/Haskell/Modules/SourceDirs.hs
+++ b/Language/Haskell/Modules/SourceDirs.hs
@@ -8,6 +8,10 @@
     , PathKey(..)
     , APath(..)
     , pathKey
+#if 0
+    , pathKey
+    , pathKeyMaybe
+#endif
     , Path(..)
     , modulePath
     , modulePathBase
diff --git a/Language/Haskell/Modules/Split.hs b/Language/Haskell/Modules/Split.hs
--- a/Language/Haskell/Modules/Split.hs
+++ b/Language/Haskell/Modules/Split.hs
@@ -28,9 +28,9 @@
 import Language.Haskell.Modules.Imports (cleanResults)
 import Language.Haskell.Modules.ModuVerse (findModule, getNames, ModuleInfo(..), moduleName, parseModule)
 import Language.Haskell.Modules.Params (MonadClean(getParams), Params(extraImports))
-import Language.Haskell.Modules.SourceDirs (APath(..), modulePathBase, pathKey)
-import Language.Haskell.Modules.Symbols (exports, imports, members, symbols)
+import Language.Haskell.Modules.SourceDirs (modulePathBase, APath(..), pathKey)
 import Language.Haskell.Modules.Util.QIO (qLnPutStr, quietly)
+import Language.Haskell.Modules.Util.Symbols (exports, imports, symbols, members)
 import Prelude hiding (writeFile)
 import System.FilePath ((<.>))
 
diff --git a/Language/Haskell/Modules/SrcLoc.hs b/Language/Haskell/Modules/SrcLoc.hs
deleted file mode 100644
--- a/Language/Haskell/Modules/SrcLoc.hs
+++ /dev/null
@@ -1,241 +0,0 @@
-{-# LANGUAGE BangPatterns, FlexibleInstances, ScopedTypeVariables, UndecidableInstances #-}
-{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
-module Language.Haskell.Modules.SrcLoc
-    ( HasSpanInfo(..)
-    , srcSpan
-    , srcLoc
-    , endLoc
-    , textEndLoc
-    , increaseSrcLoc
-    , textSpan
-    , srcPairText
-    , makeTree
-    ) where
-
-import Control.Monad.State (get, put, runState, State)
-import Data.List (groupBy, partition, sort)
-import Data.Set (Set, toList)
-import Data.Tree (Tree(Node), unfoldTree)
-import qualified Language.Haskell.Exts.Annotated.Syntax as A (Decl(..), ExportSpec(..), ExportSpecList(..), ImportDecl(ImportDecl), ModuleHead(..), ModuleName(..), ModulePragma(..), WarningText(..))
-import Language.Haskell.Exts.SrcLoc (SrcLoc(..), SrcSpan(..), SrcSpanInfo(..))
-import Prelude hiding (rem)
-
--- | A version of lines that preserves the presence or absence of a
--- terminating newline
-lines' :: String -> [String]
-lines' s =
-    -- Group characters into strings containing either only newlines or no newlines,
-    -- and then transform the newline only strings into empty lines.
-    bol (groupBy (\ a b -> a /= '\n' && b /= '\n') s)
-    where
-      -- If we are at beginning of line and see a newline, insert an empty
-      bol ("\n" : xs) = "" : bol xs
-      -- If we are at beginning of line and see something else, call end of line
-      bol (x : xs) = x : eol xs
-      -- If we see EOF at bol insert a trailing empty
-      bol [] = [""]
-      -- If we are seeking end of line and see a newline, go to beginning of line
-      eol ("\n" : xs) = bol xs
-      -- This shouldn't happen
-      eol (x : xs) = x : eol xs
-      eol [] = []
-
--- type Module = A.Module SrcSpanInfo
-type ModuleHead = A.ModuleHead SrcSpanInfo
-type ModulePragma = A.ModulePragma SrcSpanInfo
-type ModuleName = A.ModuleName SrcSpanInfo
-type WarningText = A.WarningText SrcSpanInfo
-type ExportSpecList = A.ExportSpecList SrcSpanInfo
-type ExportSpec = A.ExportSpec SrcSpanInfo
-type ImportDecl = A.ImportDecl SrcSpanInfo
--- type ImportSpecList = A.ImportSpecList SrcSpanInfo
--- type ImportSpec = A.ImportSpec SrcSpanInfo
-type Decl = A.Decl SrcSpanInfo
--- type QName = A.QName SrcSpanInfo
--- type Name = A.Name SrcSpanInfo
--- type Type = A.Type SrcSpanInfo
-
-class HasSpanInfo a where
-    spanInfo :: a -> SrcSpanInfo
-
-instance HasSpanInfo SrcSpan where
-    spanInfo x = SrcSpanInfo x []
-
-instance HasSpanInfo a => HasSpanInfo (Tree a) where
-    spanInfo (Node x _) = spanInfo x
-
-instance HasSpanInfo ModuleHead where
-    spanInfo (A.ModuleHead x _ _ _) = x
-
-instance HasSpanInfo ModuleName where
-    spanInfo (A.ModuleName x _) = x
-
-instance HasSpanInfo ModulePragma where
-    spanInfo (A.LanguagePragma x _) = x
-    spanInfo (A.OptionsPragma x _ _) = x
-    spanInfo (A.AnnModulePragma x _) = x
-
-instance HasSpanInfo WarningText where
-    spanInfo (A.WarnText x _) = x
-    spanInfo (A.DeprText x _) = x
-
-instance HasSpanInfo ExportSpecList where
-    spanInfo (A.ExportSpecList x _) = x
-
-instance HasSpanInfo ExportSpec where
-    spanInfo (A.EVar x _) = x
-    spanInfo (A.EAbs x _) = x
-    spanInfo (A.EThingAll x _) = x
-    spanInfo (A.EThingWith x _ _) = x
-    spanInfo (A.EModuleContents x _) = x
-
-instance HasSpanInfo ImportDecl where
-    spanInfo (A.ImportDecl x _ _ _ _ _ _) = x
-
-instance HasSpanInfo Decl where
-    spanInfo (A.TypeDecl l _ _) = l
-    spanInfo (A.TypeFamDecl l _ _) = l
-    spanInfo (A.DataDecl l _ _ _ _ _) = l
-    spanInfo (A.GDataDecl l _ _ _ _ _ _) = l
-    spanInfo (A.DataFamDecl l _ _ _) = l
-    spanInfo (A.TypeInsDecl l _ _) = l
-    spanInfo (A.DataInsDecl l _ _ _ _) = l
-    spanInfo (A.GDataInsDecl l _ _ _ _ _) = l
-    spanInfo (A.ClassDecl l _ _ _ _) = l
-    spanInfo (A.InstDecl l  _ _ _) = l
-    spanInfo (A.DerivDecl l _ _) = l
-    spanInfo (A.InfixDecl l _ _ _) = l
-    spanInfo (A.DefaultDecl l _) = l
-    spanInfo (A.SpliceDecl l _) = l
-    spanInfo (A.TypeSig l _ _) = l
-    spanInfo (A.FunBind l _) = l
-    spanInfo (A.PatBind l _ _ _ _) = l
-    spanInfo (A.ForImp l _ _ _ _ _) = l
-    spanInfo (A.ForExp l _ _ _ _) = l
-    spanInfo (A.RulePragmaDecl l _) = l
-    spanInfo (A.DeprPragmaDecl l _) = l
-    spanInfo (A.WarnPragmaDecl l _) = l
-    spanInfo (A.InlineSig l _ _ _) = l
-    spanInfo (A.InlineConlikeSig l _ _) = l
-    spanInfo (A.SpecSig l _ _) = l
-    spanInfo (A.SpecInlineSig l _ _ _ _) = l
-    spanInfo (A.InstSig l _ _) = l
-    spanInfo (A.AnnPragma l _) = l
-
-instance HasSpanInfo SrcSpanInfo where
-    spanInfo = id
-
-{-
-data SrcSpanInfo
-  = SrcSpanInfo { srcInfoSpan :: SrcSpan
-                , srcInfoPoints :: [SrcSpan] }
-
-data SrcSpan
-  = SrcSpan {srcSpanFilename :: String,
-             srcSpanStartLine :: Int,
-             srcSpanStartColumn :: Int,
-             srcSpanEndLine :: Int,
-             srcSpanEndColumn :: Int}
-
-data SrcLoc
-  = SrcLoc {srcFilename :: String, srcLine :: Int, srcColumn :: Int}
--}
-
-srcSpan :: HasSpanInfo x => x -> SrcSpan
-srcSpan = srcInfoSpan . spanInfo
-
-srcLoc :: HasSpanInfo x => x -> SrcLoc
-srcLoc x = let (SrcSpan f b e _ _) = srcSpan x in SrcLoc f b e
-
-endLoc :: HasSpanInfo x => x -> SrcLoc
-endLoc x = let (SrcSpan f _ _ b e) = srcSpan x in SrcLoc f b e
-
-textEndLoc :: FilePath -> String -> SrcLoc
-textEndLoc path text =
-    SrcLoc {srcFilename = path, srcLine = length ls, srcColumn = length (last ls) + 1}
-    where ls = lines' text
-
--- | Update a SrcLoc to move it from l past the string argument.
-increaseSrcLoc :: String -> SrcLoc -> SrcLoc
-increaseSrcLoc "" l = l
-increaseSrcLoc ('\n' : s) (SrcLoc f y _) = increaseSrcLoc s (SrcLoc f (y + 1) 1)
-increaseSrcLoc (_ : s) (SrcLoc f y x) = increaseSrcLoc s (SrcLoc f y (x + 1))
-
-textSpan :: FilePath -> String -> SrcSpanInfo
-textSpan path s =
-    let end = textEndLoc path s in
-    SrcSpanInfo (SrcSpan {srcSpanFilename = path, srcSpanStartLine = 1, srcSpanStartColumn = 1, srcSpanEndLine = srcLine end, srcSpanEndColumn = srcColumn end}) []
-
--- | Given a beginning and end location, and a string which starts at
--- the beginning location, return a (beforeend,afterend) pair.
-srcPairText :: SrcLoc -> SrcLoc -> String -> (String, String)
-srcPairText b0 e0 s0 =
-    fst $ runState f (b0, e0, "", s0)
-    where
-      f :: State (SrcLoc, SrcLoc, String, String) (String, String)
-      f = do (b, e, r, s) <- get
-             case (srcLine b < srcLine e, srcColumn b < srcColumn e) of
-               (True, _) ->
-                   case span (/= '\n') s of
-                     (r', '\n' : s') ->
-                         put (b {srcLine = srcLine b + 1, srcColumn = 1}, e, r ++ r' ++ "\n", s') >> f
-                     (_, "") ->
-                        -- This should not happen, but if the last line
-                        -- lacks a newline terminator, haskell-src-exts
-                        -- will set the end location as if the terminator
-                        -- was present.
-                        case s of
-                          "" -> return (r, s)
-                          (c : s') -> put (b {srcColumn = srcColumn b + 1}, e, r ++ [c], s') >> f
-                     _ -> error "Impossible: span stopped at the wrong character"
-               (_, True) ->
-                   case s of
-                     [] -> error $ "srcPairText: " ++ show (b0, e0, s0)
-                     (c : s') -> put (b {srcColumn = srcColumn b + 1}, e, r ++ [c], s') >> f
-               _ ->
-                   return (r, s)
-
--- | Build a tree of SrcSpanInfo 
-makeTree :: (HasSpanInfo a, Show a, Eq a, Ord a) => Set a -> Tree a
-makeTree s =
-    case findRoots (toList s) of
-      [] -> error "No roots"
-      [root] -> unfoldTree f root
-      roots -> error $ "Multiple roots: " ++ show roots
-    where
-      f x = (x, findChildren (toList s) x)
-
-      -- The roots are the nodes that are not covered by any other node.
-      findRoots :: (HasSpanInfo a, Eq a, Ord a) => [a] -> [a]
-      findRoots [] = []
-      findRoots (x : xs) =
-          let (_children, other) = partition (\ y -> x `covers` y) xs
-              (ancestors, cousins) = partition (\ y -> x `coveredBy` y) other in
-          case ancestors of
-            -- If there are no ancestors, x is a root, and there may be other roots among the cousins
-            [] -> x : findRoots cousins
-            -- If there are ancestors, there must be a root among them, and there still may be roots among the cousins.
-            _ -> findRoots (ancestors ++ cousins)
-
-      findChildren :: (HasSpanInfo a, Eq a, Ord a, Show a) => [a] -> a -> [a]
-      findChildren u x = findRoots children where children = sort (filter (\ y -> x `covers` y && x /= y) u)
-
--- True if a covers b
-covers :: (HasSpanInfo a, HasSpanInfo b) => a -> b -> Bool
-covers a b = srcLoc a <= srcLoc b && endLoc b <= endLoc a
-
--- True if a is covered by b
-coveredBy :: (HasSpanInfo a, HasSpanInfo b) => a -> b -> Bool
-coveredBy = flip covers
-
-{-
-test3 = TestCase (assertEqual "covers1" True (covers (mkspan (29, 1) (29, 8)) (mkspan (29, 3) (29, 7))))
-test4 = TestCase (assertEqual "covers2" False (covers (mkspan (29, 1) (29, 8)) (mkspan (29, 3) (29, 10))))
-test5 = TestCase (assertEqual "roots1"
-                                  [sp 5 10, sp 11 18]
-                                  (findRoots [sp 5 10,
-                                              sp 11 18,
-                                              sp 6 7,
-                                              sp 8 9,
-                                              sp 12 15]))
--}
diff --git a/Language/Haskell/Modules/Symbols.hs b/Language/Haskell/Modules/Symbols.hs
deleted file mode 100644
--- a/Language/Haskell/Modules/Symbols.hs
+++ /dev/null
@@ -1,187 +0,0 @@
-{-# LANGUAGE BangPatterns, CPP, FlexibleInstances, ScopedTypeVariables #-}
-{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
-module Language.Haskell.Modules.Symbols
-    ( FoldDeclared(foldDeclared)
-    , FoldMembers(foldMembers)
-    , symbols
-    , members
-    , exports
-    , imports
-    ) where
-
-import Data.List (sort)
-import Data.Maybe (mapMaybe)
-import Data.Set as Set (empty, insert, Set, toList)
-import Language.Haskell.Exts.Annotated.Simplify (sName)
-import qualified Language.Haskell.Exts.Annotated.Syntax as A (ClassDecl(..), ConDecl(..), Decl(..), DeclHead(..), ExportSpec(..), FieldDecl(..), GadtDecl(..), ImportSpec(..), InstHead(..), Match(..), Name, Pat(..), PatField(..), QName(..), QualConDecl(..), RPat(..))
-import qualified Language.Haskell.Exts.Syntax as S (CName(..), ExportSpec(..), ImportSpec(..), Name(..), QName(..))
-
--- | Do a fold over the names that are declared in a declaration (not
--- every name that appears, just the ones that the declaration is
--- causing to exist - what's the word for that?  Reify!)
-class FoldDeclared a where
-    foldDeclared :: forall r. (Maybe S.Name -> r -> r) -> r -> a -> r
-
-instance FoldDeclared (A.Decl a) where
-    foldDeclared f r (A.TypeDecl _ x _t) = foldDeclared f r x  -- type x = ...
-    foldDeclared f r (A.TypeFamDecl _ x _k) = foldDeclared f r x -- data family x = ...
-    foldDeclared f r (A.DataDecl _ _ _ x _ _) = foldDeclared f r x -- data/newtype _ x = ...
-    foldDeclared f r (A.GDataDecl _ _ _ x _ _ _) = foldDeclared f r x
-    foldDeclared f r (A.DataFamDecl _ _ x _) = foldDeclared f r x
-    foldDeclared f r (A.TypeInsDecl _ _ _) = f Nothing r -- type instance _ = ...
-    foldDeclared f r (A.DataInsDecl _ _ _ _ _) = f Nothing r -- data instance _ = ...
-    foldDeclared f r (A.GDataInsDecl _ _ _ _ _ _) = f Nothing r -- data or newtype instance, GADT style
-    foldDeclared f r (A.ClassDecl _ _ x _ _) = foldDeclared f r x  -- class context => x | fundeps where decls
-    foldDeclared f r (A.InstDecl _ _ _ _) = f Nothing r -- type class instance
-    foldDeclared f r (A.DerivDecl _ _ x) = foldDeclared f r x
-    foldDeclared f r (A.InfixDecl _ _ _ _) = f Nothing r -- fixity
-    foldDeclared f r (A.DefaultDecl _ _) = f Nothing r -- default (type1, type2 ...)
-    foldDeclared f r (A.SpliceDecl _ _) = f Nothing r  -- template haskell splice declaration
-    foldDeclared f r (A.TypeSig _ xs _) = foldl (foldDeclared f) r xs
-    foldDeclared f r (A.FunBind _ xs) = foldl (foldDeclared f) r xs
-    foldDeclared f r (A.PatBind _ x _ _ _) = foldDeclared f r x
-    foldDeclared _f _r (A.ForImp _ _ _ _ _ _) = error "Unimplemented FoldDeclared instance: ForImp"
-    foldDeclared _ _r (A.ForExp _ _ _ _ _) = error "Unimplemented FoldDeclared instance: ForExp"
-    foldDeclared f r (A.RulePragmaDecl _ _) = f Nothing r
-    foldDeclared f r (A.DeprPragmaDecl _ _) = f Nothing r
-    foldDeclared f r (A.WarnPragmaDecl _ _) = f Nothing r
-    foldDeclared f r (A.InlineSig _ _ _ x) = foldDeclared f r x
-    foldDeclared f r (A.InlineConlikeSig _ _ x) = foldDeclared f r x
-    foldDeclared f r (A.SpecSig _ x _) = foldDeclared f r x
-    foldDeclared f r (A.SpecInlineSig _ _ _ x _) = foldDeclared f r x
-    foldDeclared f r (A.InstSig _ _ x) = foldDeclared f r x
-    foldDeclared f r (A.AnnPragma _ _) = f Nothing r
-
-instance FoldDeclared (A.DeclHead a) where
-    foldDeclared f r (A.DHead _ x _) = foldDeclared f r x
-    foldDeclared f r (A.DHInfix _ _ x _) = foldDeclared f r x
-    foldDeclared f r (A.DHParen _ x) = foldDeclared f r x
-instance FoldDeclared (A.ClassDecl a) where
-    foldDeclared f r (A.ClsDecl _ x) = foldDeclared f r x	-- ordinary declaration
-    foldDeclared f r (A.ClsDataFam _ _ x _) = foldDeclared f r x	-- declaration of an associated data type
-    foldDeclared f r (A.ClsTyFam _ x _) = foldDeclared f r x	-- declaration of an associated type synonym
-    foldDeclared _ r (A.ClsTyDef _ _ _) = r -- default choice for an associated type synonym
-instance FoldDeclared (A.InstHead a) where
-    foldDeclared f r (A.IHead _ x _) = foldDeclared f r x
-    foldDeclared f r (A.IHInfix _ _ x _) = foldDeclared f r x
-    foldDeclared f r (A.IHParen _ x) = foldDeclared f r x
-instance FoldDeclared (A.Match a) where
-    foldDeclared f r (A.Match _ x _ _ _) = foldDeclared f r x
-    foldDeclared f r (A.InfixMatch _ _ x _ _ _) = foldDeclared f r x
--- Can you declare something with a qualified name?
-instance FoldDeclared (A.QName a) where
-    foldDeclared f r (A.Qual _ _ x) = foldDeclared f r x
-    foldDeclared f r (A.UnQual _ x) = foldDeclared f r x
-    foldDeclared _ r (A.Special _ _) = r
-instance FoldDeclared (A.Pat a) where
-    foldDeclared f r (A.PVar _ x) = foldDeclared f r x	-- variable
-    foldDeclared _ r (A.PLit _ _) = r	-- literal constant
-    foldDeclared f r (A.PNeg _ x) = foldDeclared f r x	-- negated pattern
-    foldDeclared f r (A.PNPlusK _ x _) = foldDeclared f r x	-- n+k pattern
-    foldDeclared f r (A.PInfixApp _ p1 _qn p2) = let r' = foldDeclared f r p1 in foldDeclared f r' p2	-- pattern with an infix data constructor
-    foldDeclared f r (A.PApp _ _ ps) = foldl (foldDeclared f) r ps	-- data constructor and argument patterns
-    foldDeclared f r (A.PTuple _ ps) = foldl (foldDeclared f) r ps	-- tuple pattern
-    foldDeclared f r (A.PList _ ps) = foldl (foldDeclared f) r ps	-- list pattern
-    foldDeclared f r (A.PParen _ x) = foldDeclared f r x	-- parenthesized pattern
-    foldDeclared f r (A.PRec _ _qn fs) = foldl (foldDeclared f) r fs	-- labelled pattern, record style
-    foldDeclared f r (A.PAsPat _ x y) = let r' = foldDeclared f r x in foldDeclared f r' y	-- @-pattern
-    foldDeclared _ r (A.PWildCard _) = r	-- wildcard pattern: _
-    foldDeclared f r (A.PIrrPat _ x) = foldDeclared f r x	-- irrefutable pattern: ~pat
-    foldDeclared f r (A.PatTypeSig _ x _) = foldDeclared f r x	-- pattern with type signature
-    foldDeclared f r (A.PViewPat _ _ x) = foldDeclared f r x	-- view patterns of the form (exp -> pat)
-    foldDeclared f r (A.PRPat _ rps) = foldl (foldDeclared f) r rps	-- regular list pattern
-    foldDeclared _f _r (A.PXTag _ _xn _pxs _mp _ps) = error "Unimplemented FoldDeclared instance: PXTag"	-- XML element pattern
-    foldDeclared _f _r (A.PXETag _ _xn _pxs _mp) = error "Unimplemented FoldDeclared instance: PXETag"	-- XML singleton element pattern
-    foldDeclared _f _r (A.PXPcdata _ _s) = error "Unimplemented FoldDeclared instance: XPcdata"	-- XML PCDATA pattern
-    foldDeclared _f _r (A.PXPatTag _ _p) = error "Unimplemented FoldDeclared instance: PXPatTag"	-- XML embedded pattern
-    foldDeclared _f _r (A.PXRPats _ _rps) = error "Unimplemented FoldDeclared instance: PXRPats"	-- XML regular list pattern
-    foldDeclared _f _r (A.PExplTypeArg _ _n _t) = error "Unimplemented FoldDeclared instance: PExplTypeArg"	-- Explicit generics style type argument e.g. f {| Int |} x = ...
-    foldDeclared _ r (A.PQuasiQuote _ _ _) = r	-- quasi quote pattern: [$name| string |]
-    foldDeclared f r (A.PBangPat _ x) = foldDeclared f r x	-- strict (bang) pattern: f !x = ...
-instance FoldDeclared (A.PatField a) where
-    foldDeclared f r (A.PFieldPat _ _n x) = foldDeclared f r x 	-- ordinary label-pattern pair
-    foldDeclared f r (A.PFieldPun _ x) = foldDeclared f r x 	-- record field pun
-    foldDeclared _ r (A.PFieldWildcard _) = r
-instance FoldDeclared (A.RPat a) where
-    foldDeclared f r (A.RPOp _ x _) = foldDeclared f r x	-- operator pattern, e.g. pat*
-    foldDeclared f r (A.RPEither _ x y) = let r' = foldDeclared f r x in foldDeclared f r' y 	-- choice pattern, e.g. (1 | 2)
-    foldDeclared f r (A.RPSeq _ xs) = foldl (foldDeclared f) r xs	-- sequence pattern, e.g. (| 1, 2, 3 |)
-    foldDeclared f r (A.RPGuard _ x _) = foldDeclared f r x	-- guarded pattern, e.g. (| p | p < 3 |)
-    foldDeclared f r (A.RPCAs _ n x) = let r' = foldDeclared f r n in foldDeclared f r' x 	-- non-linear variable binding, e.g. (foo@:(1 | 2))*
-    foldDeclared f r (A.RPAs _ n x) = let r' = foldDeclared f r n in foldDeclared f r' x  	-- linear variable binding, e.g. foo@(1 | 2)
-    foldDeclared f r (A.RPParen _ x) = foldDeclared f r x	-- parenthesised pattern, e.g. (2*)
-    foldDeclared f r (A.RPPat _ x) = foldDeclared f r x	-- an ordinary pattern
-
-instance FoldDeclared (A.Name l) where
-    foldDeclared f r x = f (Just (sName x)) r
-
--- Something imported can be exported
-instance FoldDeclared (A.ImportSpec l) where
-    foldDeclared f r (A.IVar _ name) = foldDeclared f r name
-    foldDeclared f r (A.IAbs _ name) = foldDeclared f r name
-    foldDeclared f r (A.IThingAll _ name) = foldDeclared f r name
-    foldDeclared f r (A.IThingWith _ name _) = foldDeclared f r name
-
-instance FoldDeclared (A.ExportSpec l) where
-    foldDeclared f r (A.EVar _ name) = foldDeclared f r name
-    foldDeclared f r (A.EAbs _ name) = foldDeclared f r name
-    foldDeclared f r (A.EThingAll _ name) = foldDeclared f r name
-    foldDeclared f r (A.EThingWith _ name _) = foldDeclared f r name
-    foldDeclared _ r (A.EModuleContents _ _) = r -- This probably won't work correctly
-
--- Return the set of symbols appearing in a construct.  Some
--- constructs, such as instance declarations, declare no symbols, in
--- which case Nothing is returned.  Some declare more than one.
-symbols :: FoldDeclared a => a -> Set (Maybe S.Name)
-symbols = foldDeclared insert empty
-
-members :: FoldMembers a => a -> Set (Maybe S.Name)
-members = foldMembers insert empty
-
-justs :: Set (Maybe a) -> [a]
-justs = mapMaybe id . toList
-
-exports :: (FoldDeclared a, FoldMembers a) => a -> [S.ExportSpec]
-exports x = case (justs (symbols x), justs (members x)) of
-              ([n], []) -> [S.EVar (S.UnQual n)]
-              ([n], ms) -> [S.EThingWith (S.UnQual n) (sort (map S.VarName ms))]
-              ([], []) -> []
-              ([], _) -> error "exports: members with no top level name"
-              (ns, []) -> map (S.EVar . S.UnQual) ns
-              y -> error $ "exports: multiple top level names and member names: " ++ show y
-
-imports :: (FoldDeclared a, FoldMembers a) => a -> [S.ImportSpec]
-imports x = case (justs (symbols x), justs (members x)) of
-              ([n], []) -> [S.IVar n]
-              ([n], ms) -> [S.IThingWith n (sort (map S.VarName ms))]
-              ([], []) -> []
-              ([], _ms) -> error "exports: members with no top level name"
-              (ns, []) -> map S.IVar ns
-              y -> error $ "imports: multiple top level names and member names: " ++ show y
-
--- | Fold over the declared members - e.g. the method names of a class
--- declaration, the constructors of a data declaration.
-class FoldMembers a where
-    foldMembers :: forall r. (Maybe S.Name -> r -> r) -> r -> a -> r
-
-instance FoldMembers (A.Decl a) where
-    foldMembers f r (A.ClassDecl _ _ _ _ mxs) = maybe r (foldl (foldDeclared f) r) mxs  -- class context => x | fundeps where decls
-    foldMembers f r (A.DataDecl _ _ _ _ xs _) = foldl (foldDeclared f) r xs -- data/newtype _ x = ...
-    foldMembers f r (A.GDataDecl _ _ _ _ _ xs _) = foldl (foldDeclared f) r xs
-    foldMembers _ r _ = r
-
--- The following instances of FoldDeclared are only called by the FoldMembers instances.  Hopefully.
-instance FoldDeclared (A.QualConDecl l) where
-    foldDeclared f r (A.QualConDecl _l _ _ x) = foldDeclared f r x
-
--- Constructors and field names
-instance FoldDeclared (A.ConDecl l) where
-    foldDeclared f r (A.ConDecl _ x _ts) = foldDeclared f r x	-- ordinary data constructor
-    foldDeclared f r (A.InfixConDecl _ _t1 x _t2) = foldDeclared f r x	-- infix data constructor
-    foldDeclared f r (A.RecDecl _ x fs) = let r' = foldDeclared f r x in foldl (foldDeclared f) r' fs 	-- record constructor
-
-instance FoldDeclared (A.FieldDecl l) where
-    foldDeclared f r (A.FieldDecl _ xs _) = foldl (foldDeclared f) r xs
-
-instance FoldDeclared (A.GadtDecl l) where
-    foldDeclared f r (A.GadtDecl _ x _) = foldDeclared f r x
diff --git a/Language/Haskell/Modules/Util/SrcLoc.hs b/Language/Haskell/Modules/Util/SrcLoc.hs
new file mode 100644
--- /dev/null
+++ b/Language/Haskell/Modules/Util/SrcLoc.hs
@@ -0,0 +1,241 @@
+{-# LANGUAGE BangPatterns, FlexibleInstances, ScopedTypeVariables, UndecidableInstances #-}
+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
+module Language.Haskell.Modules.Util.SrcLoc
+    ( HasSpanInfo(..)
+    , srcSpan
+    , srcLoc
+    , endLoc
+    , textEndLoc
+    , increaseSrcLoc
+    , textSpan
+    , srcPairText
+    , makeTree
+    ) where
+
+import Control.Monad.State (get, put, runState, State)
+import Data.List (groupBy, partition, sort)
+import Data.Set (Set, toList)
+import Data.Tree (Tree(Node), unfoldTree)
+import qualified Language.Haskell.Exts.Annotated.Syntax as A (Decl(..), ExportSpec(..), ExportSpecList(..), ImportDecl(ImportDecl), ModuleHead(..), ModuleName(..), ModulePragma(..), WarningText(..))
+import Language.Haskell.Exts.SrcLoc (SrcLoc(..), SrcSpan(..), SrcSpanInfo(..))
+import Prelude hiding (rem)
+
+-- | A version of lines that preserves the presence or absence of a
+-- terminating newline
+lines' :: String -> [String]
+lines' s =
+    -- Group characters into strings containing either only newlines or no newlines,
+    -- and then transform the newline only strings into empty lines.
+    bol (groupBy (\ a b -> a /= '\n' && b /= '\n') s)
+    where
+      -- If we are at beginning of line and see a newline, insert an empty
+      bol ("\n" : xs) = "" : bol xs
+      -- If we are at beginning of line and see something else, call end of line
+      bol (x : xs) = x : eol xs
+      -- If we see EOF at bol insert a trailing empty
+      bol [] = [""]
+      -- If we are seeking end of line and see a newline, go to beginning of line
+      eol ("\n" : xs) = bol xs
+      -- This shouldn't happen
+      eol (x : xs) = x : eol xs
+      eol [] = []
+
+-- type Module = A.Module SrcSpanInfo
+type ModuleHead = A.ModuleHead SrcSpanInfo
+type ModulePragma = A.ModulePragma SrcSpanInfo
+type ModuleName = A.ModuleName SrcSpanInfo
+type WarningText = A.WarningText SrcSpanInfo
+type ExportSpecList = A.ExportSpecList SrcSpanInfo
+type ExportSpec = A.ExportSpec SrcSpanInfo
+type ImportDecl = A.ImportDecl SrcSpanInfo
+-- type ImportSpecList = A.ImportSpecList SrcSpanInfo
+-- type ImportSpec = A.ImportSpec SrcSpanInfo
+type Decl = A.Decl SrcSpanInfo
+-- type QName = A.QName SrcSpanInfo
+-- type Name = A.Name SrcSpanInfo
+-- type Type = A.Type SrcSpanInfo
+
+class HasSpanInfo a where
+    spanInfo :: a -> SrcSpanInfo
+
+instance HasSpanInfo SrcSpan where
+    spanInfo x = SrcSpanInfo x []
+
+instance HasSpanInfo a => HasSpanInfo (Tree a) where
+    spanInfo (Node x _) = spanInfo x
+
+instance HasSpanInfo ModuleHead where
+    spanInfo (A.ModuleHead x _ _ _) = x
+
+instance HasSpanInfo ModuleName where
+    spanInfo (A.ModuleName x _) = x
+
+instance HasSpanInfo ModulePragma where
+    spanInfo (A.LanguagePragma x _) = x
+    spanInfo (A.OptionsPragma x _ _) = x
+    spanInfo (A.AnnModulePragma x _) = x
+
+instance HasSpanInfo WarningText where
+    spanInfo (A.WarnText x _) = x
+    spanInfo (A.DeprText x _) = x
+
+instance HasSpanInfo ExportSpecList where
+    spanInfo (A.ExportSpecList x _) = x
+
+instance HasSpanInfo ExportSpec where
+    spanInfo (A.EVar x _) = x
+    spanInfo (A.EAbs x _) = x
+    spanInfo (A.EThingAll x _) = x
+    spanInfo (A.EThingWith x _ _) = x
+    spanInfo (A.EModuleContents x _) = x
+
+instance HasSpanInfo ImportDecl where
+    spanInfo (A.ImportDecl x _ _ _ _ _ _) = x
+
+instance HasSpanInfo Decl where
+    spanInfo (A.TypeDecl l _ _) = l
+    spanInfo (A.TypeFamDecl l _ _) = l
+    spanInfo (A.DataDecl l _ _ _ _ _) = l
+    spanInfo (A.GDataDecl l _ _ _ _ _ _) = l
+    spanInfo (A.DataFamDecl l _ _ _) = l
+    spanInfo (A.TypeInsDecl l _ _) = l
+    spanInfo (A.DataInsDecl l _ _ _ _) = l
+    spanInfo (A.GDataInsDecl l _ _ _ _ _) = l
+    spanInfo (A.ClassDecl l _ _ _ _) = l
+    spanInfo (A.InstDecl l  _ _ _) = l
+    spanInfo (A.DerivDecl l _ _) = l
+    spanInfo (A.InfixDecl l _ _ _) = l
+    spanInfo (A.DefaultDecl l _) = l
+    spanInfo (A.SpliceDecl l _) = l
+    spanInfo (A.TypeSig l _ _) = l
+    spanInfo (A.FunBind l _) = l
+    spanInfo (A.PatBind l _ _ _ _) = l
+    spanInfo (A.ForImp l _ _ _ _ _) = l
+    spanInfo (A.ForExp l _ _ _ _) = l
+    spanInfo (A.RulePragmaDecl l _) = l
+    spanInfo (A.DeprPragmaDecl l _) = l
+    spanInfo (A.WarnPragmaDecl l _) = l
+    spanInfo (A.InlineSig l _ _ _) = l
+    spanInfo (A.InlineConlikeSig l _ _) = l
+    spanInfo (A.SpecSig l _ _) = l
+    spanInfo (A.SpecInlineSig l _ _ _ _) = l
+    spanInfo (A.InstSig l _ _) = l
+    spanInfo (A.AnnPragma l _) = l
+
+instance HasSpanInfo SrcSpanInfo where
+    spanInfo = id
+
+{-
+data SrcSpanInfo
+  = SrcSpanInfo { srcInfoSpan :: SrcSpan
+                , srcInfoPoints :: [SrcSpan] }
+
+data SrcSpan
+  = SrcSpan {srcSpanFilename :: String,
+             srcSpanStartLine :: Int,
+             srcSpanStartColumn :: Int,
+             srcSpanEndLine :: Int,
+             srcSpanEndColumn :: Int}
+
+data SrcLoc
+  = SrcLoc {srcFilename :: String, srcLine :: Int, srcColumn :: Int}
+-}
+
+srcSpan :: HasSpanInfo x => x -> SrcSpan
+srcSpan = srcInfoSpan . spanInfo
+
+srcLoc :: HasSpanInfo x => x -> SrcLoc
+srcLoc x = let (SrcSpan f b e _ _) = srcSpan x in SrcLoc f b e
+
+endLoc :: HasSpanInfo x => x -> SrcLoc
+endLoc x = let (SrcSpan f _ _ b e) = srcSpan x in SrcLoc f b e
+
+textEndLoc :: FilePath -> String -> SrcLoc
+textEndLoc path text =
+    SrcLoc {srcFilename = path, srcLine = length ls, srcColumn = length (last ls) + 1}
+    where ls = lines' text
+
+-- | Update a SrcLoc to move it from l past the string argument.
+increaseSrcLoc :: String -> SrcLoc -> SrcLoc
+increaseSrcLoc "" l = l
+increaseSrcLoc ('\n' : s) (SrcLoc f y _) = increaseSrcLoc s (SrcLoc f (y + 1) 1)
+increaseSrcLoc (_ : s) (SrcLoc f y x) = increaseSrcLoc s (SrcLoc f y (x + 1))
+
+textSpan :: FilePath -> String -> SrcSpanInfo
+textSpan path s =
+    let end = textEndLoc path s in
+    SrcSpanInfo (SrcSpan {srcSpanFilename = path, srcSpanStartLine = 1, srcSpanStartColumn = 1, srcSpanEndLine = srcLine end, srcSpanEndColumn = srcColumn end}) []
+
+-- | Given a beginning and end location, and a string which starts at
+-- the beginning location, return a (beforeend,afterend) pair.
+srcPairText :: SrcLoc -> SrcLoc -> String -> (String, String)
+srcPairText b0 e0 s0 =
+    fst $ runState f (b0, e0, "", s0)
+    where
+      f :: State (SrcLoc, SrcLoc, String, String) (String, String)
+      f = do (b, e, r, s) <- get
+             case (srcLine b < srcLine e, srcColumn b < srcColumn e) of
+               (True, _) ->
+                   case span (/= '\n') s of
+                     (r', '\n' : s') ->
+                         put (b {srcLine = srcLine b + 1, srcColumn = 1}, e, r ++ r' ++ "\n", s') >> f
+                     (_, "") ->
+                        -- This should not happen, but if the last line
+                        -- lacks a newline terminator, haskell-src-exts
+                        -- will set the end location as if the terminator
+                        -- was present.
+                        case s of
+                          "" -> return (r, s)
+                          (c : s') -> put (b {srcColumn = srcColumn b + 1}, e, r ++ [c], s') >> f
+                     _ -> error "Impossible: span stopped at the wrong character"
+               (_, True) ->
+                   case s of
+                     [] -> error $ "srcPairText: " ++ show (b0, e0, s0)
+                     (c : s') -> put (b {srcColumn = srcColumn b + 1}, e, r ++ [c], s') >> f
+               _ ->
+                   return (r, s)
+
+-- | Build a tree of SrcSpanInfo 
+makeTree :: (HasSpanInfo a, Show a, Eq a, Ord a) => Set a -> Tree a
+makeTree s =
+    case findRoots (toList s) of
+      [] -> error "No roots"
+      [root] -> unfoldTree f root
+      roots -> error $ "Multiple roots: " ++ show roots
+    where
+      f x = (x, findChildren (toList s) x)
+
+      -- The roots are the nodes that are not covered by any other node.
+      findRoots :: (HasSpanInfo a, Eq a, Ord a) => [a] -> [a]
+      findRoots [] = []
+      findRoots (x : xs) =
+          let (_children, other) = partition (\ y -> x `covers` y) xs
+              (ancestors, cousins) = partition (\ y -> x `coveredBy` y) other in
+          case ancestors of
+            -- If there are no ancestors, x is a root, and there may be other roots among the cousins
+            [] -> x : findRoots cousins
+            -- If there are ancestors, there must be a root among them, and there still may be roots among the cousins.
+            _ -> findRoots (ancestors ++ cousins)
+
+      findChildren :: (HasSpanInfo a, Eq a, Ord a, Show a) => [a] -> a -> [a]
+      findChildren u x = findRoots children where children = sort (filter (\ y -> x `covers` y && x /= y) u)
+
+-- True if a covers b
+covers :: (HasSpanInfo a, HasSpanInfo b) => a -> b -> Bool
+covers a b = srcLoc a <= srcLoc b && endLoc b <= endLoc a
+
+-- True if a is covered by b
+coveredBy :: (HasSpanInfo a, HasSpanInfo b) => a -> b -> Bool
+coveredBy = flip covers
+
+{-
+test3 = TestCase (assertEqual "covers1" True (covers (mkspan (29, 1) (29, 8)) (mkspan (29, 3) (29, 7))))
+test4 = TestCase (assertEqual "covers2" False (covers (mkspan (29, 1) (29, 8)) (mkspan (29, 3) (29, 10))))
+test5 = TestCase (assertEqual "roots1"
+                                  [sp 5 10, sp 11 18]
+                                  (findRoots [sp 5 10,
+                                              sp 11 18,
+                                              sp 6 7,
+                                              sp 8 9,
+                                              sp 12 15]))
+-}
diff --git a/Language/Haskell/Modules/Util/Symbols.hs b/Language/Haskell/Modules/Util/Symbols.hs
new file mode 100644
--- /dev/null
+++ b/Language/Haskell/Modules/Util/Symbols.hs
@@ -0,0 +1,187 @@
+{-# LANGUAGE BangPatterns, CPP, FlexibleInstances, ScopedTypeVariables #-}
+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
+module Language.Haskell.Modules.Util.Symbols
+    ( FoldDeclared(foldDeclared)
+    , FoldMembers(foldMembers)
+    , symbols
+    , members
+    , exports
+    , imports
+    ) where
+
+import Data.List (sort)
+import Data.Maybe (mapMaybe)
+import Data.Set as Set (empty, insert, Set, toList)
+import Language.Haskell.Exts.Annotated.Simplify (sName)
+import qualified Language.Haskell.Exts.Annotated.Syntax as A (ClassDecl(..), ConDecl(..), Decl(..), DeclHead(..), ExportSpec(..), FieldDecl(..), GadtDecl(..), ImportSpec(..), InstHead(..), Match(..), Name, Pat(..), PatField(..), QName(..), QualConDecl(..), RPat(..))
+import qualified Language.Haskell.Exts.Syntax as S (CName(..), ExportSpec(..), ImportSpec(..), Name(..), QName(..))
+
+-- | Do a fold over the names that are declared in a declaration (not
+-- every name that appears, just the ones that the declaration is
+-- causing to exist - what's the word for that?  Reify!)
+class FoldDeclared a where
+    foldDeclared :: forall r. (Maybe S.Name -> r -> r) -> r -> a -> r
+
+instance FoldDeclared (A.Decl a) where
+    foldDeclared f r (A.TypeDecl _ x _t) = foldDeclared f r x  -- type x = ...
+    foldDeclared f r (A.TypeFamDecl _ x _k) = foldDeclared f r x -- data family x = ...
+    foldDeclared f r (A.DataDecl _ _ _ x _ _) = foldDeclared f r x -- data/newtype _ x = ...
+    foldDeclared f r (A.GDataDecl _ _ _ x _ _ _) = foldDeclared f r x
+    foldDeclared f r (A.DataFamDecl _ _ x _) = foldDeclared f r x
+    foldDeclared f r (A.TypeInsDecl _ _ _) = f Nothing r -- type instance _ = ...
+    foldDeclared f r (A.DataInsDecl _ _ _ _ _) = f Nothing r -- data instance _ = ...
+    foldDeclared f r (A.GDataInsDecl _ _ _ _ _ _) = f Nothing r -- data or newtype instance, GADT style
+    foldDeclared f r (A.ClassDecl _ _ x _ _) = foldDeclared f r x  -- class context => x | fundeps where decls
+    foldDeclared f r (A.InstDecl _ _ _ _) = f Nothing r -- type class instance
+    foldDeclared f r (A.DerivDecl _ _ x) = foldDeclared f r x
+    foldDeclared f r (A.InfixDecl _ _ _ _) = f Nothing r -- fixity
+    foldDeclared f r (A.DefaultDecl _ _) = f Nothing r -- default (type1, type2 ...)
+    foldDeclared f r (A.SpliceDecl _ _) = f Nothing r  -- template haskell splice declaration
+    foldDeclared f r (A.TypeSig _ xs _) = foldl (foldDeclared f) r xs
+    foldDeclared f r (A.FunBind _ xs) = foldl (foldDeclared f) r xs
+    foldDeclared f r (A.PatBind _ x _ _ _) = foldDeclared f r x
+    foldDeclared _f _r (A.ForImp _ _ _ _ _ _) = error "Unimplemented FoldDeclared instance: ForImp"
+    foldDeclared _ _r (A.ForExp _ _ _ _ _) = error "Unimplemented FoldDeclared instance: ForExp"
+    foldDeclared f r (A.RulePragmaDecl _ _) = f Nothing r
+    foldDeclared f r (A.DeprPragmaDecl _ _) = f Nothing r
+    foldDeclared f r (A.WarnPragmaDecl _ _) = f Nothing r
+    foldDeclared f r (A.InlineSig _ _ _ x) = foldDeclared f r x
+    foldDeclared f r (A.InlineConlikeSig _ _ x) = foldDeclared f r x
+    foldDeclared f r (A.SpecSig _ x _) = foldDeclared f r x
+    foldDeclared f r (A.SpecInlineSig _ _ _ x _) = foldDeclared f r x
+    foldDeclared f r (A.InstSig _ _ x) = foldDeclared f r x
+    foldDeclared f r (A.AnnPragma _ _) = f Nothing r
+
+instance FoldDeclared (A.DeclHead a) where
+    foldDeclared f r (A.DHead _ x _) = foldDeclared f r x
+    foldDeclared f r (A.DHInfix _ _ x _) = foldDeclared f r x
+    foldDeclared f r (A.DHParen _ x) = foldDeclared f r x
+instance FoldDeclared (A.ClassDecl a) where
+    foldDeclared f r (A.ClsDecl _ x) = foldDeclared f r x	-- ordinary declaration
+    foldDeclared f r (A.ClsDataFam _ _ x _) = foldDeclared f r x	-- declaration of an associated data type
+    foldDeclared f r (A.ClsTyFam _ x _) = foldDeclared f r x	-- declaration of an associated type synonym
+    foldDeclared _ r (A.ClsTyDef _ _ _) = r -- default choice for an associated type synonym
+instance FoldDeclared (A.InstHead a) where
+    foldDeclared f r (A.IHead _ x _) = foldDeclared f r x
+    foldDeclared f r (A.IHInfix _ _ x _) = foldDeclared f r x
+    foldDeclared f r (A.IHParen _ x) = foldDeclared f r x
+instance FoldDeclared (A.Match a) where
+    foldDeclared f r (A.Match _ x _ _ _) = foldDeclared f r x
+    foldDeclared f r (A.InfixMatch _ _ x _ _ _) = foldDeclared f r x
+-- Can you declare something with a qualified name?
+instance FoldDeclared (A.QName a) where
+    foldDeclared f r (A.Qual _ _ x) = foldDeclared f r x
+    foldDeclared f r (A.UnQual _ x) = foldDeclared f r x
+    foldDeclared _ r (A.Special _ _) = r
+instance FoldDeclared (A.Pat a) where
+    foldDeclared f r (A.PVar _ x) = foldDeclared f r x	-- variable
+    foldDeclared _ r (A.PLit _ _) = r	-- literal constant
+    foldDeclared f r (A.PNeg _ x) = foldDeclared f r x	-- negated pattern
+    foldDeclared f r (A.PNPlusK _ x _) = foldDeclared f r x	-- n+k pattern
+    foldDeclared f r (A.PInfixApp _ p1 _qn p2) = let r' = foldDeclared f r p1 in foldDeclared f r' p2	-- pattern with an infix data constructor
+    foldDeclared f r (A.PApp _ _ ps) = foldl (foldDeclared f) r ps	-- data constructor and argument patterns
+    foldDeclared f r (A.PTuple _ ps) = foldl (foldDeclared f) r ps	-- tuple pattern
+    foldDeclared f r (A.PList _ ps) = foldl (foldDeclared f) r ps	-- list pattern
+    foldDeclared f r (A.PParen _ x) = foldDeclared f r x	-- parenthesized pattern
+    foldDeclared f r (A.PRec _ _qn fs) = foldl (foldDeclared f) r fs	-- labelled pattern, record style
+    foldDeclared f r (A.PAsPat _ x y) = let r' = foldDeclared f r x in foldDeclared f r' y	-- @-pattern
+    foldDeclared _ r (A.PWildCard _) = r	-- wildcard pattern: _
+    foldDeclared f r (A.PIrrPat _ x) = foldDeclared f r x	-- irrefutable pattern: ~pat
+    foldDeclared f r (A.PatTypeSig _ x _) = foldDeclared f r x	-- pattern with type signature
+    foldDeclared f r (A.PViewPat _ _ x) = foldDeclared f r x	-- view patterns of the form (exp -> pat)
+    foldDeclared f r (A.PRPat _ rps) = foldl (foldDeclared f) r rps	-- regular list pattern
+    foldDeclared _f _r (A.PXTag _ _xn _pxs _mp _ps) = error "Unimplemented FoldDeclared instance: PXTag"	-- XML element pattern
+    foldDeclared _f _r (A.PXETag _ _xn _pxs _mp) = error "Unimplemented FoldDeclared instance: PXETag"	-- XML singleton element pattern
+    foldDeclared _f _r (A.PXPcdata _ _s) = error "Unimplemented FoldDeclared instance: XPcdata"	-- XML PCDATA pattern
+    foldDeclared _f _r (A.PXPatTag _ _p) = error "Unimplemented FoldDeclared instance: PXPatTag"	-- XML embedded pattern
+    foldDeclared _f _r (A.PXRPats _ _rps) = error "Unimplemented FoldDeclared instance: PXRPats"	-- XML regular list pattern
+    foldDeclared _f _r (A.PExplTypeArg _ _n _t) = error "Unimplemented FoldDeclared instance: PExplTypeArg"	-- Explicit generics style type argument e.g. f {| Int |} x = ...
+    foldDeclared _ r (A.PQuasiQuote _ _ _) = r	-- quasi quote pattern: [$name| string |]
+    foldDeclared f r (A.PBangPat _ x) = foldDeclared f r x	-- strict (bang) pattern: f !x = ...
+instance FoldDeclared (A.PatField a) where
+    foldDeclared f r (A.PFieldPat _ _n x) = foldDeclared f r x 	-- ordinary label-pattern pair
+    foldDeclared f r (A.PFieldPun _ x) = foldDeclared f r x 	-- record field pun
+    foldDeclared _ r (A.PFieldWildcard _) = r
+instance FoldDeclared (A.RPat a) where
+    foldDeclared f r (A.RPOp _ x _) = foldDeclared f r x	-- operator pattern, e.g. pat*
+    foldDeclared f r (A.RPEither _ x y) = let r' = foldDeclared f r x in foldDeclared f r' y 	-- choice pattern, e.g. (1 | 2)
+    foldDeclared f r (A.RPSeq _ xs) = foldl (foldDeclared f) r xs	-- sequence pattern, e.g. (| 1, 2, 3 |)
+    foldDeclared f r (A.RPGuard _ x _) = foldDeclared f r x	-- guarded pattern, e.g. (| p | p < 3 |)
+    foldDeclared f r (A.RPCAs _ n x) = let r' = foldDeclared f r n in foldDeclared f r' x 	-- non-linear variable binding, e.g. (foo@:(1 | 2))*
+    foldDeclared f r (A.RPAs _ n x) = let r' = foldDeclared f r n in foldDeclared f r' x  	-- linear variable binding, e.g. foo@(1 | 2)
+    foldDeclared f r (A.RPParen _ x) = foldDeclared f r x	-- parenthesised pattern, e.g. (2*)
+    foldDeclared f r (A.RPPat _ x) = foldDeclared f r x	-- an ordinary pattern
+
+instance FoldDeclared (A.Name l) where
+    foldDeclared f r x = f (Just (sName x)) r
+
+-- Something imported can be exported
+instance FoldDeclared (A.ImportSpec l) where
+    foldDeclared f r (A.IVar _ name) = foldDeclared f r name
+    foldDeclared f r (A.IAbs _ name) = foldDeclared f r name
+    foldDeclared f r (A.IThingAll _ name) = foldDeclared f r name
+    foldDeclared f r (A.IThingWith _ name _) = foldDeclared f r name
+
+instance FoldDeclared (A.ExportSpec l) where
+    foldDeclared f r (A.EVar _ name) = foldDeclared f r name
+    foldDeclared f r (A.EAbs _ name) = foldDeclared f r name
+    foldDeclared f r (A.EThingAll _ name) = foldDeclared f r name
+    foldDeclared f r (A.EThingWith _ name _) = foldDeclared f r name
+    foldDeclared _ r (A.EModuleContents _ _) = r -- This probably won't work correctly
+
+-- Return the set of symbols appearing in a construct.  Some
+-- constructs, such as instance declarations, declare no symbols, in
+-- which case Nothing is returned.  Some declare more than one.
+symbols :: FoldDeclared a => a -> Set (Maybe S.Name)
+symbols = foldDeclared insert empty
+
+members :: FoldMembers a => a -> Set (Maybe S.Name)
+members = foldMembers insert empty
+
+justs :: Set (Maybe a) -> [a]
+justs = mapMaybe id . toList
+
+exports :: (FoldDeclared a, FoldMembers a) => a -> [S.ExportSpec]
+exports x = case (justs (symbols x), justs (members x)) of
+              ([n], []) -> [S.EVar (S.UnQual n)]
+              ([n], ms) -> [S.EThingWith (S.UnQual n) (sort (map S.VarName ms))]
+              ([], []) -> []
+              ([], _) -> error "exports: members with no top level name"
+              (ns, []) -> map (S.EVar . S.UnQual) ns
+              y -> error $ "exports: multiple top level names and member names: " ++ show y
+
+imports :: (FoldDeclared a, FoldMembers a) => a -> [S.ImportSpec]
+imports x = case (justs (symbols x), justs (members x)) of
+              ([n], []) -> [S.IVar n]
+              ([n], ms) -> [S.IThingWith n (sort (map S.VarName ms))]
+              ([], []) -> []
+              ([], _ms) -> error "exports: members with no top level name"
+              (ns, []) -> map S.IVar ns
+              y -> error $ "imports: multiple top level names and member names: " ++ show y
+
+-- | Fold over the declared members - e.g. the method names of a class
+-- declaration, the constructors of a data declaration.
+class FoldMembers a where
+    foldMembers :: forall r. (Maybe S.Name -> r -> r) -> r -> a -> r
+
+instance FoldMembers (A.Decl a) where
+    foldMembers f r (A.ClassDecl _ _ _ _ mxs) = maybe r (foldl (foldDeclared f) r) mxs  -- class context => x | fundeps where decls
+    foldMembers f r (A.DataDecl _ _ _ _ xs _) = foldl (foldDeclared f) r xs -- data/newtype _ x = ...
+    foldMembers f r (A.GDataDecl _ _ _ _ _ xs _) = foldl (foldDeclared f) r xs
+    foldMembers _ r _ = r
+
+-- The following instances of FoldDeclared are only called by the FoldMembers instances.  Hopefully.
+instance FoldDeclared (A.QualConDecl l) where
+    foldDeclared f r (A.QualConDecl _l _ _ x) = foldDeclared f r x
+
+-- Constructors and field names
+instance FoldDeclared (A.ConDecl l) where
+    foldDeclared f r (A.ConDecl _ x _ts) = foldDeclared f r x	-- ordinary data constructor
+    foldDeclared f r (A.InfixConDecl _ _t1 x _t2) = foldDeclared f r x	-- infix data constructor
+    foldDeclared f r (A.RecDecl _ x fs) = let r' = foldDeclared f r x in foldl (foldDeclared f) r' fs 	-- record constructor
+
+instance FoldDeclared (A.FieldDecl l) where
+    foldDeclared f r (A.FieldDecl _ xs _) = foldl (foldDeclared f) r xs
+
+instance FoldDeclared (A.GadtDecl l) where
+    foldDeclared f r (A.GadtDecl _ x _) = foldDeclared f r x
diff --git a/Tests/Fold.hs b/Tests/Fold.hs
--- a/Tests/Fold.hs
+++ b/Tests/Fold.hs
@@ -15,7 +15,7 @@
 import Language.Haskell.Modules.ModuVerse (ModuleInfo(..), parseModule)
 import Language.Haskell.Modules.Params (runCleanT)
 import Language.Haskell.Modules.SourceDirs (pathKey, APath(..))
-import Language.Haskell.Modules.SrcLoc (HasSpanInfo(..), makeTree)
+import Language.Haskell.Modules.Util.SrcLoc (HasSpanInfo(..), makeTree)
 import Test.HUnit (assertEqual, Test(TestList, TestCase, TestLabel))
 
 deriving instance Eq (Exts.ParseResult (A.Module SrcSpanInfo, [A.Comment]))
diff --git a/Tests/Imports.hs b/Tests/Imports.hs
--- a/Tests/Imports.hs
+++ b/Tests/Imports.hs
@@ -1,7 +1,7 @@
-{-# LANGUAGE PackageImports #-}
+{-# LANGUAGE CPP, PackageImports #-}
 module Tests.Imports where
 
-import Language.Haskell.Exts.Extension (Extension(FlexibleInstances, StandaloneDeriving, TypeSynonymInstances))
+
 import qualified Language.Haskell.Exts.Syntax as S (ModuleName(ModuleName))
 import Language.Haskell.Modules (cleanImports, modifyExtensions, modifyTestMode, modulePathBase, putDirs, runCleanT, withCurrentDirectory)
 import Language.Haskell.Modules.SourceDirs (RelPath(unRelPath))
@@ -11,6 +11,16 @@
 import System.Process (readProcessWithExitCode)
 import Test.HUnit (assertEqual, Test(..))
 
+#if MIN_VERSION_haskell_src_exts(1,14,0)
+import Language.Haskell.Exts.Extension (KnownExtension(FlexibleInstances, StandaloneDeriving, TypeSynonymInstances),Extension(EnableExtension))
+nameToExtension x = EnableExtension x
+
+#else
+import Language.Haskell.Exts.Extension (Extension(FlexibleInstances, StandaloneDeriving, TypeSynonymInstances))
+nameToExtension x = x
+
+#endif
+
 tests :: Test
 tests = TestLabel "Clean" (TestList [test1, test2, test3, test4, test5, test6, test7])
 
@@ -77,7 +87,7 @@
       (do _ <- rsync "testdata/imports5" "tmp"
           _ <- runCleanT
                  (putDirs ["tmp"] >>
-                  modifyExtensions (++ [StandaloneDeriving, TypeSynonymInstances, FlexibleInstances]) >>
+                  modifyExtensions (++ map nameToExtension [StandaloneDeriving, TypeSynonymInstances, FlexibleInstances]) >>
                   cleanImports ["tmp/Deriving.hs"])
           (code, out, err) <- diff "testdata/imports5" "tmp"
           assertEqual "standalone deriving"
diff --git a/Tests/SrcLoc.hs b/Tests/SrcLoc.hs
--- a/Tests/SrcLoc.hs
+++ b/Tests/SrcLoc.hs
@@ -3,7 +3,7 @@
 module Tests.SrcLoc where
 
 import Language.Haskell.Exts.SrcLoc (SrcLoc(..))
-import Language.Haskell.Modules.SrcLoc (srcPairText)
+import Language.Haskell.Modules.Util.SrcLoc (srcPairText)
 import Prelude hiding (rem)
 import Test.HUnit (assertEqual, Test(TestCase, TestList))
 
diff --git a/Tests/Symbols.hs b/Tests/Symbols.hs
--- a/Tests/Symbols.hs
+++ b/Tests/Symbols.hs
@@ -9,13 +9,13 @@
     ) where
 
 import Data.Set (fromList)
-import Language.Haskell.Exts.Annotated.Syntax as A (Decl(DefaultDecl, PatBind), Exp(Var), Name(Ident), Pat(PApp, PVar), QName(UnQual), Rhs(UnGuardedRhs), Type(TyVar))
-import Language.Haskell.Exts.Parser (fromParseResult, parse)
+import Language.Haskell.Exts.Annotated.Syntax as A -- (Decl(DefaultDecl, PatBind), Exp(Var), Name(Ident), Pat(PApp, PVar), QName(UnQual), Rhs(UnGuardedRhs), Type(TyVar))
+import Language.Haskell.Exts.Parser (parse, fromParseResult)
 import Language.Haskell.Exts.Pretty (prettyPrint)
 import Language.Haskell.Exts.SrcLoc (SrcSpan(..), SrcSpanInfo(..))
-import qualified Language.Haskell.Exts.Syntax as S (Name(Ident))
-import Language.Haskell.Modules.Symbols (members, symbols)
-import Language.Haskell.Modules.SrcLoc ()
+import qualified Language.Haskell.Exts.Syntax as S
+import Language.Haskell.Modules.Util.SrcLoc ()
+import Language.Haskell.Modules.Util.Symbols (symbols, members)
 import Test.HUnit (assertEqual, Test(TestCase, TestList))
 
 tests :: Test
diff --git a/debian/changelog b/debian/changelog
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+haskell-module-management (0.16) unstable; urgency=low
+
+  * Use haskeline in the hmm program (Adam Vogt)
+  * use case insensitive completion when it is unambiguous (Adam Vogt)
+  * Clean up issues involving fixities (Adam Vogt)
+  * Preliminary support for cabal files (Adam Vogt)
+  * And more by Adam...
+
+ -- David Fox <dsf@seereason.com>  Fri, 16 Aug 2013 08:48:58 -0700
+
 haskell-module-management (0.15.1) unstable; urgency=low
 
   * Documentation updates.
diff --git a/module-management.cabal b/module-management.cabal
--- a/module-management.cabal
+++ b/module-management.cabal
@@ -1,5 +1,5 @@
 Name:               module-management
-Version:            0.15.1
+Version:            0.16
 Synopsis:           Clean up module imports, split and merge modules
 Description:        Clean up module imports, split and merge modules.
 Homepage:           http://src.seereason.com/module-management
@@ -28,10 +28,10 @@
     Language.Haskell.Modules.Params,
     Language.Haskell.Modules.SourceDirs,
     Language.Haskell.Modules.Split,
-    Language.Haskell.Modules.SrcLoc,
-    Language.Haskell.Modules.Symbols,
     Language.Haskell.Modules.Util.DryIO,
     Language.Haskell.Modules.Util.QIO,
+    Language.Haskell.Modules.Util.SrcLoc,
+    Language.Haskell.Modules.Util.Symbols,
     Language.Haskell.Modules.Util.Temp,
     Language.Haskell.Modules.Util.Test
   Other-Modules:
@@ -41,6 +41,7 @@
     Tests.Split
     Tests.SrcLoc
     Tests.Symbols
+
   Build-Depends:
     applicative-extras,
     base >= 4 && < 5,
@@ -64,7 +65,8 @@
     temporary
 
 Executable hmm
-  Main-is: scripts/CLI.hs
+  Main-is: CLI.hs
+  Hs-source-dirs: scripts
   Build-Depends:
     base,
     containers,
@@ -80,7 +82,14 @@
     process,
     set-extra,
     syb,
-    temporary
+    temporary,
+    haskeline == 0.7.*,
+    transformers-base,
+    Cabal,
+    cmdargs,
+    lens
+
+  ghc-options: -O0
 
 Executable tests
   Main-is: Tests.hs
diff --git a/scripts/CLI.hs b/scripts/CLI.hs
--- a/scripts/CLI.hs
+++ b/scripts/CLI.hs
@@ -1,60 +1,294 @@
-{-# OPTIONS_GHC -Wall #-}
+{- # OPTIONS_GHC -Wall #-}
+{-# LANGUAGE ViewPatterns, PatternGuards, DeriveDataTypeable #-}
 module Main where
 
+import System.Console.Haskeline
+import Control.Monad.State
+
+import System.Environment
+import System.Directory
+import CLI.HaskelineTransAdapter ()
 import Control.Monad as List (mapM_)
-import Control.Monad.Trans (MonadIO(liftIO))
-import Data.List (intercalate, isPrefixOf)
+import Control.Monad.Trans (MonadIO(liftIO), MonadTrans(..))
+import Data.List
+import Data.Maybe (maybeToList)
+import Data.Char (toLower)
+import qualified Data.Set as S (member, toList, map)
 import Data.Set.Extra as Set (Set, toList)
-import Language.Haskell.Modules
+import Language.Haskell.Modules (cleanImports, CleanT, findHsModules, mergeModules, modifyDirs, ModuleName(..), MonadClean, noisily, putDirs, putModule, runCleanT, splitModuleDecls)
 import Language.Haskell.Modules.ModuVerse (getNames)
 import Language.Haskell.Modules.SourceDirs (getDirs)
-import System.IO (hGetLine, hPutStr, hPutStrLn, stderr, stdin)
+import Language.Haskell.Modules.Util.QIO (modifyVerbosity)
+import System.Console.Haskeline (completeFilename, CompletionFunc, defaultSettings, getInputLine, InputT, noCompletion, runInputT, setComplete, simpleCompletion)
+import System.IO (hPutStrLn, stderr)
 
+import System.Console.CmdArgs
+import Control.Lens
+import Data.Maybe
+
+import Control.Monad.Reader
+
+import Distribution.PackageDescription (GenericPackageDescription)
+
+import qualified CLI.Cabal as Cabal
+import qualified Distribution.Verbosity
+import Data.Data
+
+import Data.Foldable(traverse_)
+import System.Console.Haskeline.MonadException
+import Control.Exception (fromException)
+
+import System.Exit
+
+data HMM = CLI
+  { verbosity :: Int,
+    verbosityCabal :: Int,
+    caseSensitiveCompletion :: Bool,
+    cabalFile :: Maybe FilePath,
+    otherFiles :: [FilePath] }
+    deriving (Data,Typeable,Show)
+
+defaultHMM = CLI
+  { Main.verbosity = fromEnum Loud
+            &= enumHelp "module-management verbosity" (undefined :: Verbosity)
+                        (Main.verbosity defaultHMM),
+    verbosityCabal = fromEnum (maxBound :: Distribution.Verbosity.Verbosity)
+            &= enumHelp "cabal file parser verbosity"
+                        (undefined :: Distribution.Verbosity.Verbosity)
+                        (verbosityCabal defaultHMM),
+    caseSensitiveCompletion = False
+            &= help "should completion of module names be case-sensitive?"
+            &= name "s",
+    cabalFile = Nothing
+            &= typFile
+            &= name "f"
+            &= help ".cabal file to load. Modules listed there will be loaded\
+                \ and when modules are split the .cabal file will be updated\
+                \ when you quit or use the cabalWrite command",
+    otherFiles = []
+            &= typFile
+            &= args }
+
+
+enumHelp item proxy def =
+    help ("Level of "++item++". Takes values from " ++
+            rangeOfBounded (undefined `asTypeOf` proxy) ++
+            ". Default is "++ show def ++ ".")
+rangeOfBounded proxy = show (fromEnum (minBound `asTypeOf` proxy))
+    ++ " to "
+    ++ show (fromEnum (maxBound `asTypeOf` proxy))
+
+
+toEnumBounded :: (Bounded e, Enum e) => Int -> e
+toEnumBounded i =
+    let r | i > iMax = maxBound
+          | i < iMin = minBound
+          | otherwise = toEnum i
+        iMax = fromEnum (maxBound `asTypeOf` r)
+        iMin = fromEnum (minBound `asTypeOf` r)
+    in r
+
 main :: IO ()
-main = runCleanT (noisily cli)
+main = do
+    conf <- cmdArgs defaultHMM
+    args <- mapM canonicalizePath (otherFiles conf)
 
-cli :: MonadClean m => m ()
-cli = liftIO (hPutStr stderr " > " >> hGetLine stdin) >>= cmd . words
+    pkgDesc' <-
+        traverse (Cabal.readPackageDescription (toEnumBounded (verbosityCabal conf)))
+            (cabalFile conf)
 
-cmd :: MonadClean m => [String] -> m ()
+
+    let initState = do
+            traverse (dir . (".":) . Cabal.getSrcDirs) pkgDesc'
+            modifyVerbosity $ \ _ -> Main.verbosity conf
+            let modules0 = args ++ (map moduleNameToStr $ Cabal.getModules =<< maybeToList pkgDesc')
+            when (not (null modules0)) $ verse modules0
+
+
+        execCmdM :: CmdM a -> IO (Maybe GenericPackageDescription)
+        execCmdM x = runCleanT
+            $ flip execStateT pkgDesc'
+            $ flip runReaderT conf
+            $ runInputT (setComplete ((lift . lift) `fmap` compl conf) defaultSettings) x
+
+    pkgDesc' <- execCmdM $ do
+        liftCT initState
+        let step = cli
+            loop = catch (do step; loop) $ \e @ SomeException {} -> case () of
+                    _ | Just e <- fromException e -> throwIO (e `asTypeOf` ExitSuccess)
+                      | Just (Callback _msg f) <- fromException e -> f loop
+                    _ -> do
+                        liftIO (print e)
+                        loop
+        loop
+
+    -- this gets bypassed when the ExitCode is re-thrown.
+    -- Should it be run on ExitFailures or just success?
+    traverse_ (uncurry Cabal.writeGenericPackageDescription)
+        $ liftM2 (,) (cabalFile conf) pkgDesc'
+
+
+-- | these versions of quietly and noisily play well with 'lift'
+quietly', noisily' :: CmdM a -> CmdM a
+quietly' act = do
+    liftCT (modifyVerbosity (\x -> x - 1))
+    r <- act
+    liftCT (modifyVerbosity (+ 1))
+    return r
+
+noisily' act = do
+    liftCT (modifyVerbosity (+ 1))
+    r <- act
+    liftCT (modifyVerbosity (\x -> x - 1))
+    return r
+
+compl ::  HMM -> CompletionFunc (CleanT IO)
+compl conf (xs,ys) | cmd: _ <- words (reverse xs),
+    matchingCommands <- filter (cmd `isPrefixOf`) commandNames = case matchingCommands of
+        _:_:_ | Nothing <- stripPrefix " " =<< stripPrefix cmd (reverse xs) ->
+                return ("", map simpleCompletion matchingCommands)
+        [] -> return ("", map simpleCompletion commandNames)
+
+        [x] | cmd `notElem` commandNames -> return ("", [simpleCompletion x])
+            | takesModuleNames cmd -> do
+                ns <- getNames
+                let complAllModules = map (simpleCompletion . moduleNameToStr) (S.toList ns)
+                    nsLower = S.map (ModuleName . map toLower . moduleNameToStr) ns
+                    transform
+                        | caseSensitiveCompletion conf = id
+                        | nsLower == ns = map toLower
+                        | otherwise = id
+                return $ case span (/=' ') xs of
+                    (reverse -> cw @ (_:_), rest) ->
+                        case filter (isPrefixOf (transform cw) . transform)
+                                        (moduleNameToStr `map` S.toList ns) of
+                            -- this first case isn't really needed: it should do the same as the
+                            -- next case but possibly be more efficient
+                            _ | ModuleName cw `S.member` ns -> (rest, [simpleCompletion cw])
+                            [modName] -> (rest, [simpleCompletion modName])
+                            _ -> (rest, complAllModules)
+                    _ -> (xs, complAllModules)
+            | otherwise  -> completeFilename (xs,ys)
+        _ -> noCompletion (xs,ys)
+compl _ x = noCompletion x
+
+moduleNameToStr :: ModuleName -> String
+moduleNameToStr (ModuleName x) = x
+
+takesModuleNames :: String -> Bool
+takesModuleNames x = x `elem` ["merge"]
+
+
+cli :: CmdM ()
+cli = cmd . concatMap words . maybeToList =<< getInputLine "> "
+
+type CmdM a = InputT (ReaderT HMM (StateT (Maybe GenericPackageDescription) (CleanT IO))) a
+
+askConf :: CmdM HMM
+askConf = lift ask
+
+liftCT :: CleanT IO a -> CmdM a
+liftCT = lift . lift . lift
+
+liftS :: StateT (Maybe GenericPackageDescription) (CleanT IO) a -> CmdM a
+liftS  = lift . lift
+
+
+cmd :: [String] -> CmdM ()
 cmd [] = cli
 cmd (s : args) =
-    case filter (any (== s) . fst) cmds of
-      [(_, f)] -> f
-      -- No exact matches - look for prefix matches
-      [] -> case filter (any (isPrefixOf s) . fst) cmds of
-              [(_, f)] -> f
-              [] -> liftIO (hPutStrLn stderr $
-                              show s ++ " invalid - expected " ++ intercalate ", " (concatMap fst cmds)) >> cli
-              xs -> liftIO (hPutStrLn stderr $
-                              show s ++ " ambiguous - expected " ++ intercalate ", " (concatMap fst xs)) >> cli
-      _ -> error $ "Internal error - multiple definitions for " ++ show s
-    where
-      cmds =
-          [(["quit", "exit", "bye", "."],	liftIO (hPutStrLn stderr "Exiting")),
-           (["v"],				liftIO (hPutStrLn stderr "Increasing verbosity level") >> noisily cli),
-           (["q"],				liftIO (hPutStrLn stderr "Decreasing verbosity level") >> quietly cli),
-           (["help"],				liftIO (hPutStrLn stderr "help text") >> cli),
-           (["verse"],				verse args >> cli),
-           (["clean"],				clean args >> cli),
-           (["dir"],				dir args >> cli),
-           (["split"],				split args >> cli),
-           (["merge"],				merge args >> cli)]
+      case filter (any (== s) . fst) cmds of
+        [(_, f)] -> f
+        -- No exact matches - look for prefix matches
+        [] -> case filter (any (isPrefixOf s) . fst) cmds of
+                [(_, f)] -> f
+                [] -> liftIO (hPutStrLn stderr $
+                                show s ++ " invalid - expected " ++ intercalate ", " (concatMap fst cmds)) >> cli
+                xs -> liftIO (hPutStrLn stderr $
+                                show s ++ " ambiguous - expected " ++ intercalate ", " (concatMap fst xs)) >> cli
+        _ -> error $ "Internal error - multiple definitions for " ++ show s
+        where
+        cmds = cmds_ args
 
+
+data Callback = Callback String (CmdM () -> CmdM ()) deriving (Typeable)
+instance Show Callback where
+    show (Callback x _) = x
+instance Exception Callback
+
+commandNames :: [String]
+commandNames = concatMap fst (cmds_ undefined)
+
+cmds_ :: [String] -> [([String], CmdM ())]
+cmds_ args =
+          [(["quit", "exit", "bye", ".", "\EOT"], do
+                liftIO (hPutStrLn stderr "Exiting")
+                throwIO ExitSuccess),
+           (["v"], throwIO . Callback "louder" $ \next -> do
+                    liftIO (hPutStrLn stderr "Increasing Verbosity")
+                    noisily' next),
+           (["q"], throwIO . Callback "quieter" $ \next -> do
+                    liftIO (hPutStrLn stderr "Decreasing Verbosity")
+                    quietly' next),
+           (["help"],  liftIO (hPutStrLn stderr "help text")),
+           (["verse"], liftCT (verse args)),
+           (["clean"], liftCT (clean args)),
+           (["dir"],   liftCT (dir args)),
+           (["split"], split args),
+           (["merge"], merge args),
+           (["cabalPrint"], cabalPrint),
+           (["cabalRead"], cabalRead args),
+           (["cabalWrite"], cabalWrite args)]
+
+cabalPrint :: CmdM ()
+cabalPrint = do
+    pkgDesc <- liftS get
+    liftIO $ putStrLn $ case pkgDesc of
+        Nothing -> "No cabal file loaded"
+        Just x -> Cabal.showGenericPackageDescription x
+
+cabalWrite, cabalRead :: [String] -> CmdM ()
+cabalWrite [f] = do
+    pkgDesc <- liftS get
+    liftIO $ case pkgDesc of
+        Nothing -> putStrLn "cabalWrite: no cabal file was loaded"
+        Just x -> Cabal.writeGenericPackageDescription f x
+cabalWrite [] = do
+    conf <- askConf
+    case cabalFile conf of
+        Nothing -> liftIO $ putStrLn "Usage: cabalWrite <file.cabal>"
+        Just f -> cabalWrite [f] -- goto previous case
+cabalWrite _ = liftIO $ putStrLn "Usage: cabalWrite <file.cabal>"
+
+cabalRead [f] = throwIO . Callback "cabalRead" $ \next -> do
+    conf <- askConf
+    pd <- liftIO $ Cabal.readPackageDescription (toEnumBounded (verbosityCabal conf)) f
+
+    liftCT $ do
+        ds <- getDirs
+        let ds' = Cabal.getSrcDirs pd
+        unless (null $ ds' \\ ds) $ dir ds'
+
+        verse (unModuleName `map` Cabal.getModules pd)
+
+    mapInputT (local (\x -> x{ cabalFile = Just f })) next
+
+cabalRead _ = liftIO $ putStrLn "Usage: cabalRead <file.cabal>"
+
 unModuleName :: ModuleName -> String
 unModuleName (ModuleName x) = x
 
 verse :: MonadClean m => [String] -> m ()
 verse [] =
     do modules <- getNames
-       liftIO $ hPutStrLn stderr ("Usage: verse <pathormodule1> <pathormodule2> ...\n" ++
+       liftIO $ putStrLn ("Usage: verse <pathormodule1> <pathormodule2> ...\n" ++
                                   "Add the module or all the modules below a directory to the moduVerse\n" ++
                                   "Currently:\n  " ++ showVerse modules)
 verse args =
     do new <- mapM (liftIO . find) args
        List.mapM_ (List.mapM_ putModule) new
        modules <- getNames
-       liftIO (hPutStrLn stderr $ "moduVerse updated:\n  " ++ showVerse modules)
+       liftIO (putStrLn $ "moduVerse updated:\n  " ++ showVerse modules)
     where
       find s =
           do ms <- liftIO (findHsModules [s])
@@ -70,18 +304,23 @@
 dir xs =
     do modifyDirs (++ xs)
        xs' <- getDirs
-       liftIO (hPutStrLn stderr $ "sourceDirs updated:\n  [ " ++ intercalate "\n  , " xs' ++ " ]")
+       liftIO (putStrLn $ "sourceDirs updated:\n  [ " ++ intercalate "\n  , " xs' ++ " ]")
 
 clean :: MonadClean m => [FilePath] -> m ()
-clean [] = liftIO $ hPutStrLn stderr "Usage: clean <modulepath1> <modulepath2> ..."
+clean [] = liftIO $ putStrLn "Usage: clean <modulepath1> <modulepath2> ..."
 clean args = cleanImports args >> return ()
 
-split :: MonadClean m => [FilePath] -> m ()
-split [arg] = splitModuleDecls arg >> return ()
-split _ = liftIO $ hPutStrLn stderr "Usage: split <modulepath>"
+split :: [FilePath] -> CmdM ()
+split [arg] = do
+    r <- liftCT (splitModuleDecls arg)
+    lift (modify (Cabal.update r))
+    return ()
+split _ = liftIO $ putStrLn "Usage: split <modulepath>"
 
-merge :: MonadClean m => [String] -> m ()
+merge :: [String] -> CmdM ()
 merge args =
     case splitAt (length args - 1) args of
-      (inputs, [output]) -> mergeModules (map ModuleName inputs) (ModuleName output) >> return ()
-      _ -> liftIO $ hPutStrLn stderr "Usage: merge <inputmodulename1> <inputmodulename2> ... <outputmodulename>"
+      (inputs, [output]) -> do
+            r <- liftCT $ mergeModules (map ModuleName inputs) (ModuleName output)
+            liftS (modify (Cabal.update r))
+      _ -> liftIO $ putStrLn "Usage: merge <inputmodulename1> <inputmodulename2> ... <outputmodulename>"
diff --git a/testdata.tar.gz b/testdata.tar.gz
Binary files a/testdata.tar.gz and b/testdata.tar.gz differ
