diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,11 @@
+# 0.1.6
+
+- Fix filepath issues on Windows
+- Add support for sublibraries
+- Format `build-tool-depends`
+- Use Cabal-syntax-3.8.1.0
+- Smarter version range normaliser
+
 # 0.1.5.1
 
 - Fix bug in pretty printing empty version ranges.
diff --git a/cabal-fmt.cabal b/cabal-fmt.cabal
--- a/cabal-fmt.cabal
+++ b/cabal-fmt.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               cabal-fmt
-version:            0.1.5.1
+version:            0.1.6
 synopsis:           Format .cabal files
 category:           Development
 description:
@@ -12,7 +12,15 @@
 license-file:       LICENSE
 author:             Oleg Grenrus <oleg.grenrus@iki.fi>
 maintainer:         Oleg Grenrus <oleg.grenrus@iki.fi>
-tested-with:        GHC ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.2
+tested-with:
+  GHC ==8.4.4
+   || ==8.6.5
+   || ==8.8.4
+   || ==8.10.7
+   || ==9.0.2
+   || ==9.2.4
+   || ==9.4.1
+
 extra-source-files:
   Changelog.md
   fixtures/*.cabal
@@ -22,22 +30,34 @@
   type:     git
   location: https://github.com/phadej/cabal-fmt.git
 
+library version-interval
+  default-language: Haskell2010
+  hs-source-dirs:   src-interval
+  build-depends:
+    , base          ^>=4.11.1.0 || ^>=4.12.0.0 || ^>=4.13.0.0 || ^>=4.14.0.0 || ^>=4.15.0.0 || ^>=4.16.0.0 || ^>=4.17.0.0
+    , Cabal-syntax  ^>=3.8.1.0
+
+  exposed-modules:  VersionInterval
+
 library cabal-fmt-internal
   default-language: Haskell2010
   hs-source-dirs:   src
 
   -- GHC boot libraries
   build-depends:
-    , base        ^>=4.11.1.0 || ^>=4.12.0.0 || ^>=4.13.0.0 || ^>=4.14.0.0
-    , bytestring  ^>=0.10.8.2
-    , Cabal       ^>=3.2.0.0
-    , containers  ^>=0.5.11.0 || ^>=0.6.0.1
-    , directory   ^>=1.3.1.5
-    , filepath    ^>=1.4.2
-    , mtl         ^>=2.2.2
-    , parsec      ^>=3.1.13.0
-    , pretty      ^>=1.1.3.6
+    , base          ^>=4.11.1.0 || ^>=4.12.0.0 || ^>=4.13.0.0 || ^>=4.14.0.0 || ^>=4.15.0.0 || ^>=4.16.0.0 || ^>=4.17.0.0
+    , bytestring    ^>=0.10.8.2 || ^>=0.11.3.1
+    , Cabal-syntax  ^>=3.8.1.0
+    , containers    ^>=0.5.11.0 || ^>=0.6.0.1
+    , directory     ^>=1.3.1.5
+    , filepath      ^>=1.4.2
+    , mtl           ^>=2.2.2
+    , parsec        ^>=3.1.13.0
+    , pretty        ^>=1.1.3.6
 
+  -- our version interval normalisation
+  build-depends:    version-interval
+
   -- cabal-fmt: expand src
   exposed-modules:
     CabalFmt
@@ -87,7 +107,7 @@
     , filepath
 
   -- extra dependencies
-  build-depends:    optparse-applicative >=0.14.3.0 && <0.17
+  build-depends:    optparse-applicative >=0.14.3.0 && <0.18
 
 test-suite golden
   type:             exitcode-stdio-1.0
@@ -99,8 +119,8 @@
   build-depends:
     , base
     , bytestring
-    , Cabal
     , cabal-fmt-internal
+    , Cabal-syntax
     , containers
 
   -- test dependencies
@@ -109,5 +129,21 @@
     , process
     , tasty
     , tasty-golden
+    , temporary
+
+test-suite version-interval-tests
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  hs-source-dirs:   tests-interval
+  main-is:          version-interval-tests.hs
+  build-depends:
+    , base
+    , Cabal-syntax
+    , integer-logarithms  ^>=1.0.3.1
+    , QuickCheck
+    , tasty
+    , tasty-hunit
+    , tasty-quickcheck
+    , version-interval
 
 -- end file comment
diff --git a/cli/Main.hs b/cli/Main.hs
--- a/cli/Main.hs
+++ b/cli/Main.hs
@@ -4,8 +4,6 @@
 module Main (main) where
 
 import Control.Applicative (many, (<**>))
-import Control.Monad       (unless, when)
-import Data.Foldable       (asum, for_)
 import Data.Traversable    (for)
 import Data.Version        (showVersion)
 import System.Exit         (exitFailure)
diff --git a/fixtures/Cabal-notab.cabal b/fixtures/Cabal-notab.cabal
new file mode 100644
--- /dev/null
+++ b/fixtures/Cabal-notab.cabal
@@ -0,0 +1,653 @@
+name:          Cabal
+version:       2.5.0.0
+-- cabal-fmt: no-tabular
+copyright:     2003-2018, Cabal Development Team (see AUTHORS file)
+license:       BSD3
+license-file:  LICENSE
+author:        Cabal Development Team <cabal-devel@haskell.org>
+maintainer:    cabal-devel@haskell.org
+homepage:      http://www.haskell.org/cabal/
+bug-reports:   https://github.com/haskell/cabal/issues
+synopsis:      A framework for packaging Haskell software
+description:
+  The Haskell Common Architecture for Building Applications and
+  Libraries: a framework defining a common interface for authors to more
+  easily build their Haskell applications in a portable way.
+  .
+  The Haskell Cabal is part of a larger infrastructure for distributing,
+  organizing, and cataloging Haskell libraries and tools.
+category:       Distribution
+cabal-version:  >=1.10
+build-type:     Simple
+-- If we use a new Cabal feature, this needs to be changed to Custom so
+-- we can bootstrap.
+
+extra-source-files:
+  README.md tests/README.md ChangeLog.md
+  doc/bugs-and-stability.rst doc/concepts-and-development.rst
+  doc/conf.py doc/config-and-install.rst doc/developing-packages.rst
+  doc/images/Cabal-dark.png doc/index.rst doc/installing-packages.rst
+  doc/intro.rst doc/misc.rst doc/nix-local-build-overview.rst
+  doc/nix-local-build.rst doc/file-format-changelog.rst doc/README.md
+  doc/references.inc
+
+  -- Generated with 'make gen-extra-source-files'
+  -- Do NOT edit this section manually; instead, run the script.
+  -- BEGIN gen-extra-source-files
+  tests/ParserTests/errors/common1.cabal
+  tests/ParserTests/errors/common1.errors
+  tests/ParserTests/errors/common2.cabal
+  tests/ParserTests/errors/common2.errors
+  tests/ParserTests/errors/common3.cabal
+  tests/ParserTests/errors/common3.errors
+  tests/ParserTests/errors/forward-compat.cabal
+  tests/ParserTests/errors/forward-compat.errors
+  tests/ParserTests/errors/forward-compat2.cabal
+  tests/ParserTests/errors/forward-compat2.errors
+  tests/ParserTests/errors/forward-compat3.cabal
+  tests/ParserTests/errors/forward-compat3.errors
+  tests/ParserTests/errors/issue-5055-2.cabal
+  tests/ParserTests/errors/issue-5055-2.errors
+  tests/ParserTests/errors/issue-5055.cabal
+  tests/ParserTests/errors/issue-5055.errors
+  tests/ParserTests/errors/leading-comma-2.cabal
+  tests/ParserTests/errors/leading-comma-2.errors
+  tests/ParserTests/errors/leading-comma-2b.cabal
+  tests/ParserTests/errors/leading-comma-2b.errors
+  tests/ParserTests/errors/leading-comma-2c.cabal
+  tests/ParserTests/errors/leading-comma-2c.errors
+  tests/ParserTests/errors/leading-comma.cabal
+  tests/ParserTests/errors/leading-comma.errors
+  tests/ParserTests/errors/multiple-libs.cabal
+  tests/ParserTests/errors/multiple-libs.errors
+  tests/ParserTests/errors/noVersion.cabal
+  tests/ParserTests/errors/noVersion.errors
+  tests/ParserTests/errors/noVersion2.cabal
+  tests/ParserTests/errors/noVersion2.errors
+  tests/ParserTests/errors/range-ge-wild.cabal
+  tests/ParserTests/errors/range-ge-wild.errors
+  tests/ParserTests/errors/removed-fields.cabal
+  tests/ParserTests/errors/removed-fields.errors
+  tests/ParserTests/errors/spdx-1.cabal
+  tests/ParserTests/errors/spdx-1.errors
+  tests/ParserTests/errors/spdx-2.cabal
+  tests/ParserTests/errors/spdx-2.errors
+  tests/ParserTests/errors/spdx-3.cabal
+  tests/ParserTests/errors/spdx-3.errors
+  tests/ParserTests/ipi/Includes2.cabal
+  tests/ParserTests/ipi/Includes2.expr
+  tests/ParserTests/ipi/Includes2.format
+  tests/ParserTests/ipi/internal-preprocessor-test.cabal
+  tests/ParserTests/ipi/internal-preprocessor-test.expr
+  tests/ParserTests/ipi/internal-preprocessor-test.format
+  tests/ParserTests/ipi/issue-2276-ghc-9885.cabal
+  tests/ParserTests/ipi/issue-2276-ghc-9885.expr
+  tests/ParserTests/ipi/issue-2276-ghc-9885.format
+  tests/ParserTests/ipi/transformers.cabal
+  tests/ParserTests/ipi/transformers.expr
+  tests/ParserTests/ipi/transformers.format
+  tests/ParserTests/regressions/MiniAgda.cabal
+  tests/ParserTests/regressions/MiniAgda.check
+  tests/ParserTests/regressions/Octree-0.5.cabal
+  tests/ParserTests/regressions/Octree-0.5.expr
+  tests/ParserTests/regressions/Octree-0.5.format
+  tests/ParserTests/regressions/bad-glob-syntax.cabal
+  tests/ParserTests/regressions/bad-glob-syntax.check
+  tests/ParserTests/regressions/cc-options-with-optimization.cabal
+  tests/ParserTests/regressions/cc-options-with-optimization.check
+  tests/ParserTests/regressions/common-conditional.cabal
+  tests/ParserTests/regressions/common-conditional.expr
+  tests/ParserTests/regressions/common-conditional.format
+  tests/ParserTests/regressions/common.cabal
+  tests/ParserTests/regressions/common.expr
+  tests/ParserTests/regressions/common.format
+  tests/ParserTests/regressions/common2.cabal
+  tests/ParserTests/regressions/common2.expr
+  tests/ParserTests/regressions/common2.format
+  tests/ParserTests/regressions/cxx-options-with-optimization.cabal
+  tests/ParserTests/regressions/cxx-options-with-optimization.check
+  tests/ParserTests/regressions/elif.cabal
+  tests/ParserTests/regressions/elif.expr
+  tests/ParserTests/regressions/elif.format
+  tests/ParserTests/regressions/elif2.cabal
+  tests/ParserTests/regressions/elif2.expr
+  tests/ParserTests/regressions/elif2.format
+  tests/ParserTests/regressions/encoding-0.8.cabal
+  tests/ParserTests/regressions/encoding-0.8.expr
+  tests/ParserTests/regressions/encoding-0.8.format
+  tests/ParserTests/regressions/extensions-paths-5054.cabal
+  tests/ParserTests/regressions/extensions-paths-5054.check
+  tests/ParserTests/regressions/generics-sop.cabal
+  tests/ParserTests/regressions/generics-sop.expr
+  tests/ParserTests/regressions/generics-sop.format
+  tests/ParserTests/regressions/ghc-option-j.cabal
+  tests/ParserTests/regressions/ghc-option-j.check
+  tests/ParserTests/regressions/haddock-api-2.18.1-check.cabal
+  tests/ParserTests/regressions/haddock-api-2.18.1-check.check
+  tests/ParserTests/regressions/hidden-main-lib.cabal
+  tests/ParserTests/regressions/hidden-main-lib.expr
+  tests/ParserTests/regressions/hidden-main-lib.format
+  tests/ParserTests/regressions/issue-5055.cabal
+  tests/ParserTests/regressions/issue-5055.expr
+  tests/ParserTests/regressions/issue-5055.format
+  tests/ParserTests/regressions/issue-774.cabal
+  tests/ParserTests/regressions/issue-774.check
+  tests/ParserTests/regressions/issue-774.expr
+  tests/ParserTests/regressions/issue-774.format
+  tests/ParserTests/regressions/jaeger-flamegraph.cabal
+  tests/ParserTests/regressions/jaeger-flamegraph.expr
+  tests/ParserTests/regressions/jaeger-flamegraph.format
+  tests/ParserTests/regressions/leading-comma-2.cabal
+  tests/ParserTests/regressions/leading-comma-2.expr
+  tests/ParserTests/regressions/leading-comma-2.format
+  tests/ParserTests/regressions/leading-comma.cabal
+  tests/ParserTests/regressions/leading-comma.expr
+  tests/ParserTests/regressions/leading-comma.format
+  tests/ParserTests/regressions/multiple-libs-2.cabal
+  tests/ParserTests/regressions/multiple-libs-2.check
+  tests/ParserTests/regressions/multiple-libs-2.expr
+  tests/ParserTests/regressions/multiple-libs-2.format
+  tests/ParserTests/regressions/noVersion.cabal
+  tests/ParserTests/regressions/noVersion.expr
+  tests/ParserTests/regressions/noVersion.format
+  tests/ParserTests/regressions/nothing-unicode.cabal
+  tests/ParserTests/regressions/nothing-unicode.check
+  tests/ParserTests/regressions/nothing-unicode.expr
+  tests/ParserTests/regressions/nothing-unicode.format
+  tests/ParserTests/regressions/pre-1.6-glob.cabal
+  tests/ParserTests/regressions/pre-1.6-glob.check
+  tests/ParserTests/regressions/pre-2.4-globstar.cabal
+  tests/ParserTests/regressions/pre-2.4-globstar.check
+  tests/ParserTests/regressions/shake.cabal
+  tests/ParserTests/regressions/shake.expr
+  tests/ParserTests/regressions/shake.format
+  tests/ParserTests/regressions/spdx-1.cabal
+  tests/ParserTests/regressions/spdx-1.expr
+  tests/ParserTests/regressions/spdx-1.format
+  tests/ParserTests/regressions/spdx-2.cabal
+  tests/ParserTests/regressions/spdx-2.expr
+  tests/ParserTests/regressions/spdx-2.format
+  tests/ParserTests/regressions/spdx-3.cabal
+  tests/ParserTests/regressions/spdx-3.expr
+  tests/ParserTests/regressions/spdx-3.format
+  tests/ParserTests/regressions/th-lift-instances.cabal
+  tests/ParserTests/regressions/th-lift-instances.expr
+  tests/ParserTests/regressions/th-lift-instances.format
+  tests/ParserTests/regressions/wl-pprint-indef.cabal
+  tests/ParserTests/regressions/wl-pprint-indef.expr
+  tests/ParserTests/regressions/wl-pprint-indef.format
+  tests/ParserTests/warnings/bom.cabal
+  tests/ParserTests/warnings/bool.cabal
+  tests/ParserTests/warnings/deprecatedfield.cabal
+  tests/ParserTests/warnings/doubledash.cabal
+  tests/ParserTests/warnings/extratestmodule.cabal
+  tests/ParserTests/warnings/gluedop.cabal
+  tests/ParserTests/warnings/multiplesingular.cabal
+  tests/ParserTests/warnings/nbsp.cabal
+  tests/ParserTests/warnings/newsyntax.cabal
+  tests/ParserTests/warnings/oldsyntax.cabal
+  tests/ParserTests/warnings/subsection.cabal
+  tests/ParserTests/warnings/tab.cabal
+  tests/ParserTests/warnings/trailingfield.cabal
+  tests/ParserTests/warnings/unknownfield.cabal
+  tests/ParserTests/warnings/unknownsection.cabal
+  tests/ParserTests/warnings/utf8.cabal
+  tests/ParserTests/warnings/versiontag.cabal
+  tests/hackage/check.sh
+  tests/hackage/download.sh
+  tests/hackage/unpack.sh
+  tests/misc/ghc-supported-languages.hs
+  -- END gen-extra-source-files
+
+source-repository head
+  type:     git
+  location: https://github.com/haskell/cabal/
+  subdir:   Cabal
+
+flag bundled-binary-generic
+  default: False
+
+library
+  build-depends:
+    array      >= 0.4.0.1  && < 0.6,
+    base       >= 4.6      && < 5,
+    bytestring >= 0.10.0.0 && < 0.11,
+    containers >= 0.5.0.0  && < 0.7,
+    deepseq    >= 1.3.0.1  && < 1.5,
+    directory  >= 1.2      && < 1.4,
+    filepath   >= 1.3.0.1  && < 1.5,
+    pretty     >= 1.1.1    && < 1.2,
+    process    >= 1.1.0.2  && < 1.7,
+    time       >= 1.4.0.1  && < 1.10
+
+  if flag(bundled-binary-generic)
+    build-depends: binary >= 0.5.1.1 && < 0.7
+  else
+    build-depends: binary >= 0.7 && < 0.9
+
+  if os(windows)
+    build-depends: Win32 >= 2.3.0.0 && < 2.9
+  else
+    build-depends: unix  >= 2.6.0.0 && < 2.8
+
+  ghc-options: -Wall -fno-ignore-asserts -fwarn-tabs
+  if impl(ghc >= 8.0)
+    ghc-options: -Wcompat -Wnoncanonical-monad-instances
+                 -Wnoncanonical-monadfail-instances
+
+  exposed-modules:
+    Distribution.Backpack
+    Distribution.Backpack.Configure
+    Distribution.Backpack.ComponentsGraph
+    Distribution.Backpack.ConfiguredComponent
+    Distribution.Backpack.DescribeUnitId
+    Distribution.Backpack.FullUnitId
+    Distribution.Backpack.LinkedComponent
+    Distribution.Backpack.ModSubst
+    Distribution.Backpack.ModuleShape
+    Distribution.Backpack.PreModuleShape
+    Distribution.CabalSpecVersion
+    Distribution.Utils.IOData
+    Distribution.Utils.LogProgress
+    Distribution.Utils.MapAccum
+    Distribution.Compat.CreatePipe
+    Distribution.Compat.Directory
+    Distribution.Compat.Environment
+    Distribution.Compat.Exception
+    Distribution.Compat.Graph
+    Distribution.Compat.Internal.TempFile
+    Distribution.Compat.Newtype
+    Distribution.Compat.Prelude.Internal
+    Distribution.Compat.Semigroup
+    Distribution.Compat.Stack
+    Distribution.Compat.Time
+    Distribution.Compat.DList
+    Distribution.Compiler
+    Distribution.InstalledPackageInfo
+    Distribution.Types.AbiDependency
+    Distribution.Types.ExposedModule
+    Distribution.Types.InstalledPackageInfo
+    Distribution.Types.InstalledPackageInfo.FieldGrammar
+    Distribution.License
+    Distribution.Make
+    Distribution.ModuleName
+    Distribution.Package
+    Distribution.PackageDescription
+    Distribution.PackageDescription.Check
+    Distribution.PackageDescription.Configuration
+    Distribution.PackageDescription.PrettyPrint
+    Distribution.PackageDescription.Utils
+    Distribution.ReadE
+    Distribution.Simple
+    Distribution.Simple.Bench
+    Distribution.Simple.Build
+    Distribution.Simple.Build.Macros
+    Distribution.Simple.Build.PathsModule
+    Distribution.Simple.BuildPaths
+    Distribution.Simple.BuildTarget
+    Distribution.Simple.BuildToolDepends
+    Distribution.Simple.CCompiler
+    Distribution.Simple.Command
+    Distribution.Simple.Compiler
+    Distribution.Simple.Configure
+    Distribution.Simple.Flag
+    Distribution.Simple.GHC
+    Distribution.Simple.GHCJS
+    Distribution.Simple.Haddock
+    Distribution.Simple.Doctest
+    Distribution.Simple.Glob
+    Distribution.Simple.HaskellSuite
+    Distribution.Simple.Hpc
+    Distribution.Simple.Install
+    Distribution.Simple.InstallDirs
+    Distribution.Simple.LocalBuildInfo
+    Distribution.Simple.PackageIndex
+    Distribution.Simple.PreProcess
+    Distribution.Simple.PreProcess.Unlit
+    Distribution.Simple.Program
+    Distribution.Simple.Program.Ar
+    Distribution.Simple.Program.Builtin
+    Distribution.Simple.Program.Db
+    Distribution.Simple.Program.Find
+    Distribution.Simple.Program.GHC
+    Distribution.Simple.Program.HcPkg
+    Distribution.Simple.Program.Hpc
+    Distribution.Simple.Program.Internal
+    Distribution.Simple.Program.Ld
+    Distribution.Simple.Program.ResponseFile
+    Distribution.Simple.Program.Run
+    Distribution.Simple.Program.Script
+    Distribution.Simple.Program.Strip
+    Distribution.Simple.Program.Types
+    Distribution.Simple.Register
+    Distribution.Simple.Setup
+    Distribution.Simple.SrcDist
+    Distribution.Simple.Test
+    Distribution.Simple.Test.ExeV10
+    Distribution.Simple.Test.LibV09
+    Distribution.Simple.Test.Log
+    Distribution.Simple.UHC
+    Distribution.Simple.UserHooks
+    Distribution.Simple.Utils
+    Distribution.SPDX
+    Distribution.SPDX.License
+    Distribution.SPDX.LicenseId
+    Distribution.SPDX.LicenseExceptionId
+    Distribution.SPDX.LicenseExpression
+    Distribution.SPDX.LicenseListVersion
+    Distribution.SPDX.LicenseReference
+    Distribution.System
+    Distribution.TestSuite
+    Distribution.Text
+    Distribution.Pretty
+    Distribution.Types.AbiHash
+    Distribution.Types.AnnotatedId
+    Distribution.Types.Benchmark
+    Distribution.Types.BenchmarkInterface
+    Distribution.Types.BenchmarkType
+    Distribution.Types.BuildInfo
+    Distribution.Types.BuildType
+    Distribution.Types.ComponentInclude
+    Distribution.Types.Dependency
+    Distribution.Types.ExeDependency
+    Distribution.Types.LegacyExeDependency
+    Distribution.Types.PkgconfigDependency
+    Distribution.Types.DependencyMap
+    Distribution.Types.ComponentId
+    Distribution.Types.MungedPackageId
+    Distribution.Types.PackageId
+    Distribution.Types.UnitId
+    Distribution.Types.Executable
+    Distribution.Types.ExecutableScope
+    Distribution.Types.Library
+    Distribution.Types.LibraryVisibility
+    Distribution.Types.ForeignLib
+    Distribution.Types.ForeignLibType
+    Distribution.Types.ForeignLibOption
+    Distribution.Types.Module
+    Distribution.Types.ModuleReexport
+    Distribution.Types.ModuleRenaming
+    Distribution.Types.ComponentName
+    Distribution.Types.LibraryName
+    Distribution.Types.MungedPackageName
+    Distribution.Types.PackageName
+    Distribution.Types.PkgconfigName
+    Distribution.Types.UnqualComponentName
+    Distribution.Types.IncludeRenaming
+    Distribution.Types.Mixin
+    Distribution.Types.SetupBuildInfo
+    Distribution.Types.TestSuite
+    Distribution.Types.TestSuiteInterface
+    Distribution.Types.TestType
+    Distribution.Types.GenericPackageDescription
+    Distribution.Types.Condition
+    Distribution.Types.CondTree
+    Distribution.Types.HookedBuildInfo
+    Distribution.Types.PackageDescription
+    Distribution.Types.SourceRepo
+    Distribution.Types.Component
+    Distribution.Types.ComponentLocalBuildInfo
+    Distribution.Types.LocalBuildInfo
+    Distribution.Types.ComponentRequestedSpec
+    Distribution.Types.TargetInfo
+    Distribution.Types.Version
+    Distribution.Types.VersionRange
+    Distribution.Types.VersionInterval
+    Distribution.Types.GivenComponent
+    Distribution.Types.PackageVersionConstraint
+    Distribution.Utils.Generic
+    Distribution.Utils.NubList
+    Distribution.Utils.ShortText
+    Distribution.Utils.Progress
+    Distribution.Verbosity
+    Distribution.Version
+    Language.Haskell.Extension
+    Distribution.Compat.Binary
+
+  -- Parsec parser-related modules
+  build-depends:
+    -- transformers-0.4.0.0 doesn't have record syntax e.g. for Identity
+    -- See also https://github.com/ekmett/transformers-compat/issues/35
+    transformers (>= 0.3      && < 0.4) || (>=0.4.1.0 && <0.6),
+    mtl           >= 2.1      && < 2.3,
+    text          >= 1.2.3.0  && < 1.3,
+    parsec        >= 3.1.13.0 && < 3.2
+  exposed-modules:
+    Distribution.Compat.Parsing
+    Distribution.Compat.CharParsing
+    Distribution.FieldGrammar
+    Distribution.FieldGrammar.Class
+    Distribution.FieldGrammar.FieldDescrs
+    Distribution.FieldGrammar.Parsec
+    Distribution.FieldGrammar.Pretty
+    Distribution.PackageDescription.FieldGrammar
+    Distribution.PackageDescription.Parsec
+    Distribution.PackageDescription.Quirks
+    Distribution.Parsec
+    Distribution.Parsec.Error
+    Distribution.Parsec.Newtypes
+    Distribution.Parsec.Position
+    Distribution.Parsec.Warning
+    Distribution.Parsec.FieldLineStream
+    Distribution.Fields
+    Distribution.Fields.ConfVar
+    Distribution.Fields.Field
+    Distribution.Fields.Lexer
+    Distribution.Fields.LexerMonad
+    Distribution.Fields.ParseResult
+    Distribution.Fields.Parser
+    Distribution.Fields.Pretty
+
+  -- Lens functionality
+  exposed-modules:
+    Distribution.Compat.Lens
+    Distribution.Types.Lens
+    Distribution.Types.Benchmark.Lens
+    Distribution.Types.BuildInfo.Lens
+    Distribution.Types.Executable.Lens
+    Distribution.Types.ForeignLib.Lens
+    Distribution.Types.GenericPackageDescription.Lens
+    Distribution.Types.InstalledPackageInfo.Lens
+    Distribution.Types.Library.Lens
+    Distribution.Types.PackageDescription.Lens
+    Distribution.Types.PackageId.Lens
+    Distribution.Types.SetupBuildInfo.Lens
+    Distribution.Types.SourceRepo.Lens
+    Distribution.Types.TestSuite.Lens
+
+  other-modules:
+    Distribution.Backpack.PreExistingComponent
+    Distribution.Backpack.ReadyComponent
+    Distribution.Backpack.MixLink
+    Distribution.Backpack.ModuleScope
+    Distribution.Backpack.UnifyM
+    Distribution.Backpack.Id
+    Distribution.Utils.UnionFind
+    Distribution.Utils.Base62
+    Distribution.Compat.CopyFile
+    Distribution.Compat.GetShortPathName
+    Distribution.Compat.MonadFail
+    Distribution.Compat.Prelude
+    Distribution.Compat.SnocList
+    Distribution.GetOpt
+    Distribution.Lex
+    Distribution.Utils.String
+    Distribution.Simple.GHC.EnvironmentParser
+    Distribution.Simple.GHC.Internal
+    Distribution.Simple.GHC.ImplInfo
+    Paths_Cabal
+
+  if flag(bundled-binary-generic)
+    other-modules:
+      Distribution.Compat.Binary.Class
+      Distribution.Compat.Binary.Generic
+
+  default-language: Haskell2010
+  other-extensions:
+    BangPatterns
+    CPP
+    DefaultSignatures
+    DeriveDataTypeable
+    DeriveFoldable
+    DeriveFunctor
+    DeriveGeneric
+    DeriveTraversable
+    ExistentialQuantification
+    FlexibleContexts
+    FlexibleInstances
+    GeneralizedNewtypeDeriving
+    ImplicitParams
+    KindSignatures
+    NondecreasingIndentation
+    OverloadedStrings
+    RankNTypes
+    RecordWildCards
+    ScopedTypeVariables
+    StandaloneDeriving
+    Trustworthy
+    TypeFamilies
+    TypeOperators
+    TypeSynonymInstances
+    UndecidableInstances
+
+  if impl(ghc >= 7.11)
+    other-extensions: PatternSynonyms
+
+-- Small, fast running tests.
+test-suite unit-tests
+  type: exitcode-stdio-1.0
+  hs-source-dirs: tests
+  other-modules:
+    Test.Laws
+    Test.QuickCheck.Utils
+    UnitTests.Distribution.Compat.CreatePipe
+    UnitTests.Distribution.Compat.Time
+    UnitTests.Distribution.Compat.Graph
+    UnitTests.Distribution.Simple.Glob
+    UnitTests.Distribution.Simple.Program.Internal
+    UnitTests.Distribution.Simple.Utils
+    UnitTests.Distribution.SPDX
+    UnitTests.Distribution.System
+    UnitTests.Distribution.Types.GenericPackageDescription
+    UnitTests.Distribution.Utils.Generic
+    UnitTests.Distribution.Utils.NubList
+    UnitTests.Distribution.Utils.ShortText
+    UnitTests.Distribution.Version
+  main-is: UnitTests.hs
+  build-depends:
+    array,
+    base,
+    bytestring,
+    containers,
+    directory,
+    filepath,
+    integer-logarithms >= 1.0.2 && <1.1,
+    tasty >= 1.1.0.3 && < 1.2,
+    tasty-hunit,
+    tasty-quickcheck,
+    tagged,
+    temporary,
+    text,
+    pretty,
+    QuickCheck >= 2.11.3 && < 2.12,
+    Cabal
+  ghc-options: -Wall
+  default-language: Haskell2010
+
+test-suite parser-tests
+  type: exitcode-stdio-1.0
+  hs-source-dirs: tests
+  main-is: ParserTests.hs
+  build-depends:
+    base,
+    base-compat >=0.10.4 && <0.11,
+    bytestring,
+    directory,
+    filepath,
+    tasty >= 1.1.0.3 && < 1.2,
+    tasty-hunit,
+    tasty-quickcheck,
+    tasty-golden >=2.3.1.1 && <2.4,
+    Diff >=0.3.4 && <0.4,
+    Cabal
+  ghc-options: -Wall
+  default-language: Haskell2010
+
+  if impl(ghc >= 7.8)
+    build-depends:
+      tree-diff      >= 0.0.1 && <0.1
+    other-modules:
+      Instances.TreeDiff
+      Instances.TreeDiff.Language
+      Instances.TreeDiff.SPDX
+      Instances.TreeDiff.Version
+
+test-suite check-tests
+  type: exitcode-stdio-1.0
+  hs-source-dirs: tests
+  main-is: CheckTests.hs
+  build-depends:
+    base,
+    bytestring,
+    directory,
+    filepath,
+    tasty >= 1.1.0.3 && < 1.2,
+    tasty-golden >=2.3.1.1 && <2.4,
+    Diff >=0.3.4 && <0.4,
+    Cabal
+  ghc-options: -Wall
+  default-language: Haskell2010
+
+test-suite custom-setup-tests
+  type: exitcode-stdio-1.0
+  hs-source-dirs: tests/custom-setup
+  main-is: CustomSetupTests.hs
+  other-modules:
+    CabalDoctestSetup
+    IdrisSetup
+  build-depends:
+    Cabal,
+    base,
+    directory,
+    filepath,
+    process
+  default-language: Haskell2010
+
+test-suite hackage-tests
+  type: exitcode-stdio-1.0
+  main-is: HackageTests.hs
+
+  -- TODO: need to get 01-index.tar on appveyor
+  if os(windows)
+    buildable: False
+
+  hs-source-dirs: tests
+
+  build-depends:
+    base,
+    Cabal,
+    bytestring,
+    deepseq,
+    containers,
+    directory,
+    filepath
+
+  build-depends:
+    base-compat          >=0.10.4   && <0.11,
+    base-orphans         >=0.6      && <0.9,
+    optparse-applicative >=0.13.2.0 && <0.15,
+    stm                  >=2.4.5.0  && <2.6,
+    tar                  >=0.5.0.3  && <0.6
+
+  if impl(ghc >= 7.8)
+    build-depends:
+      tree-diff      >= 0.0.1 && <0.1
+    other-modules:
+      Instances.TreeDiff
+      Instances.TreeDiff.Language
+      Instances.TreeDiff.SPDX
+      Instances.TreeDiff.Version
+
+  ghc-options: -Wall -rtsopts -threaded
+  default-extensions: CPP
+  default-language: Haskell2010
diff --git a/fixtures/Cabal-notab.format b/fixtures/Cabal-notab.format
new file mode 100644
--- /dev/null
+++ b/fixtures/Cabal-notab.format
@@ -0,0 +1,675 @@
+name:               Cabal
+version:            2.5.0.0
+
+-- cabal-fmt: no-tabular
+copyright:          2003-2018, Cabal Development Team (see AUTHORS file)
+license:            BSD3
+license-file:       LICENSE
+author:             Cabal Development Team <cabal-devel@haskell.org>
+maintainer:         cabal-devel@haskell.org
+homepage:           http://www.haskell.org/cabal/
+bug-reports:        https://github.com/haskell/cabal/issues
+synopsis:           A framework for packaging Haskell software
+description:
+  The Haskell Common Architecture for Building Applications and
+  Libraries: a framework defining a common interface for authors to more
+  easily build their Haskell applications in a portable way.
+  .
+  The Haskell Cabal is part of a larger infrastructure for distributing,
+  organizing, and cataloging Haskell libraries and tools.
+
+category:           Distribution
+cabal-version:      >=1.10
+build-type:         Simple
+
+-- If we use a new Cabal feature, this needs to be changed to Custom so
+-- we can bootstrap.
+
+extra-source-files:
+  ChangeLog.md
+  doc/bugs-and-stability.rst
+  doc/concepts-and-development.rst
+  doc/conf.py
+  doc/config-and-install.rst
+  doc/developing-packages.rst
+  doc/file-format-changelog.rst
+  doc/images/Cabal-dark.png
+  doc/index.rst
+  doc/installing-packages.rst
+  doc/intro.rst
+  doc/misc.rst
+  doc/nix-local-build-overview.rst
+  doc/nix-local-build.rst
+  doc/README.md
+  doc/references.inc
+  README.md
+  tests/hackage/check.sh
+  tests/hackage/download.sh
+  tests/hackage/unpack.sh
+  tests/misc/ghc-supported-languages.hs
+  tests/ParserTests/errors/common1.cabal
+  tests/ParserTests/errors/common1.errors
+  tests/ParserTests/errors/common2.cabal
+  tests/ParserTests/errors/common2.errors
+  tests/ParserTests/errors/common3.cabal
+  tests/ParserTests/errors/common3.errors
+  tests/ParserTests/errors/forward-compat.cabal
+  tests/ParserTests/errors/forward-compat.errors
+  tests/ParserTests/errors/forward-compat2.cabal
+  tests/ParserTests/errors/forward-compat2.errors
+  tests/ParserTests/errors/forward-compat3.cabal
+  tests/ParserTests/errors/forward-compat3.errors
+  tests/ParserTests/errors/issue-5055-2.cabal
+  tests/ParserTests/errors/issue-5055-2.errors
+  tests/ParserTests/errors/issue-5055.cabal
+  tests/ParserTests/errors/issue-5055.errors
+  tests/ParserTests/errors/leading-comma-2.cabal
+  tests/ParserTests/errors/leading-comma-2.errors
+  tests/ParserTests/errors/leading-comma-2b.cabal
+  tests/ParserTests/errors/leading-comma-2b.errors
+  tests/ParserTests/errors/leading-comma-2c.cabal
+  tests/ParserTests/errors/leading-comma-2c.errors
+  tests/ParserTests/errors/leading-comma.cabal
+  tests/ParserTests/errors/leading-comma.errors
+  tests/ParserTests/errors/multiple-libs.cabal
+  tests/ParserTests/errors/multiple-libs.errors
+  tests/ParserTests/errors/noVersion.cabal
+  tests/ParserTests/errors/noVersion.errors
+  tests/ParserTests/errors/noVersion2.cabal
+  tests/ParserTests/errors/noVersion2.errors
+  tests/ParserTests/errors/range-ge-wild.cabal
+  tests/ParserTests/errors/range-ge-wild.errors
+  tests/ParserTests/errors/removed-fields.cabal
+  tests/ParserTests/errors/removed-fields.errors
+  tests/ParserTests/errors/spdx-1.cabal
+  tests/ParserTests/errors/spdx-1.errors
+  tests/ParserTests/errors/spdx-2.cabal
+  tests/ParserTests/errors/spdx-2.errors
+  tests/ParserTests/errors/spdx-3.cabal
+  tests/ParserTests/errors/spdx-3.errors
+  tests/ParserTests/ipi/Includes2.cabal
+  tests/ParserTests/ipi/Includes2.expr
+  tests/ParserTests/ipi/Includes2.format
+  tests/ParserTests/ipi/internal-preprocessor-test.cabal
+  tests/ParserTests/ipi/internal-preprocessor-test.expr
+  tests/ParserTests/ipi/internal-preprocessor-test.format
+  tests/ParserTests/ipi/issue-2276-ghc-9885.cabal
+  tests/ParserTests/ipi/issue-2276-ghc-9885.expr
+  tests/ParserTests/ipi/issue-2276-ghc-9885.format
+  tests/ParserTests/ipi/transformers.cabal
+  tests/ParserTests/ipi/transformers.expr
+  tests/ParserTests/ipi/transformers.format
+  tests/ParserTests/regressions/bad-glob-syntax.cabal
+  tests/ParserTests/regressions/bad-glob-syntax.check
+  tests/ParserTests/regressions/cc-options-with-optimization.cabal
+  tests/ParserTests/regressions/cc-options-with-optimization.check
+  tests/ParserTests/regressions/common-conditional.cabal
+  tests/ParserTests/regressions/common-conditional.expr
+  tests/ParserTests/regressions/common-conditional.format
+  tests/ParserTests/regressions/common.cabal
+  tests/ParserTests/regressions/common.expr
+  tests/ParserTests/regressions/common.format
+  tests/ParserTests/regressions/common2.cabal
+  tests/ParserTests/regressions/common2.expr
+  tests/ParserTests/regressions/common2.format
+  tests/ParserTests/regressions/cxx-options-with-optimization.cabal
+  tests/ParserTests/regressions/cxx-options-with-optimization.check
+  tests/ParserTests/regressions/elif.cabal
+  tests/ParserTests/regressions/elif.expr
+  tests/ParserTests/regressions/elif.format
+  tests/ParserTests/regressions/elif2.cabal
+  tests/ParserTests/regressions/elif2.expr
+  tests/ParserTests/regressions/elif2.format
+  tests/ParserTests/regressions/encoding-0.8.cabal
+  tests/ParserTests/regressions/encoding-0.8.expr
+  tests/ParserTests/regressions/encoding-0.8.format
+  tests/ParserTests/regressions/extensions-paths-5054.cabal
+  tests/ParserTests/regressions/extensions-paths-5054.check
+  tests/ParserTests/regressions/generics-sop.cabal
+  tests/ParserTests/regressions/generics-sop.expr
+  tests/ParserTests/regressions/generics-sop.format
+  tests/ParserTests/regressions/ghc-option-j.cabal
+  tests/ParserTests/regressions/ghc-option-j.check
+  tests/ParserTests/regressions/haddock-api-2.18.1-check.cabal
+  tests/ParserTests/regressions/haddock-api-2.18.1-check.check
+  tests/ParserTests/regressions/hidden-main-lib.cabal
+  tests/ParserTests/regressions/hidden-main-lib.expr
+  tests/ParserTests/regressions/hidden-main-lib.format
+  tests/ParserTests/regressions/issue-5055.cabal
+  tests/ParserTests/regressions/issue-5055.expr
+  tests/ParserTests/regressions/issue-5055.format
+  tests/ParserTests/regressions/issue-774.cabal
+  tests/ParserTests/regressions/issue-774.check
+  tests/ParserTests/regressions/issue-774.expr
+  tests/ParserTests/regressions/issue-774.format
+  tests/ParserTests/regressions/jaeger-flamegraph.cabal
+  tests/ParserTests/regressions/jaeger-flamegraph.expr
+  tests/ParserTests/regressions/jaeger-flamegraph.format
+  tests/ParserTests/regressions/leading-comma-2.cabal
+  tests/ParserTests/regressions/leading-comma-2.expr
+  tests/ParserTests/regressions/leading-comma-2.format
+  tests/ParserTests/regressions/leading-comma.cabal
+  tests/ParserTests/regressions/leading-comma.expr
+  tests/ParserTests/regressions/leading-comma.format
+  tests/ParserTests/regressions/MiniAgda.cabal
+  tests/ParserTests/regressions/MiniAgda.check
+  tests/ParserTests/regressions/multiple-libs-2.cabal
+  tests/ParserTests/regressions/multiple-libs-2.check
+  tests/ParserTests/regressions/multiple-libs-2.expr
+  tests/ParserTests/regressions/multiple-libs-2.format
+  tests/ParserTests/regressions/nothing-unicode.cabal
+  tests/ParserTests/regressions/nothing-unicode.check
+  tests/ParserTests/regressions/nothing-unicode.expr
+  tests/ParserTests/regressions/nothing-unicode.format
+  tests/ParserTests/regressions/noVersion.cabal
+  tests/ParserTests/regressions/noVersion.expr
+  tests/ParserTests/regressions/noVersion.format
+  tests/ParserTests/regressions/Octree-0.5.cabal
+  tests/ParserTests/regressions/Octree-0.5.expr
+  tests/ParserTests/regressions/Octree-0.5.format
+  tests/ParserTests/regressions/pre-1.6-glob.cabal
+  tests/ParserTests/regressions/pre-1.6-glob.check
+  tests/ParserTests/regressions/pre-2.4-globstar.cabal
+  tests/ParserTests/regressions/pre-2.4-globstar.check
+  tests/ParserTests/regressions/shake.cabal
+  tests/ParserTests/regressions/shake.expr
+  tests/ParserTests/regressions/shake.format
+  tests/ParserTests/regressions/spdx-1.cabal
+  tests/ParserTests/regressions/spdx-1.expr
+  tests/ParserTests/regressions/spdx-1.format
+  tests/ParserTests/regressions/spdx-2.cabal
+  tests/ParserTests/regressions/spdx-2.expr
+  tests/ParserTests/regressions/spdx-2.format
+  tests/ParserTests/regressions/spdx-3.cabal
+  tests/ParserTests/regressions/spdx-3.expr
+  tests/ParserTests/regressions/spdx-3.format
+  tests/ParserTests/regressions/th-lift-instances.cabal
+  tests/ParserTests/regressions/th-lift-instances.expr
+  tests/ParserTests/regressions/th-lift-instances.format
+  tests/ParserTests/regressions/wl-pprint-indef.cabal
+  tests/ParserTests/regressions/wl-pprint-indef.expr
+  tests/ParserTests/regressions/wl-pprint-indef.format
+  tests/ParserTests/warnings/bom.cabal
+  tests/ParserTests/warnings/bool.cabal
+  tests/ParserTests/warnings/deprecatedfield.cabal
+  tests/ParserTests/warnings/doubledash.cabal
+  tests/ParserTests/warnings/extratestmodule.cabal
+  tests/ParserTests/warnings/gluedop.cabal
+  tests/ParserTests/warnings/multiplesingular.cabal
+  tests/ParserTests/warnings/nbsp.cabal
+  tests/ParserTests/warnings/newsyntax.cabal
+  tests/ParserTests/warnings/oldsyntax.cabal
+  tests/ParserTests/warnings/subsection.cabal
+  tests/ParserTests/warnings/tab.cabal
+  tests/ParserTests/warnings/trailingfield.cabal
+  tests/ParserTests/warnings/unknownfield.cabal
+  tests/ParserTests/warnings/unknownsection.cabal
+  tests/ParserTests/warnings/utf8.cabal
+  tests/ParserTests/warnings/versiontag.cabal
+  tests/README.md
+
+-- Generated with 'make gen-extra-source-files'
+-- Do NOT edit this section manually; instead, run the script.
+-- BEGIN gen-extra-source-files
+-- END gen-extra-source-files
+
+source-repository head
+  type:     git
+  location: https://github.com/haskell/cabal/
+  subdir:   Cabal
+
+flag bundled-binary-generic
+  default: False
+
+library
+  build-depends:
+      array >=0.4.0.1 && <0.6
+    , base >=4.6 && <5
+    , bytestring >=0.10.0.0 && <0.11
+    , containers >=0.5.0.0 && <0.7
+    , deepseq >=1.3.0.1 && <1.5
+    , directory >=1.2 && <1.4
+    , filepath >=1.3.0.1 && <1.5
+    , pretty >=1.1.1 && <1.2
+    , process >=1.1.0.2 && <1.7
+    , time >=1.4.0.1 && <1.10
+
+  if flag(bundled-binary-generic)
+    build-depends: binary >=0.5.1.1 && <0.7
+
+  else
+    build-depends: binary >=0.7 && <0.9
+
+  if os(windows)
+    build-depends: Win32 >=2.3.0.0 && <2.9
+
+  else
+    build-depends: unix >=2.6.0.0 && <2.8
+
+  ghc-options:      -Wall -fno-ignore-asserts -fwarn-tabs
+
+  if impl(ghc >=8.0)
+    ghc-options:
+      -Wcompat -Wnoncanonical-monad-instances
+      -Wnoncanonical-monadfail-instances
+
+  exposed-modules:
+    Distribution.Backpack
+    Distribution.Backpack.ComponentsGraph
+    Distribution.Backpack.Configure
+    Distribution.Backpack.ConfiguredComponent
+    Distribution.Backpack.DescribeUnitId
+    Distribution.Backpack.FullUnitId
+    Distribution.Backpack.LinkedComponent
+    Distribution.Backpack.ModSubst
+    Distribution.Backpack.ModuleShape
+    Distribution.Backpack.PreModuleShape
+    Distribution.CabalSpecVersion
+    Distribution.Compat.Binary
+    Distribution.Compat.CreatePipe
+    Distribution.Compat.Directory
+    Distribution.Compat.DList
+    Distribution.Compat.Environment
+    Distribution.Compat.Exception
+    Distribution.Compat.Graph
+    Distribution.Compat.Internal.TempFile
+    Distribution.Compat.Newtype
+    Distribution.Compat.Prelude.Internal
+    Distribution.Compat.Semigroup
+    Distribution.Compat.Stack
+    Distribution.Compat.Time
+    Distribution.Compiler
+    Distribution.InstalledPackageInfo
+    Distribution.License
+    Distribution.Make
+    Distribution.ModuleName
+    Distribution.Package
+    Distribution.PackageDescription
+    Distribution.PackageDescription.Check
+    Distribution.PackageDescription.Configuration
+    Distribution.PackageDescription.PrettyPrint
+    Distribution.PackageDescription.Utils
+    Distribution.Pretty
+    Distribution.ReadE
+    Distribution.Simple
+    Distribution.Simple.Bench
+    Distribution.Simple.Build
+    Distribution.Simple.Build.Macros
+    Distribution.Simple.Build.PathsModule
+    Distribution.Simple.BuildPaths
+    Distribution.Simple.BuildTarget
+    Distribution.Simple.BuildToolDepends
+    Distribution.Simple.CCompiler
+    Distribution.Simple.Command
+    Distribution.Simple.Compiler
+    Distribution.Simple.Configure
+    Distribution.Simple.Doctest
+    Distribution.Simple.Flag
+    Distribution.Simple.GHC
+    Distribution.Simple.GHCJS
+    Distribution.Simple.Glob
+    Distribution.Simple.Haddock
+    Distribution.Simple.HaskellSuite
+    Distribution.Simple.Hpc
+    Distribution.Simple.Install
+    Distribution.Simple.InstallDirs
+    Distribution.Simple.LocalBuildInfo
+    Distribution.Simple.PackageIndex
+    Distribution.Simple.PreProcess
+    Distribution.Simple.PreProcess.Unlit
+    Distribution.Simple.Program
+    Distribution.Simple.Program.Ar
+    Distribution.Simple.Program.Builtin
+    Distribution.Simple.Program.Db
+    Distribution.Simple.Program.Find
+    Distribution.Simple.Program.GHC
+    Distribution.Simple.Program.HcPkg
+    Distribution.Simple.Program.Hpc
+    Distribution.Simple.Program.Internal
+    Distribution.Simple.Program.Ld
+    Distribution.Simple.Program.ResponseFile
+    Distribution.Simple.Program.Run
+    Distribution.Simple.Program.Script
+    Distribution.Simple.Program.Strip
+    Distribution.Simple.Program.Types
+    Distribution.Simple.Register
+    Distribution.Simple.Setup
+    Distribution.Simple.SrcDist
+    Distribution.Simple.Test
+    Distribution.Simple.Test.ExeV10
+    Distribution.Simple.Test.LibV09
+    Distribution.Simple.Test.Log
+    Distribution.Simple.UHC
+    Distribution.Simple.UserHooks
+    Distribution.Simple.Utils
+    Distribution.SPDX
+    Distribution.SPDX.License
+    Distribution.SPDX.LicenseExceptionId
+    Distribution.SPDX.LicenseExpression
+    Distribution.SPDX.LicenseId
+    Distribution.SPDX.LicenseListVersion
+    Distribution.SPDX.LicenseReference
+    Distribution.System
+    Distribution.TestSuite
+    Distribution.Text
+    Distribution.Types.AbiDependency
+    Distribution.Types.AbiHash
+    Distribution.Types.AnnotatedId
+    Distribution.Types.Benchmark
+    Distribution.Types.BenchmarkInterface
+    Distribution.Types.BenchmarkType
+    Distribution.Types.BuildInfo
+    Distribution.Types.BuildType
+    Distribution.Types.Component
+    Distribution.Types.ComponentId
+    Distribution.Types.ComponentInclude
+    Distribution.Types.ComponentLocalBuildInfo
+    Distribution.Types.ComponentName
+    Distribution.Types.ComponentRequestedSpec
+    Distribution.Types.Condition
+    Distribution.Types.CondTree
+    Distribution.Types.Dependency
+    Distribution.Types.DependencyMap
+    Distribution.Types.Executable
+    Distribution.Types.ExecutableScope
+    Distribution.Types.ExeDependency
+    Distribution.Types.ExposedModule
+    Distribution.Types.ForeignLib
+    Distribution.Types.ForeignLibOption
+    Distribution.Types.ForeignLibType
+    Distribution.Types.GenericPackageDescription
+    Distribution.Types.GivenComponent
+    Distribution.Types.HookedBuildInfo
+    Distribution.Types.IncludeRenaming
+    Distribution.Types.InstalledPackageInfo
+    Distribution.Types.InstalledPackageInfo.FieldGrammar
+    Distribution.Types.LegacyExeDependency
+    Distribution.Types.Library
+    Distribution.Types.LibraryName
+    Distribution.Types.LibraryVisibility
+    Distribution.Types.LocalBuildInfo
+    Distribution.Types.Mixin
+    Distribution.Types.Module
+    Distribution.Types.ModuleReexport
+    Distribution.Types.ModuleRenaming
+    Distribution.Types.MungedPackageId
+    Distribution.Types.MungedPackageName
+    Distribution.Types.PackageDescription
+    Distribution.Types.PackageId
+    Distribution.Types.PackageName
+    Distribution.Types.PackageVersionConstraint
+    Distribution.Types.PkgconfigDependency
+    Distribution.Types.PkgconfigName
+    Distribution.Types.SetupBuildInfo
+    Distribution.Types.SourceRepo
+    Distribution.Types.TargetInfo
+    Distribution.Types.TestSuite
+    Distribution.Types.TestSuiteInterface
+    Distribution.Types.TestType
+    Distribution.Types.UnitId
+    Distribution.Types.UnqualComponentName
+    Distribution.Types.Version
+    Distribution.Types.VersionInterval
+    Distribution.Types.VersionRange
+    Distribution.Utils.Generic
+    Distribution.Utils.IOData
+    Distribution.Utils.LogProgress
+    Distribution.Utils.MapAccum
+    Distribution.Utils.NubList
+    Distribution.Utils.Progress
+    Distribution.Utils.ShortText
+    Distribution.Verbosity
+    Distribution.Version
+    Language.Haskell.Extension
+
+  -- Parsec parser-related modules
+  build-depends:
+      mtl >=2.1 && <2.3
+    , parsec >=3.1.13.0 && <3.2
+    , text >=1.2.3.0 && <1.3
+    , transformers >=0.3 && <0.4 || >=0.4.1.0 && <0.6
+
+  -- transformers-0.4.0.0 doesn't have record syntax e.g. for Identity
+  -- See also https://github.com/ekmett/transformers-compat/issues/35
+  exposed-modules:
+    Distribution.Compat.CharParsing
+    Distribution.Compat.Parsing
+    Distribution.FieldGrammar
+    Distribution.FieldGrammar.Class
+    Distribution.FieldGrammar.FieldDescrs
+    Distribution.FieldGrammar.Parsec
+    Distribution.FieldGrammar.Pretty
+    Distribution.Fields
+    Distribution.Fields.ConfVar
+    Distribution.Fields.Field
+    Distribution.Fields.Lexer
+    Distribution.Fields.LexerMonad
+    Distribution.Fields.Parser
+    Distribution.Fields.ParseResult
+    Distribution.Fields.Pretty
+    Distribution.PackageDescription.FieldGrammar
+    Distribution.PackageDescription.Parsec
+    Distribution.PackageDescription.Quirks
+    Distribution.Parsec
+    Distribution.Parsec.Error
+    Distribution.Parsec.FieldLineStream
+    Distribution.Parsec.Newtypes
+    Distribution.Parsec.Position
+    Distribution.Parsec.Warning
+
+  -- Lens functionality
+  exposed-modules:
+    Distribution.Compat.Lens
+    Distribution.Types.Benchmark.Lens
+    Distribution.Types.BuildInfo.Lens
+    Distribution.Types.Executable.Lens
+    Distribution.Types.ForeignLib.Lens
+    Distribution.Types.GenericPackageDescription.Lens
+    Distribution.Types.InstalledPackageInfo.Lens
+    Distribution.Types.Lens
+    Distribution.Types.Library.Lens
+    Distribution.Types.PackageDescription.Lens
+    Distribution.Types.PackageId.Lens
+    Distribution.Types.SetupBuildInfo.Lens
+    Distribution.Types.SourceRepo.Lens
+    Distribution.Types.TestSuite.Lens
+
+  other-modules:
+    Distribution.Backpack.Id
+    Distribution.Backpack.MixLink
+    Distribution.Backpack.ModuleScope
+    Distribution.Backpack.PreExistingComponent
+    Distribution.Backpack.ReadyComponent
+    Distribution.Backpack.UnifyM
+    Distribution.Compat.CopyFile
+    Distribution.Compat.GetShortPathName
+    Distribution.Compat.MonadFail
+    Distribution.Compat.Prelude
+    Distribution.Compat.SnocList
+    Distribution.GetOpt
+    Distribution.Lex
+    Distribution.Simple.GHC.EnvironmentParser
+    Distribution.Simple.GHC.ImplInfo
+    Distribution.Simple.GHC.Internal
+    Distribution.Utils.Base62
+    Distribution.Utils.String
+    Distribution.Utils.UnionFind
+    Paths_Cabal
+
+  if flag(bundled-binary-generic)
+    other-modules:
+      Distribution.Compat.Binary.Class
+      Distribution.Compat.Binary.Generic
+
+  default-language: Haskell2010
+  other-extensions:
+    BangPatterns
+    CPP
+    DefaultSignatures
+    DeriveDataTypeable
+    DeriveFoldable
+    DeriveFunctor
+    DeriveGeneric
+    DeriveTraversable
+    ExistentialQuantification
+    FlexibleContexts
+    FlexibleInstances
+    GeneralizedNewtypeDeriving
+    ImplicitParams
+    KindSignatures
+    NondecreasingIndentation
+    OverloadedStrings
+    RankNTypes
+    RecordWildCards
+    ScopedTypeVariables
+    StandaloneDeriving
+    Trustworthy
+    TypeFamilies
+    TypeOperators
+    TypeSynonymInstances
+    UndecidableInstances
+
+  if impl(ghc >=7.11)
+    other-extensions: PatternSynonyms
+
+-- Small, fast running tests.
+test-suite unit-tests
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   tests
+  other-modules:
+    Test.Laws
+    Test.QuickCheck.Utils
+    UnitTests.Distribution.Compat.CreatePipe
+    UnitTests.Distribution.Compat.Graph
+    UnitTests.Distribution.Compat.Time
+    UnitTests.Distribution.Simple.Glob
+    UnitTests.Distribution.Simple.Program.Internal
+    UnitTests.Distribution.Simple.Utils
+    UnitTests.Distribution.SPDX
+    UnitTests.Distribution.System
+    UnitTests.Distribution.Types.GenericPackageDescription
+    UnitTests.Distribution.Utils.Generic
+    UnitTests.Distribution.Utils.NubList
+    UnitTests.Distribution.Utils.ShortText
+    UnitTests.Distribution.Version
+
+  main-is:          UnitTests.hs
+  build-depends:
+      array
+    , base
+    , bytestring
+    , Cabal
+    , containers
+    , directory
+    , filepath
+    , integer-logarithms >=1.0.2 && <1.1
+    , pretty
+    , QuickCheck >=2.11.3 && <2.12
+    , tagged
+    , tasty >=1.1.0.3 && <1.2
+    , tasty-hunit
+    , tasty-quickcheck
+    , temporary
+    , text
+
+  ghc-options:      -Wall
+  default-language: Haskell2010
+
+test-suite parser-tests
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   tests
+  main-is:          ParserTests.hs
+  build-depends:
+      base
+    , base-compat >=0.10.4 && <0.11
+    , bytestring
+    , Cabal
+    , Diff >=0.3.4 && <0.4
+    , directory
+    , filepath
+    , tasty >=1.1.0.3 && <1.2
+    , tasty-golden >=2.3.1.1 && <2.4
+    , tasty-hunit
+    , tasty-quickcheck
+
+  ghc-options:      -Wall
+  default-language: Haskell2010
+
+  if impl(ghc >=7.8)
+    build-depends: tree-diff >=0.0.1 && <0.1
+    other-modules:
+      Instances.TreeDiff
+      Instances.TreeDiff.Language
+      Instances.TreeDiff.SPDX
+      Instances.TreeDiff.Version
+
+test-suite check-tests
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   tests
+  main-is:          CheckTests.hs
+  build-depends:
+      base
+    , bytestring
+    , Cabal
+    , Diff >=0.3.4 && <0.4
+    , directory
+    , filepath
+    , tasty >=1.1.0.3 && <1.2
+    , tasty-golden >=2.3.1.1 && <2.4
+
+  ghc-options:      -Wall
+  default-language: Haskell2010
+
+test-suite custom-setup-tests
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   tests/custom-setup
+  main-is:          CustomSetupTests.hs
+  other-modules:
+    CabalDoctestSetup
+    IdrisSetup
+
+  build-depends:
+      base
+    , Cabal
+    , directory
+    , filepath
+    , process
+
+  default-language: Haskell2010
+
+test-suite hackage-tests
+  type:               exitcode-stdio-1.0
+  main-is:            HackageTests.hs
+
+  -- TODO: need to get 01-index.tar on appveyor
+  if os(windows)
+    buildable: False
+
+  hs-source-dirs:     tests
+  build-depends:
+      base
+    , bytestring
+    , Cabal
+    , containers
+    , deepseq
+    , directory
+    , filepath
+
+  build-depends:
+      base-compat >=0.10.4 && <0.11
+    , base-orphans >=0.6 && <0.9
+    , optparse-applicative >=0.13.2.0 && <0.15
+    , stm >=2.4.5.0 && <2.6
+    , tar >=0.5.0.3 && <0.6
+
+  if impl(ghc >=7.8)
+    build-depends: tree-diff >=0.0.1 && <0.1
+    other-modules:
+      Instances.TreeDiff
+      Instances.TreeDiff.Language
+      Instances.TreeDiff.SPDX
+      Instances.TreeDiff.Version
+
+  ghc-options:        -Wall -rtsopts -threaded
+  default-extensions: CPP
+  default-language:   Haskell2010
diff --git a/fixtures/cabal-fmt.format b/fixtures/cabal-fmt.format
--- a/fixtures/cabal-fmt.format
+++ b/fixtures/cabal-fmt.format
@@ -11,11 +11,11 @@
   -- build depends will be in
   -- a nice tabular format
   build-depends:
-    , base        >=4.11     && <4.13
+    , base        >=4.11      && <4.13
     , bytestring
     , Cabal       ^>=2.5
     , containers  ^>=0.5.11.0 || ^>=0.6.0.1
-    , pretty      ^>=1.1.3.6
+    , pretty      >=1.1.3.6   && <1.2
 
   -- extensions will be sorted
   other-extensions:
diff --git a/fixtures/simple-example.cabal b/fixtures/simple-example.cabal
--- a/fixtures/simple-example.cabal
+++ b/fixtures/simple-example.cabal
@@ -57,6 +57,11 @@
   build-depends: foo <2
   build-depends: abc <1, def <1, ghj <2
 
+  -- build-tool-depends are formatted like build-depends
+  build-tool-depends: happy:happy
+
+  build-tool-depends: happy:happy >=1, alex:alex >=1
+
 test-suite doctests
   type:                exitcode-stdio-1.0
   main-is:             doctests.hs
diff --git a/fixtures/simple-example.format b/fixtures/simple-example.format
--- a/fixtures/simple-example.format
+++ b/fixtures/simple-example.format
@@ -56,8 +56,8 @@
   if impl(hugs)
     build-depends: unbuildable <0
     build-depends:
-        unbuildable <0
-      , unbuildable2 <0
+        unbuildable   <0
+      , unbuildable2  <0
 
   -- full interval
   build-depends:      text
@@ -66,12 +66,18 @@
     , pretty
 
   -- only upper bound
-  build-depends:      foo ==0.*
+  build-depends:      foo <1
   build-depends:      foo <2
   build-depends:
       abc  <1
     , def  <1
     , ghj  <2
+
+  -- build-tool-depends are formatted like build-depends
+  build-tool-depends: happy:happy
+  build-tool-depends:
+      alex:alex    >=1
+    , happy:happy  >=1
 
 test-suite doctests
   type:             exitcode-stdio-1.0
diff --git a/fixtures/tree-diff.cabal b/fixtures/tree-diff.cabal
new file mode 100644
--- /dev/null
+++ b/fixtures/tree-diff.cabal
@@ -0,0 +1,190 @@
+cabal-version:      2.2
+name:               tree-diff
+version:            0.2.2
+synopsis:           Diffing of (expression) trees.
+category:           Data, Testing
+description:
+  Common diff algorithm works on list structures:
+  .
+  @
+  diff :: Eq a => [a] -> [a] -> [Edit a]
+  @
+  .
+  This package works on trees.
+  .
+  @
+  treeDiff :: Eq a => Tree a -> Tree a -> Edit (EditTree a)
+  @
+  .
+  This package also provides a way to diff arbitrary ADTs,
+  using @Generics@-derivable helpers.
+  .
+  This package differs from <http://hackage.haskell.org/package/gdiff gdiff>,
+  in a two ways: @tree-diff@ doesn't have patch function,
+  and the "edit-script" is a tree itself, which is useful for pretty-printing.
+  .
+  @
+  >>> prettyEditExpr $ ediff (Foo 42 [True, False] "old") (Foo 42 [False, False, True] "new")
+  Foo
+  \  {fooBool = [-True, +False, False, +True],
+  \   fooInt = 42,
+  \   fooString = -"old" +"new"}
+  @
+
+homepage:           https://github.com/phadej/tree-diff
+bug-reports:        https://github.com/phadej/tree-diff/issues
+license:            GPL-2.0-or-later
+license-file:       LICENSE
+author:             Oleg Grenrus <oleg.grenrus@iki.fi>
+maintainer:         Oleg.Grenrus <oleg.grenrus@iki.fi>
+copyright:          (c) 2017-2021 Oleg Grenrus
+build-type:         Simple
+extra-source-files:
+  ChangeLog.md
+  README.md
+
+tested-with:
+    GHC ==7.4.2
+     || ==7.6.3
+     || ==7.8.4
+     || ==7.10.3
+     || ==8.0.2
+     || ==8.2.2
+     || ==8.4.4
+     || ==8.6.5
+     || ==8.8.4
+     || ==8.10.4
+     || ==9.0.2
+     || ==9.2.4
+     || ==9.4.1
+  , GHCJS ==8.4
+
+extra-source-files:
+  fixtures/exfoo.expr
+  fixtures/MyInt1.expr
+  fixtures/MyInt2.expr
+  fixtures/MyInt3.expr
+  fixtures/Positional.expr
+
+source-repository head
+  type:     git
+  location: https://github.com/phadej/tree-diff.git
+
+library
+  exposed-modules:
+    Data.TreeDiff
+    Data.TreeDiff.Class
+    Data.TreeDiff.Expr
+    Data.TreeDiff.Golden
+    Data.TreeDiff.List
+    Data.TreeDiff.OMap
+    Data.TreeDiff.Parser
+    Data.TreeDiff.Pretty
+    Data.TreeDiff.QuickCheck
+    Data.TreeDiff.Tree
+
+  -- GHC boot libraries
+  build-depends:
+    , base        >=4.5      && <4.18
+    , bytestring  ^>=0.9.2.1 || ^>=0.10.0.2 || ^>=0.11.0.0
+    , containers  ^>=0.4.2.1 || ^>=0.5.0.0 || ^>=0.6.0.1
+    , deepseq     ^>=1.3.0.0 || ^>=1.4.0.0
+    , parsec      ^>=3.1.13.0
+    , pretty      ^>=1.1.1.0
+    , text        ^>=1.2.3.0 || ^>=2.0
+    , time        ^>=1.4      || ^>=1.5.0.1  || ^>=1.6.0.1  || ^>=1.8.0.2 || >=1.9.3 && <1.13
+
+  build-depends:
+    , aeson                 ^>=1.4.6.0 || ^>=1.5.6.0 || ^>=2.0.0.0 || ^>=2.1.0.0
+    , ansi-terminal         >=0.10       && <0.12
+    , ansi-wl-pprint        ^>=0.6.8.2
+    , base-compat           ^>=0.10.5 || ^>=0.11.0 || ^>=0.12.0
+    , bytestring-builder    ^>=0.10.8.2.0
+    , hashable              ^>=1.2.7.0 || ^>=1.3.0.0 || ^>=1.4.0.1
+    , parsers               ^>=0.12.10
+    , primitive             ^>=0.7.1.0
+    , QuickCheck            ^>=2.14.2
+    , scientific            ^>=0.3.6.2
+    , semialign             ^>=1.2.0.1
+    , strict                ^>=0.4.0.1
+    , tagged                ^>=0.8.6
+    , these                 ^>=1.1.1.1
+    , unordered-containers  ^>=0.2.8.0
+    , uuid-types            ^>=1.0.3
+    , vector                ^>=0.12.0.0 || ^>=0.13.0.0
+
+  if impl(ghc <7.5)
+    build-depends: ghc-prim
+
+  if !impl(ghc >=8.0)
+    build-depends: semigroups >=0.19.1 && <0.21
+
+  if !impl(ghc >=7.8)
+    build-depends: generic-deriving >=1.13.1 && <1.15
+
+  if !impl(ghc >=7.10)
+    build-depends:
+      , nats          ^>=1.1.2
+      , transformers  ^>=0.3.0.0 || ^>=0.4.2.0 || ^>=0.5.2.0
+      , void          ^>=0.7.3
+
+  other-extensions:
+    CPP
+    ConstraintKinds
+    DefaultSignatures
+    FlexibleContexts
+    GADTs
+    RankNTypes
+    ScopedTypeVariables
+    TypeOperators
+
+  hs-source-dirs:   src
+  default-language: Haskell2010
+
+test-suite tree-diff-test
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  main-is:          Tests.hs
+  hs-source-dirs:   tests src-diff
+  ghc-options:      -Wall -threaded
+  other-modules:    RefDiffBy
+
+  -- dependencies from library
+  build-depends:
+    , ansi-terminal
+    , ansi-wl-pprint
+    , base
+    , base-compat
+    , parsec
+    , primitive
+    , QuickCheck
+    , tagged
+    , tree-diff
+
+  if impl(ghc <7.5)
+    build-depends: ghc-prim
+
+  -- extra dependencies
+  build-depends:
+    , tasty             ^>=1.2 || ^>=1.3.1 || ^>=1.4.2
+    , tasty-golden      ^>=2.3.1.1
+    , tasty-quickcheck  ^>=0.10.1
+    , trifecta          >=2       && <2.2
+
+benchmark tree-diff-bench
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  main-is:          tree-diff-bench.hs
+  hs-source-dirs:   bench
+  ghc-options:      -Wall -threaded
+
+  -- dependencies from library
+  build-depends:
+    , base
+    , deepseq
+    , tree-diff
+
+  -- extra dependencies
+  build-depends:
+    , criterion  ^>=1.6.0.0
+    , Diff       ^>=0.4.0
diff --git a/fixtures/tree-diff.format b/fixtures/tree-diff.format
new file mode 100644
--- /dev/null
+++ b/fixtures/tree-diff.format
@@ -0,0 +1,190 @@
+cabal-version:      2.2
+name:               tree-diff
+version:            0.2.2
+synopsis:           Diffing of (expression) trees.
+category:           Data, Testing
+description:
+  Common diff algorithm works on list structures:
+  .
+  @
+  diff :: Eq a => [a] -> [a] -> [Edit a]
+  @
+  .
+  This package works on trees.
+  .
+  @
+  treeDiff :: Eq a => Tree a -> Tree a -> Edit (EditTree a)
+  @
+  .
+  This package also provides a way to diff arbitrary ADTs,
+  using @Generics@-derivable helpers.
+  .
+  This package differs from <http://hackage.haskell.org/package/gdiff gdiff>,
+  in a two ways: @tree-diff@ doesn't have patch function,
+  and the "edit-script" is a tree itself, which is useful for pretty-printing.
+  .
+  @
+  >>> prettyEditExpr $ ediff (Foo 42 [True, False] "old") (Foo 42 [False, False, True] "new")
+  Foo
+  \  {fooBool = [-True, +False, False, +True],
+  \   fooInt = 42,
+  \   fooString = -"old" +"new"}
+  @
+
+homepage:           https://github.com/phadej/tree-diff
+bug-reports:        https://github.com/phadej/tree-diff/issues
+license:            GPL-2.0-or-later
+license-file:       LICENSE
+author:             Oleg Grenrus <oleg.grenrus@iki.fi>
+maintainer:         Oleg.Grenrus <oleg.grenrus@iki.fi>
+copyright:          (c) 2017-2021 Oleg Grenrus
+build-type:         Simple
+extra-source-files:
+  ChangeLog.md
+  README.md
+
+tested-with:
+    GHC ==7.4.2
+     || ==7.6.3
+     || ==7.8.4
+     || ==7.10.3
+     || ==8.0.2
+     || ==8.2.2
+     || ==8.4.4
+     || ==8.6.5
+     || ==8.8.4
+     || ==8.10.4
+     || ==9.0.2
+     || ==9.2.4
+     || ==9.4.1
+  , GHCJS ==8.4
+
+extra-source-files:
+  fixtures/exfoo.expr
+  fixtures/MyInt1.expr
+  fixtures/MyInt2.expr
+  fixtures/MyInt3.expr
+  fixtures/Positional.expr
+
+source-repository head
+  type:     git
+  location: https://github.com/phadej/tree-diff.git
+
+library
+  exposed-modules:
+    Data.TreeDiff
+    Data.TreeDiff.Class
+    Data.TreeDiff.Expr
+    Data.TreeDiff.Golden
+    Data.TreeDiff.List
+    Data.TreeDiff.OMap
+    Data.TreeDiff.Parser
+    Data.TreeDiff.Pretty
+    Data.TreeDiff.QuickCheck
+    Data.TreeDiff.Tree
+
+  -- GHC boot libraries
+  build-depends:
+    , base        >=4.5       && <4.18
+    , bytestring  ^>=0.9.2.1  || ^>=0.10.0.2 || ^>=0.11.0.0
+    , containers  ^>=0.4.2.1  || ^>=0.5.0.0  || ^>=0.6.0.1
+    , deepseq     ^>=1.3.0.0  || ^>=1.4.0.0
+    , parsec      ^>=3.1.13.0
+    , pretty      ^>=1.1.1.0
+    , text        ^>=1.2.3.0  || ^>=2.0
+    , time        ^>=1.4      || ^>=1.5.0.1  || ^>=1.6.0.1  || ^>=1.8.0.2 || >=1.9.3 && <1.12 || ^>=1.12
+
+  build-depends:
+    , aeson                 ^>=1.4.6.0    || ^>=1.5.6.0  || ^>=2.0.0.0 || ^>=2.1.0.0
+    , ansi-terminal         >=0.10        && <0.12
+    , ansi-wl-pprint        ^>=0.6.8.2
+    , base-compat           ^>=0.10.5     || ^>=0.11.0   || ^>=0.12.0
+    , bytestring-builder    ^>=0.10.8.2.0
+    , hashable              ^>=1.2.7.0    || ^>=1.3.0.0  || ^>=1.4.0.1
+    , parsers               ^>=0.12.10
+    , primitive             ^>=0.7.1.0
+    , QuickCheck            ^>=2.14.2
+    , scientific            ^>=0.3.6.2
+    , semialign             ^>=1.2.0.1
+    , strict                ^>=0.4.0.1
+    , tagged                ^>=0.8.6
+    , these                 ^>=1.1.1.1
+    , unordered-containers  ^>=0.2.8.0
+    , uuid-types            ^>=1.0.3
+    , vector                ^>=0.12.0.0   || ^>=0.13.0.0
+
+  if impl(ghc <7.5)
+    build-depends: ghc-prim
+
+  if !impl(ghc >=8.0)
+    build-depends: semigroups >=0.19.1 && <0.21
+
+  if !impl(ghc >=7.8)
+    build-depends: generic-deriving >=1.13.1 && <1.15
+
+  if !impl(ghc >=7.10)
+    build-depends:
+      , nats          ^>=1.1.2
+      , transformers  ^>=0.3.0.0 || ^>=0.4.2.0 || ^>=0.5.2.0
+      , void          ^>=0.7.3
+
+  other-extensions:
+    CPP
+    ConstraintKinds
+    DefaultSignatures
+    FlexibleContexts
+    GADTs
+    RankNTypes
+    ScopedTypeVariables
+    TypeOperators
+
+  hs-source-dirs:   src
+  default-language: Haskell2010
+
+test-suite tree-diff-test
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  main-is:          Tests.hs
+  hs-source-dirs:   tests src-diff
+  ghc-options:      -Wall -threaded
+  other-modules:    RefDiffBy
+
+  -- dependencies from library
+  build-depends:
+    , ansi-terminal
+    , ansi-wl-pprint
+    , base
+    , base-compat
+    , parsec
+    , primitive
+    , QuickCheck
+    , tagged
+    , tree-diff
+
+  if impl(ghc <7.5)
+    build-depends: ghc-prim
+
+  -- extra dependencies
+  build-depends:
+    , tasty             ^>=1.2     || ^>=1.3.1 || ^>=1.4.2
+    , tasty-golden      ^>=2.3.1.1
+    , tasty-quickcheck  ^>=0.10.1
+    , trifecta          >=2        && <2.2
+
+benchmark tree-diff-bench
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  main-is:          tree-diff-bench.hs
+  hs-source-dirs:   bench
+  ghc-options:      -Wall -threaded
+
+  -- dependencies from library
+  build-depends:
+    , base
+    , deepseq
+    , tree-diff
+
+  -- extra dependencies
+  build-depends:
+    , criterion  ^>=1.6.0.0
+    , Diff       ^>=0.4.0
diff --git a/fixtures/with-sublibs.cabal b/fixtures/with-sublibs.cabal
new file mode 100644
--- /dev/null
+++ b/fixtures/with-sublibs.cabal
@@ -0,0 +1,12 @@
+cabal-version: 3.0
+name:          with-sublibs
+version:       1
+
+library
+  hs-source-dirs:     src
+  default-language:   Haskell2010
+  build-depends:
+    test1,
+    test1:sub,
+    test2 >=1 && <3,
+    test2:sub >=2 && <4
diff --git a/fixtures/with-sublibs.format b/fixtures/with-sublibs.format
new file mode 100644
--- /dev/null
+++ b/fixtures/with-sublibs.format
@@ -0,0 +1,11 @@
+Up to date
+cabal-version: 3.0
+name:          with-sublibs
+version:       1
+
+library
+  hs-source-dirs:   src
+  default-language: Haskell2010
+  build-depends:
+    , test1:{test1, sub}
+    , test2:{test2, sub}  >=2 && <3
diff --git a/src-interval/VersionInterval.hs b/src-interval/VersionInterval.hs
new file mode 100644
--- /dev/null
+++ b/src-interval/VersionInterval.hs
@@ -0,0 +1,444 @@
+{-# LANGUAGE BangPatterns #-}
+
+-- |
+--
+-- Author:          Oleg Grenrus <oleg.grenrus@iki.fi>
+-- SPDX-License-Id: GPL-2.0-or-later
+--
+-- This module implements a view of a 'VersionRange' as a finite
+-- list of separated version intervals.
+--
+-- In conversion from and to 'VersionRange' it makes some effort to
+-- preserve the caret operator @^>=x.y@.  This constraint a priori
+-- specifies the same interval as @==x.y.*@, but indicates that newer
+-- versions could be acceptable (@allow-newer: ^@).
+--
+module VersionInterval (
+    -- * Version intervals
+    VersionIntervals,
+    unVersionIntervals,
+
+    -- * Conversions
+    toVersionIntervals,
+    fromVersionIntervals,
+    ConversionProblem (..),
+
+    -- ** Normalisation
+    normaliseVersionRange,
+
+    -- * Version intervals view
+    VersionInterval (..),
+    LB(..),
+    MB(..),
+    UB(..),
+    Bound(..),
+
+    -- * For testing
+    validVersionInterval,
+    validVersionIntervals,
+    intersectInterval,
+    stage1, stage2, stage3,
+)  where
+
+import Control.Applicative (liftA2)
+import Control.Monad       (join)
+import Data.List           (sortOn)
+import Data.List.NonEmpty  (NonEmpty (..), cons)
+import Data.Maybe          (catMaybes)
+
+import Distribution.Types.Version
+       (Version, mkVersion, validVersion, version0, versionNumbers)
+import Distribution.Types.VersionRange.Internal
+       (VersionRange, VersionRangeF (..), cataVersionRange, earlierVersion,
+       intersectVersionRanges, majorBoundVersion, majorUpperBound, noVersion,
+       orLaterVersion, thisVersion, unionVersionRanges)
+
+singleton :: a -> NonEmpty a
+singleton x = x :| []
+
+-------------------------------------------------------------------------------
+-- Data
+-------------------------------------------------------------------------------
+
+-- | A complementary representation of a 'VersionRange'. Instead of a boolean
+-- version predicate it uses an increasing sequence of non-overlapping,
+-- non-empty intervals.
+--
+-- This version is different than in @Cabal-3.8@ and previous,
+-- as it tries to preserve @^>=@ version ranges under default and @transformCaretUpper@ semantics.
+-- Slighly simplifying, 'normalizeVersionRange' shouldn't destroy @^>=@ in version range expressions.
+--
+newtype VersionIntervals = VersionIntervals [VersionInterval]
+  deriving (Eq, Show)
+
+-- | Inspect the list of version intervals.
+--
+unVersionIntervals :: VersionIntervals -> [VersionInterval]
+unVersionIntervals (VersionIntervals is) = is
+
+-- | Version interval.
+--
+-- Invariants:
+--
+-- * Interval is non-empty
+-- * 'MB' is between 'LB' and 'UB'.
+--
+data VersionInterval = VI !LB !MB !UB
+  deriving (Eq, Show)
+
+-- | Lower bound. For intervals it always exist: 'zeroLB' i.e. @>= 0@.
+--
+-- All lower bound intervals are inclusive, i.e. @>=v@. @>x.y.z@ is converted into @>=x.y.z.0@.
+--
+data LB = LB !Version
+  deriving (Eq, Ord, Show)
+
+-- | Upper bound.
+--
+-- All upper bounds are exclusive, i.e. @<v@. @<=x.y.z@ is converted to @<x.y.z.0@.
+--
+--
+data UB
+    = UB !Version   -- ^ upper bound
+    | NoUB          -- ^ no upper bound (i.e. infinite)
+  deriving (Eq, Ord, Show)
+
+-- | Bound variant.
+data Bound
+    = Incl  -- ^ inclusive: @>=@ or @<=@
+    | Excl  -- ^ exclusive: @>@ or @<@
+  deriving (Eq, Ord, Show)
+
+-- | Middle bound.
+data MB
+    = MB !Version  -- ^ major bound.
+    | NoMB         -- ^ no major bound (i.e. infinite)
+  deriving (Eq, Ord, Show)
+
+-- | @>=0@
+zeroLB :: LB
+zeroLB = LB version0
+
+-- | Whether the version is @0@.
+isVersion0 :: Version -> Bool
+isVersion0 = (==) version0
+
+-- | Versions are not separated type.
+succVersion :: Version -> Version
+succVersion v = mkVersion (versionNumbers v ++ [0])
+
+-------------------------------------------------------------------------------
+-- Stage1
+-------------------------------------------------------------------------------
+
+stage1 :: ([VersionInterval] -> [VersionInterval]) -> VersionRange -> [VersionInterval]
+stage1 opt = cataVersionRange alg where
+    -- version range leafs transform into singleton intervals
+    alg (ThisVersionF v)                = [VI (LB v)                (MB (succVersion v))      (UB (succVersion v))]
+    alg (LaterVersionF v)               = [VI (LB (succVersion v))  NoMB                      NoUB]
+    alg (OrLaterVersionF v)             = [VI (LB v)                NoMB                      NoUB]
+    alg (EarlierVersionF v)
+        | isVersion0 v                  = []
+        | otherwise                     = [VI zeroLB                (MB v)                    (UB v)]
+    alg (OrEarlierVersionF v)           = [VI zeroLB                (MB (succVersion v))      (UB (succVersion v))]
+
+    -- ^>= version-range's upper bound should be MajorBound
+    alg (MajorBoundVersionF v)          = [VI (LB v)                (MB (majorUpperBound v))  NoUB]
+
+    -- union: just merge the version intervals
+    alg (UnionVersionRangesF v1 v2)     = v1 ++ v2
+
+    -- intersection: pairwise intersect. Strip empty intervals. Sort to restore the invariant.
+    alg (IntersectVersionRangesF v1 v2) = catMaybes $ liftA2 intersectInterval (opt v1) (opt v2)
+
+-------------------------------------------------------------------------------
+-- Stage2
+-------------------------------------------------------------------------------
+
+stage2 :: [VersionInterval] -> [VersionInterval]
+stage2 = sortOn (\(VI l _ _) -> l)
+
+-------------------------------------------------------------------------------
+-- Postprocess
+-------------------------------------------------------------------------------
+
+stage2and3 :: [VersionInterval] -> [VersionInterval]
+stage2and3 = stage3 . stage2
+
+stage3 :: [VersionInterval] -> [VersionInterval]
+stage3 []                = []
+stage3 (VI l m u : rest) = stage3go l m u rest
+
+stage3go :: LB -> MB -> UB -> [VersionInterval] -> [VersionInterval]
+stage3go l m u []                 = [VI l m u]
+stage3go l m u (VI l' m' u' : is)
+    | l == l'   = stage3go l' (unionMB m m') (unionUB u u') is
+    | otherwise = case overlap m u l' of
+        NoOverlap -> VI l m u : stage3go l' m' u' is
+        OverlapU  -> viCons (VI l m (trimLB u l')) (stage3go l' m' (unionUB u u') is)
+        OverlapM  -> stage3go l (unionMB m m') (unionUB u u') is
+  where
+    viCons :: VersionInterval -> [VersionInterval] -> [VersionInterval]
+    viCons i | nonEmptyVI i = (i :)
+    viCons _                = id
+
+trimLB :: UB -> LB -> UB
+trimLB _    (LB l) = UB l
+
+-------------------------------------------------------------------------------
+-- Intersections
+-------------------------------------------------------------------------------
+
+intersectInterval :: VersionInterval -> VersionInterval -> Maybe VersionInterval
+intersectInterval (VI xl xm xu) (VI yl ym yu)
+    | nonEmptyVI xy = Just xy
+    | otherwise     = Nothing
+  where
+    l = intersectLB xl yl
+    m = intersectMB xm ym
+    u = intersectUB xu yu
+
+    -- make middle bound be between l and u
+    m' = rtrimMB (ltrimMB l m) u
+
+    xy = VI l m' u
+
+ltrimMB :: LB -> MB -> MB
+ltrimMB _         NoMB      = NoMB
+ltrimMB (LB l) (MB m) = case compare l m of
+    LT -> MB m
+    EQ -> MB m
+    GT -> MB l
+
+rtrimMB :: MB -> UB -> MB
+rtrimMB m      NoUB   = m
+rtrimMB NoMB   (UB u) = MB u
+rtrimMB (MB m) (UB u) = MB (min m u)
+
+intersectLB :: LB -> LB -> LB
+intersectLB (LB v) (LB u) = LB (max v u)
+
+intersectMB :: MB -> MB -> MB
+intersectMB NoMB   b      = b
+intersectMB b      NoMB   = b
+intersectMB (MB v) (MB u) = MB (min v u)
+
+intersectUB :: UB -> UB -> UB
+intersectUB NoUB   b      = b
+intersectUB b      NoUB   = b
+intersectUB (UB v) (UB u) = UB (min v u)
+
+intersectMBandUB :: MB -> UB -> UB
+intersectMBandUB NoMB   b      = b
+intersectMBandUB (MB v) NoUB   = UB v
+intersectMBandUB (MB v) (UB u) = UB (min v u)
+
+-------------------------------------------------------------------------------
+-- Unions
+-------------------------------------------------------------------------------
+
+unionMB :: MB -> MB -> MB
+unionMB NoMB   _      = NoMB
+unionMB _      NoMB   = NoMB
+unionMB (MB v) (MB u) = MB (max v u)
+
+unionUB :: UB -> UB -> UB
+unionUB NoUB   _      = NoUB
+unionUB _      NoUB   = NoUB
+unionUB (UB v) (UB u) = UB (max v u)
+
+-------------------------------------------------------------------------------
+-- Helpers
+-------------------------------------------------------------------------------
+
+-- | Overlaps.
+--
+data Overlap
+    = NoOverlap  -- ^ no overlap, next interval's @l@ is greater than @u@
+    | OverlapM   -- ^ overlaps, next interval's @l@ is less than @m@
+    | OverlapU   -- ^ overlaps, next interval's @l@ is less than @u@ (but greater than @m@)
+  deriving (Eq, Show)
+
+overlap :: MB -> UB -> LB -> Overlap
+overlap _           (UB u ) (LB l) | u <  l = NoOverlap
+overlap (MB m ) _           (LB l) | m <  l = OverlapU
+overlap _           _           _           = OverlapM
+
+-------------------------------------------------------------------------------
+-- Invariants
+-------------------------------------------------------------------------------
+
+-- | 'VersionIntervals' invariant:
+--
+-- * all intervals are valid (lower bound is less then upper bound, middle bound is in between)
+-- * intervals doesn't touch each other (distinct)
+--
+validVersionIntervals :: VersionIntervals -> Bool
+validVersionIntervals (VersionIntervals intervals) =
+    all validVersionInterval intervals &&
+    all doesNotTouch' (pairs intervals)
+  where
+    doesNotTouch' :: (VersionInterval, VersionInterval) -> Bool
+    doesNotTouch' (VI l m u, VI l' _ _) = l < l' && case overlap m u l' of
+        NoOverlap -> True
+        OverlapM  -> False
+        OverlapU  -> case u of
+            NoUB     -> True
+            UB uv -> case l' of LB lv -> uv == lv
+
+pairs :: [a] -> [(a,a)]
+pairs xs = zip xs (tail xs)
+
+validLB :: LB -> Bool
+validLB (LB v) = validVersion v
+
+validUB :: UB -> Bool
+validUB NoUB   = True
+validUB (UB v) = validVersion v
+
+validMB :: MB -> Bool
+validMB NoMB   = True
+validMB (MB v) = validVersion v
+
+validVersionInterval :: VersionInterval -> Bool
+validVersionInterval i@(VI l m u) = validLB l && validMB m && validUB u && nonEmptyVI i && lbLessThanMB l m && mbLessThanUB m u
+
+mbLessThanUB :: MB -> UB -> Bool
+mbLessThanUB (MB m) (UB u) = m <= u
+mbLessThanUB NoMB   (UB _) = False
+mbLessThanUB _       NoUB  = True
+
+lbLessThanMB :: LB -> MB -> Bool
+lbLessThanMB _      NoMB   = True
+lbLessThanMB (LB l) (MB m) = l <= m
+
+-- Check an interval is non-empty
+--
+nonEmptyVI :: VersionInterval -> Bool
+nonEmptyVI (VI (LB _) _ NoUB)   = True
+nonEmptyVI (VI (LB l) _ (UB u)) = l < u
+
+-------------------------------------------------------------------------------
+-- Conversions
+-------------------------------------------------------------------------------
+
+-- | Convert a 'VersionRange' to a sequence of version intervals.
+--
+toVersionIntervals :: VersionRange -> VersionIntervals
+toVersionIntervals = VersionIntervals . stage2and3 . stage1 stage2and3
+
+data ConversionProblem
+    = IntervalsEmpty
+    | OtherConversionProblem
+  deriving (Eq, Show)
+
+-- | Convert a 'VersionIntervals' value back into a 'VersionRange' expression
+-- representing the version intervals.
+--
+fromVersionIntervals :: VersionIntervals -> Either ConversionProblem VersionRange
+fromVersionIntervals (VersionIntervals [])     = Right noVersion
+fromVersionIntervals (VersionIntervals (x:xs)) =
+    case join <$> traverse intervalToVersionRange (preprocess x xs) of
+        Just vrs -> Right (foldr1 unionVersionRanges vrs)
+        Nothing  -> Left $
+            if all seemsEmpty (x:xs)
+            then IntervalsEmpty
+            else OtherConversionProblem
+  where
+    -- we can remove upper bounds, if they touch next interval, and the next interval doesn't have upper bound
+    preprocess :: VersionInterval -> [VersionInterval] -> NonEmpty VersionInterval
+    preprocess i [] = i :| []
+    preprocess i@(VI l m u) (j:js) = case u' of
+        NoUB | touchesUB u l' -> cons (VI l m NoUB) js'
+        _                     -> cons i             js'
+      where
+        js'@(VI l' _ u' :| _)  = preprocess j js
+
+    seemsEmpty :: VersionInterval -> Bool
+    seemsEmpty (VI l m u) = not (nonEmptyVI (VI l NoMB (intersectMBandUB m u)))
+
+touchesUB :: UB -> LB -> Bool
+touchesUB NoUB   _      = True
+touchesUB (UB u) (LB l) = u >= l
+
+lbToVR :: LB -> VersionRange
+lbToVR (LB l) = orLaterVersion l
+
+ubToVR :: UB -> VersionRange -> VersionRange
+ubToVR NoUB   vr = vr
+ubToVR (UB u) vr = intersectVersionRanges vr (earlierVersion u)
+
+mbEqUB :: MB -> UB -> Bool
+mbEqUB NoMB   NoUB   = True
+mbEqUB NoMB   (UB _) = False
+mbEqUB (MB m) (UB u) = m == u
+mbEqUB (MB _) NoUB   = False
+
+-- return the unions of version ranges.
+intervalToVersionRange :: VersionInterval -> Maybe (NonEmpty VersionRange)
+intervalToVersionRange (VI l m u) | mbEqUB m u = Just (singleton (intervalToVersionRange1 l u))
+intervalToVersionRange (VI l m u)              = fmap (fmap (ubToVR u)) (intervalToVersionRange2 l m)
+
+intervalToVersionRange1 :: LB -> UB -> VersionRange
+intervalToVersionRange1 (LB v) upper' = case upper' of
+    NoUB
+        -> lowerBound
+
+    UB u
+        | succVersion v == u
+        -> thisVersion v
+
+    UB u -> withLowerBound (makeUpperBound u)
+  where
+    lowerBound :: VersionRange
+    lowerBound = lbToVR (LB v)
+
+    withLowerBound :: VersionRange -> VersionRange
+    withLowerBound vr
+        | isVersion0 v = vr
+        | otherwise    = intersectVersionRanges lowerBound vr
+
+    makeUpperBound :: Version -> VersionRange
+    makeUpperBound u = earlierVersion u
+
+intervalToVersionRange2 :: LB -> MB -> Maybe (NonEmpty VersionRange)
+intervalToVersionRange2 (LB l) major = case major of
+    NoMB -> Just (singleton lowerBound)
+    MB m
+        | majorUpperBound l == m
+        -> Just (singleton (majorBoundVersion l))
+
+{-
+    MB m
+        | [a,b]  <- versionNumbers m
+        , a' : _ <- versionNumbers l
+        , a' == a
+        , b >= 1
+        , majorUpperBound l <= m
+        -> Just $ go (majorBoundVersion l :|) (majorUpperBound l)
+      where
+        go acc v = if v >= m then acc [] else go (acc . (majorBoundVersion v :)) (majorUpperBound v)
+-}
+
+    MB m
+        | [a,b] <- versionNumbers m
+        , let m' = mkVersion [a,b-1]
+        , b >= 1
+        , m' > l
+        -> Just $
+            (ubToVR (UB m') (lbToVR (LB l)))
+            :| [ majorBoundVersion (mkVersion [a, b-1]) ]
+
+    _ -> Nothing
+  where
+    lowerBound :: VersionRange
+    lowerBound = lbToVR (LB l)
+
+-------------------------------------------------------------------------------
+-- Normalisation
+-------------------------------------------------------------------------------
+
+-- | Convert 'VersionRange' to 'VersionIntervals' and back.
+--
+normaliseVersionRange :: VersionRange -> Either ConversionProblem VersionRange
+normaliseVersionRange = fromVersionIntervals . toVersionIntervals
diff --git a/src/CabalFmt.hs b/src/CabalFmt.hs
--- a/src/CabalFmt.hs
+++ b/src/CabalFmt.hs
@@ -11,7 +11,6 @@
 
 import Control.Monad        (join)
 import Control.Monad.Reader (asks, local)
-import Data.Either          (partitionEithers)
 
 import qualified Data.ByteString                              as BS
 import qualified Distribution.CabalSpecVersion                as C
@@ -22,13 +21,12 @@
 import qualified Distribution.PackageDescription.FieldGrammar as C
 import qualified Distribution.Parsec                          as C
 import qualified Distribution.Pretty                          as C
-import qualified Distribution.Simple.Utils                    as C
 import qualified Distribution.Types.Condition                 as C
 import qualified Distribution.Types.ConfVar                   as C
 import qualified Distribution.Types.GenericPackageDescription as C
 import qualified Distribution.Types.PackageDescription        as C
-import qualified Distribution.Types.Version                   as C
 import qualified Distribution.Types.VersionRange              as C
+import qualified Distribution.Utils.Generic                   as C
 import qualified Text.PrettyPrint                             as PP
 
 import CabalFmt.Comments
@@ -79,9 +77,7 @@
         False -> return C.cabalSpecLatest
         True  -> do
             gpd <- parseGpd filepath contents
-            return $ C.cabalSpecFromVersionDigits
-              $ C.versionNumbers
-              $ C.specVersion
+            return $ C.specVersion
               $ C.packageDescription gpd
 
     local (over options $ \o -> runOptionsMorphism optsEndo $ o { optSpecVersion = csv }) $ do
@@ -93,12 +89,13 @@
             prettySectionArgs
             inputFields
 
-        return $ C.showFields' fromComments indentWith outputPrettyFields
+        return $ C.showFields' fromComments (const id) indentWith outputPrettyFields
             & if nullComments endComments then id else
                 (++ unlines ("" : [ C.fromUTF8BS c | c <- unComments endComments ]))
 
-fromComments :: Comments -> [String]
-fromComments (Comments bss) = map C.fromUTF8BS bss
+fromComments :: Comments -> C.CommentPosition
+fromComments (Comments [])  = C.NoComment
+fromComments (Comments bss) = C.CommentBefore (map C.fromUTF8BS bss)
 
 -------------------------------------------------------------------------------
 -- Field prettyfying
@@ -120,6 +117,7 @@
 fieldDescrs :: Options -> FieldDescrs () ()
 fieldDescrs opts
     =  buildDependsF opts
+    <> buildToolDependsF opts
     <> setupDependsF opts
     <> defaultExtensionsF
     <> otherExtensionsF
@@ -158,12 +156,12 @@
 ppCondition (C.CAnd c1 c2) = PP.parens (PP.hsep [ppCondition c1, PP.text "&&", ppCondition c2])
 
 ppConfVar :: C.ConfVar -> PP.Doc
-ppConfVar (C.OS os)     = PP.text "os"   PP.<> PP.parens (C.pretty os)
-ppConfVar (C.Arch arch) = PP.text "arch" PP.<> PP.parens (C.pretty arch)
-ppConfVar (C.Flag name) = PP.text "flag" PP.<> PP.parens (C.pretty name)
+ppConfVar (C.OS os)            = PP.text "os"   PP.<> PP.parens (C.pretty os)
+ppConfVar (C.Arch arch)        = PP.text "arch" PP.<> PP.parens (C.pretty arch)
+ppConfVar (C.PackageFlag name) = PP.text "flag" PP.<> PP.parens (C.pretty name)
 ppConfVar (C.Impl c v)
-    | v == C.anyVersion = PP.text "impl" PP.<> PP.parens (C.pretty c)
-    | otherwise         = PP.text "impl" PP.<> PP.parens (C.pretty c PP.<+> C.pretty v)
+    | v == C.anyVersion        = PP.text "impl" PP.<> PP.parens (C.pretty c)
+    | otherwise                = PP.text "impl" PP.<> PP.parens (C.pretty c PP.<+> C.pretty v)
 
 -------------------------------------------------------------------------------
 -- Pragma to OM
diff --git a/src/CabalFmt/Error.hs b/src/CabalFmt/Error.hs
--- a/src/CabalFmt/Error.hs
+++ b/src/CabalFmt/Error.hs
@@ -12,8 +12,8 @@
 import qualified Data.ByteString            as BS
 import qualified Data.ByteString.Char8      as BS8
 import qualified Distribution.Parsec        as C
-import qualified Distribution.Simple.Utils  as C (fromUTF8BS)
 import qualified Distribution.Types.Version as C
+import qualified Distribution.Utils.Generic as C (fromUTF8BS)
 
 data Error
     = SomeError String
diff --git a/src/CabalFmt/Fields.hs b/src/CabalFmt/Fields.hs
--- a/src/CabalFmt/Fields.hs
+++ b/src/CabalFmt/Fields.hs
@@ -3,7 +3,10 @@
 -- Copyright: Oleg Grenrus
 {-# LANGUAGE DeriveFunctor             #-}
 {-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE FlexibleInstances         #-}
+{-# LANGUAGE MultiParamTypeClasses     #-}
 {-# LANGUAGE RankNTypes                #-}
+{-# LANGUAGE UndecidableInstances      #-}
 module CabalFmt.Fields (
     FieldDescrs,
     fieldDescrLookup,
@@ -69,7 +72,7 @@
     -> FieldDescrs s a
 singletonF fn f g = F $ Map.singleton fn (SP f g)
 
-instance C.FieldGrammar FieldDescrs where
+instance C.FieldGrammar PrettyParsec FieldDescrs where
     blurFieldGrammar _ (F m) = F m
 
     booleanFieldDef fn _ _def = singletonF fn f C.parsec where
@@ -109,3 +112,6 @@
     removedIn _ _ x        = x
     availableSince _ _     = id
     hiddenField _          = F mempty
+
+class (C.Pretty a, C.Parsec a) => PrettyParsec a
+instance (C.Pretty a, C.Parsec a) => PrettyParsec a
diff --git a/src/CabalFmt/Fields/BuildDepends.hs b/src/CabalFmt/Fields/BuildDepends.hs
--- a/src/CabalFmt/Fields/BuildDepends.hs
+++ b/src/CabalFmt/Fields/BuildDepends.hs
@@ -2,26 +2,29 @@
 -- License: GPL-3.0-or-later
 -- Copyright: Oleg Grenrus
 {-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -Wno-deprecations #-}
 module CabalFmt.Fields.BuildDepends (
     buildDependsF,
     setupDependsF,
-    ) where
+    buildToolDependsF,
+) where
 
-import qualified Distribution.CabalSpecVersion      as C
-import qualified Distribution.Parsec                as C
-import qualified Distribution.Parsec.Newtypes       as C
-import qualified Distribution.Pretty                as C
-import qualified Distribution.Types.Dependency      as C
-import qualified Distribution.Types.DependencyMap   as C
-import qualified Distribution.Types.PackageName     as C
-import qualified Distribution.Types.Version         as C
-import qualified Distribution.Types.VersionInterval as C
-import qualified Distribution.Types.VersionRange    as C
-import qualified Text.PrettyPrint                   as PP
+import Data.List (dropWhileEnd)
 
-import CabalFmt.Prelude
+import qualified Distribution.CabalSpecVersion    as C
+import qualified Distribution.FieldGrammar        as C
+import qualified Distribution.Parsec              as C
+import qualified Distribution.Pretty              as C
+import qualified Distribution.Types.Dependency    as C
+import qualified Distribution.Types.DependencyMap as C
+import qualified Distribution.Types.ExeDependency as C
+import qualified Distribution.Types.VersionRange  as C
+import qualified Text.PrettyPrint                 as PP
+
 import CabalFmt.Fields
 import CabalFmt.Options
+import CabalFmt.Prelude
+import VersionInterval  (normaliseVersionRange, ConversionProblem (..))
 
 setupDependsF :: Options -> FieldDescrs () ()
 setupDependsF opts = singletonF "setup-depends" (pretty opts) parse
@@ -29,111 +32,122 @@
 buildDependsF :: Options -> FieldDescrs () ()
 buildDependsF opts = singletonF "build-depends" (pretty opts) parse
 
+buildToolDependsF :: Options -> FieldDescrs () ()
+buildToolDependsF opts = singletonF "build-tool-depends" (prettyExe opts) parseExe
+
 parse :: C.CabalParsing m => m [C.Dependency]
 parse = unpack' (C.alaList C.CommaVCat) <$> C.parsec
 
+parseExe :: C.CabalParsing m => m [C.ExeDependency]
+parseExe = unpack' (C.alaList C.CommaVCat) <$> C.parsec
+
+normaliseVersionRange' :: C.VersionRange -> C.VersionRange
+normaliseVersionRange' vr = either fromConversionProblem id (normaliseVersionRange vr) where
+    fromConversionProblem :: ConversionProblem -> C.VersionRange
+    fromConversionProblem IntervalsEmpty         = C.noVersion
+    fromConversionProblem OtherConversionProblem = vr
+
 pretty :: Options -> [C.Dependency] -> PP.Doc
-pretty Options { optSpecVersion = v, optTabular = tab } deps = case deps of
+pretty opts deps = case deps of
     []    -> PP.empty
     [dep] -> C.pretty (C.depPkgName dep) PP.<+> prettyVR vr'
       where
-        vr' = either (C.fromVersionIntervals . C.mkVersionIntervals) id
-            $ norm (C.asVersionIntervals $ C.depVerRange dep)
+        vr' = normaliseVersionRange' (C.depVerRange dep)
 
         prettyVR vr | vr == C.anyVersion = PP.empty
                     | vr == C.noVersion  = PP.text "<0"
                     | otherwise          = C.pretty vr
 
-    _ -> PP.vcat (zipWith pretty' (True : repeat False) deps')
+    _ -> prettyMany opts deps'
       where
-        deps' :: [(String, [C.VersionInterval])]
+        deps' :: [(String, C.VersionRange)]
         deps' = sortOn (map toLower . fst)
-              $ map (C.unPackageName . C.depPkgName &&& C.asVersionIntervals . C.depVerRange)
+              $ map (prettyDepNoVersion &&& C.depVerRange)
               $ C.fromDepMap . C.toDepMap -- this combines duplicate packages
               $ deps
 
-        width = maximum (0 : map (length . fst) deps') + 1
-        width' = maximum (0 : map (firstComponent . snd) deps')
+        prettyDepNoVersion :: C.Dependency -> String
+        prettyDepNoVersion (C.Dependency pkg _ libs) =
+          C.prettyShow (C.Dependency pkg C.anyVersion libs)
 
-        -- we assume cabal-version: 2.2 or higher
-        pretty' :: Bool -> (String, [C.VersionInterval]) -> PP.Doc
-        pretty' isFirst (name, vis)
-            | empty vis = comma PP.<+> PP.text name PP.<+> PP.text "<0"
-            | full  vis = comma PP.<+> PP.text name
-            | otherwise = case norm vis of
-                Left [] -> comma PP.<+> PP.text name
-                Left (vi : vis') ->
-                    comma PP.<+>
-                    PP.text (lp width name) PP.<+>
-                    PP.hsep
-                        ( prettyVi vi
-                        : map (\vi' -> PP.text "||" PP.<+> prettyVi' vi') vis'
-                        )
-                Right vr ->
-                    comma PP.<+>
-                    PP.text (lp width name) PP.<+>
-                    C.pretty vr
-          where
-            comma | isFirst, v < C.CabalSpecV2_2 = PP.text " "
-                  | otherwise = PP.comma
 
-        -- indent first
-        prettyVi (C.LowerBound l lb, C.NoUpperBound) =
-            prettyLowerBound lb PP.<> C.pretty l
-        prettyVi (C.LowerBound l C.InclusiveBound, C.UpperBound u C.InclusiveBound)
-            | l == u = PP.text "==" PP.<> C.pretty l
-        prettyVi (C.LowerBound l C.InclusiveBound, C.UpperBound u ub)
-            | l == C.version0
-            = prettyUpperBound ub PP.<> C.pretty u
-        prettyVi (C.LowerBound l lb, C.UpperBound u ub) =
-            prettyLowerBound lb PP.<> PP.text (lp width' l')
-            PP.<+> PP.text "&&" PP.<+>
-            prettyUpperBound ub PP.<> C.pretty u
-          where
-            l' = C.prettyShow l
+prettyExe :: Options -> [C.ExeDependency] -> PP.Doc
+prettyExe opts deps = case deps of
+    []    -> PP.empty
+    [dep] -> PP.text (exeDepExeName dep) PP.<+> prettyVR vr'
+      where
+        vr' = normaliseVersionRange' (exeDepVerRange dep)
 
-        prettyVi' (C.LowerBound l lb, C.NoUpperBound) =
-            prettyLowerBound lb PP.<> C.pretty l
-        prettyVi' (C.LowerBound l C.InclusiveBound, C.UpperBound u C.InclusiveBound)
-            | l == u = PP.text "==" PP.<> C.pretty l
-        prettyVi' (C.LowerBound l lb, C.UpperBound u ub) =
-            prettyLowerBound lb PP.<> C.pretty l PP.<+> PP.text "&&" PP.<+>
-            prettyUpperBound ub PP.<> C.pretty u
+        prettyVR vr | vr == C.anyVersion = PP.empty
+                    | vr == C.noVersion  = PP.text "<0"
+                    | otherwise          = C.pretty vr
 
-        prettyLowerBound :: C.Bound -> PP.Doc
-        prettyLowerBound C.InclusiveBound = PP.text ">="
-        prettyLowerBound C.ExclusiveBound = PP.text ">"
+    _ -> prettyMany opts deps'
+      where
+        deps' :: [(String, C.VersionRange)]
+        deps' = sortOn (map toLower . fst)
+              $ map (exeDepExeName &&& exeDepVerRange)
+              -- C.fromDepMap . C.toDepMap -- this combines duplicate packages
+              $ deps
 
-        prettyUpperBound :: C.Bound -> PP.Doc
-        prettyUpperBound C.InclusiveBound = PP.text "<="
-        prettyUpperBound C.ExclusiveBound = PP.text "<"
-  where
-    full :: [C.VersionInterval] -> Bool
-    full [(C.LowerBound l C.InclusiveBound, C.NoUpperBound)] = l == C.mkVersion [0]
-    full _                                                   = False
+exeDepExeName :: C.ExeDependency -> String
+exeDepExeName (C.ExeDependency name exe _) =
+    C.prettyShow name ++ ":" ++ C.prettyShow exe
 
-    empty :: [C.VersionInterval] -> Bool
-    empty [] = True
-    empty _  = False
+exeDepVerRange :: C.ExeDependency -> C.VersionRange
+exeDepVerRange (C.ExeDependency _ _ vr) = vr
 
-    norm :: [C.VersionInterval] -> Either [C.VersionInterval] C.VersionRange
-    norm []                                                                    = Right C.noVersion
-    norm [(C.LowerBound l C.InclusiveBound, C.NoUpperBound)] | l == C.version0 = Right C.anyVersion
-    norm (i:is) = maybe (Left $ i:is) Right $
-        foldr1 C.unionVersionRanges <$> traverse f (i : is)
+prettyMany :: Options -> [(String, C.VersionRange)] -> PP.Doc
+prettyMany Options { optSpecVersion = v, optTabular = tab } deps'
+    = PP.vcat
+    $ map PP.text
+    $ tbl
+    $ zipWith cols (True : repeat False) deps'
+  where
+    cols :: Bool -> (String, C.VersionRange) -> [String]
+    cols isFirst (name, vr)
+        | full vr'  = [comma, name]
+        | otherwise = comma : name : "" : words (C.prettyShow vr')
       where
-        f :: C.VersionInterval -> Maybe C.VersionRange
-        f (C.LowerBound l C.InclusiveBound, C.UpperBound u C.ExclusiveBound)
-            | v >= C.CabalSpecV2_0, u == C.majorUpperBound l =
-                Just (C.majorBoundVersion l)
-        f _ = Nothing
+        vr' = normaliseVersionRange' vr
 
-    firstComponent :: [C.VersionInterval] -> Int
-    firstComponent [] = 0
-    firstComponent ((C.LowerBound l _, _) : _) = length (C.prettyShow l)
+        comma | isFirst, v < C.CabalSpecV2_2 = " "
+              | otherwise                    = ","
 
-    lp | tab       = leftpad
-       | otherwise = \_ x -> x
+    full :: C.VersionRange -> Bool
+    full vr = vr == C.anyVersion
 
-leftpad :: Int -> String -> String
-leftpad w s = s ++ replicate (w - length s) ' '
+    tbl :: [[String]] -> [String]
+    tbl = if tab then table else map (concatSpaces . unwords)
+
+-- returns rows.
+table :: [[String]] -> [String]
+table cells = map strip rows
+  where
+    cols      :: Int
+    rowWidths :: [Int]
+    rows      :: [String]
+
+    (cols, rowWidths, rows) = foldr go (0, repeat 0, []) cells
+
+    go :: [String] -> (Int, [Int], [String]) -> (Int, [Int], [String])
+    go xs (c, w, yss) =
+        ( max c (length xs)
+        , zipWith max w (map length xs ++ repeat 0)
+        , unwords (take cols (zipWith fill xs rowWidths))
+          : yss
+        )
+
+    fill :: String -> Int -> String
+    fill s n = s ++ replicate (n - length s) ' '
+
+strip :: String -> String
+strip = dropWhileEnd (' ' ==)
+
+concatSpaces :: String -> String
+concatSpaces []        = []
+concatSpaces (' ' : s) = ' ' : concatSpaces s
+concatSpaces (c0 : s0)   = c0 : go s0 where
+    go (' ' : ' ' : s) = go (' ' : s)
+    go (c:s)           = c : go s
+    go []              = []
diff --git a/src/CabalFmt/Fields/Extensions.hs b/src/CabalFmt/Fields/Extensions.hs
--- a/src/CabalFmt/Fields/Extensions.hs
+++ b/src/CabalFmt/Fields/Extensions.hs
@@ -7,14 +7,14 @@
     defaultExtensionsF,
     ) where
 
-import qualified Distribution.Parsec          as C
-import qualified Distribution.Parsec.Newtypes as C
-import qualified Distribution.Pretty          as C
-import qualified Language.Haskell.Extension   as C
-import qualified Text.PrettyPrint             as PP
+import qualified Distribution.FieldGrammar  as C
+import qualified Distribution.Parsec        as C
+import qualified Distribution.Pretty        as C
+import qualified Language.Haskell.Extension as C
+import qualified Text.PrettyPrint           as PP
 
-import CabalFmt.Prelude
 import CabalFmt.Fields
+import CabalFmt.Prelude
 
 otherExtensionsF :: FieldDescrs () ()
 otherExtensionsF = singletonF "other-extensions" pretty parse
diff --git a/src/CabalFmt/Fields/Modules.hs b/src/CabalFmt/Fields/Modules.hs
--- a/src/CabalFmt/Fields/Modules.hs
+++ b/src/CabalFmt/Fields/Modules.hs
@@ -7,14 +7,14 @@
     exposedModulesF,
     ) where
 
-import qualified Distribution.ModuleName      as C
-import qualified Distribution.Parsec          as C
-import qualified Distribution.Parsec.Newtypes as C
-import qualified Distribution.Pretty          as C
-import qualified Text.PrettyPrint             as PP
+import qualified Distribution.FieldGrammar as C
+import qualified Distribution.ModuleName   as C
+import qualified Distribution.Parsec       as C
+import qualified Distribution.Pretty       as C
+import qualified Text.PrettyPrint          as PP
 
-import CabalFmt.Prelude
 import CabalFmt.Fields
+import CabalFmt.Prelude
 
 exposedModulesF :: FieldDescrs () ()
 exposedModulesF = singletonF "exposed-modules" pretty parse
diff --git a/src/CabalFmt/Fields/SourceFiles.hs b/src/CabalFmt/Fields/SourceFiles.hs
--- a/src/CabalFmt/Fields/SourceFiles.hs
+++ b/src/CabalFmt/Fields/SourceFiles.hs
@@ -7,13 +7,15 @@
     fileFields,
     ) where
 
-import System.FilePath.Posix (splitDirectories)
+-- Make sure we explicitly use Posix's splitDirectories
+-- when parsing glob syntax since only `/` is valid, and not '\\'
+import qualified System.FilePath.Posix     as Posix (splitDirectories)
 
-import qualified Distribution.Fields          as C
-import qualified Distribution.Parsec          as C
-import qualified Distribution.Parsec.Newtypes as C
-import qualified Distribution.Pretty          as C
-import qualified Text.PrettyPrint             as PP
+import qualified Distribution.FieldGrammar as C
+import qualified Distribution.Fields       as C
+import qualified Distribution.Parsec       as C
+import qualified Distribution.Pretty       as C
+import qualified Text.PrettyPrint          as PP
 
 import CabalFmt.Fields
 import CabalFmt.Prelude
@@ -46,7 +48,7 @@
 pretty
     = PP.vcat . map C.showFilePath
     . nub
-    . sortBy (cmp `on` map strToLower . splitDirectories)
+    . sortBy (cmp `on` map strToLower . Posix.splitDirectories)
   where
     cmp a b = case dropCommonPrefix a b of
         ([], [])  -> EQ
diff --git a/src/CabalFmt/Fields/TestedWith.hs b/src/CabalFmt/Fields/TestedWith.hs
--- a/src/CabalFmt/Fields/TestedWith.hs
+++ b/src/CabalFmt/Fields/TestedWith.hs
@@ -11,15 +11,15 @@
 import qualified Data.Set                      as Set
 import qualified Distribution.CabalSpecVersion as C
 import qualified Distribution.Compiler         as C
+import qualified Distribution.FieldGrammar     as C
 import qualified Distribution.Parsec           as C
-import qualified Distribution.Parsec.Newtypes  as C
 import qualified Distribution.Pretty           as C
 import qualified Distribution.Version          as C
 import qualified Text.PrettyPrint              as PP
 
-import CabalFmt.Prelude
 import CabalFmt.Fields
 import CabalFmt.Options
+import CabalFmt.Prelude
 
 testedWithF :: Options -> FieldDescrs () ()
 testedWithF Options { optSpecVersion = ver } = singletonF "tested-with" pretty parse where
@@ -56,7 +56,7 @@
 isVersionSet :: C.VersionRange -> Maybe (Set C.Version)
 isVersionSet vr = go Set.empty (C.asVersionIntervals vr) where
     go !acc [] = Just acc
-    go acc ((C.LowerBound v C.InclusiveBound, C.UpperBound u C.InclusiveBound) : vis)
+    go acc (C.VersionInterval (C.LowerBound v C.InclusiveBound) (C.UpperBound u C.InclusiveBound) : vis)
         | v == u    = go (Set.insert v acc) vis
     go _ _ = Nothing
 
diff --git a/src/CabalFmt/Glob.hs b/src/CabalFmt/Glob.hs
--- a/src/CabalFmt/Glob.hs
+++ b/src/CabalFmt/Glob.hs
@@ -1,9 +1,11 @@
 module CabalFmt.Glob where
 
-import Data.List             (isInfixOf)
-import Data.List.NonEmpty    (NonEmpty (..))
-import System.FilePath.Posix (splitDirectories)
+import Data.List          (isInfixOf)
+import Data.List.NonEmpty (NonEmpty (..))
 
+import qualified System.FilePath       as Native (splitDirectories)
+import qualified System.FilePath.Posix as Posix (splitDirectories)
+
 import CabalFmt.Prelude
 
 data Glob = Glob FilePath [GlobPiece]
@@ -27,7 +29,7 @@
 -- [False,False,True,True]
 --
 match :: Glob -> FilePath -> Bool
-match (Glob g1 gs0) fp = go0 (splitDirectories fp) where
+match (Glob g1 gs0) fp = go0 (Native.splitDirectories fp) where
     go0 []     = False
     go0 (p:ps) = if p == g1 then go ps gs0 else False
 
@@ -38,7 +40,6 @@
     go (s:ss) (GlobStarStar : gs) = go (s:ss) gs || go ss (GlobStarStar : gs)
     go (s:ss) (GlobPiece cs : gs) = matches s (toList cs) && go ss gs
 
-
     matches :: FilePath -> [GlobChar] -> Bool
     matches []     []                = True
     matches (_:_)  []                = False
@@ -47,7 +48,7 @@
     matches (x:xs) (GlobChar c : cs) = if x == c then matches xs cs else False
 
 parseGlob :: String -> Either String Glob
-parseGlob input = case splitDirectories input of
+parseGlob input = case Posix.splitDirectories input of
     []     -> Left "empty path"
     (x:xs) -> do
         p <- parseFirstPiece x
diff --git a/src/CabalFmt/Monad.hs b/src/CabalFmt/Monad.hs
--- a/src/CabalFmt/Monad.hs
+++ b/src/CabalFmt/Monad.hs
@@ -30,7 +30,7 @@
 import Data.List              (isPrefixOf, stripPrefix)
 import Data.Maybe             (mapMaybe)
 import System.Exit            (exitFailure)
-import System.FilePath        ((</>))
+import System.FilePath        (pathSeparator, (</>))
 import System.IO              (hPutStrLn, stderr)
 
 import qualified Data.ByteString  as BS
@@ -86,14 +86,17 @@
       where
         f :: FilePath -> Maybe FilePath
         f fp = do
-            rest <- stripPrefix (dir ++ "/") fp
-            return $ takeWhile (/= '/') rest
+            rest <- stripPrefix (dir ++ [pathSeparator]) fp
+            return $ takeWhile (/= pathSeparator) rest
+
     doesDirectoryExist dir = CabalFmt $ do
         files <- asks snd
-        return (any (isPrefixOf (dir ++ "/")) (Map.keys files))
+        return (any (isPrefixOf (dir ++ [pathSeparator])) (Map.keys files))
+
     readFileBS p         = CabalFmt $ do
         files <- asks snd
         return (maybe (IOError "doesn't exist") Contents $ Map.lookup p files)
+
     displayWarning w     = do
         werror <- asks optError
         if werror
diff --git a/src/CabalFmt/Prelude.hs b/src/CabalFmt/Prelude.hs
--- a/src/CabalFmt/Prelude.hs
+++ b/src/CabalFmt/Prelude.hs
@@ -15,7 +15,7 @@
     -- * Data.Either
     partitionEithers,
     -- * Data.Foldable
-    toList, traverse_, asum,
+    toList, traverse_, asum, for_,
     -- * Data.Function
     on, (&),
     -- * Data.List
@@ -51,7 +51,7 @@
 import Data.ByteString             (ByteString)
 import Data.Char                   (toLower)
 import Data.Either                 (partitionEithers)
-import Data.Foldable               (asum, toList, traverse_)
+import Data.Foldable               (asum, for_, toList, traverse_)
 import Data.Function               (on, (&))
 import Data.List                   (intercalate, nub, sortBy, sortOn)
 import Data.Maybe                  (catMaybes, fromMaybe, isJust, isNothing)
@@ -60,7 +60,7 @@
 import Distribution.Compat.Newtype (pack', unpack')
 import System.FilePath             (dropExtension, splitDirectories)
 
-import qualified Distribution.Simple.Utils as C
+import qualified Distribution.Utils.Generic as C
 
 traverseOf
     :: Applicative f
diff --git a/src/CabalFmt/Refactoring/ExpandExposedModules.hs b/src/CabalFmt/Refactoring/ExpandExposedModules.hs
--- a/src/CabalFmt/Refactoring/ExpandExposedModules.hs
+++ b/src/CabalFmt/Refactoring/ExpandExposedModules.hs
@@ -3,6 +3,7 @@
 -- Copyright: Oleg Grenrus
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RankNTypes        #-}
+{-# OPTIONS_GHC -Wno-deprecations #-}
 module CabalFmt.Refactoring.ExpandExposedModules (
     refactoringExpandExposedModules,
     ) where
@@ -28,7 +29,7 @@
             , file <- files'
             , let parts = splitDirectories $ dropExtension file
             , all C.validModuleComponent parts
-            , let mn = C.fromComponents parts
+            , let mn = C.fromComponents parts -- TODO: don't use fromComponents
             , mn `notElem` mns
             ]
 
diff --git a/src/CabalFmt/Refactoring/Fragments.hs b/src/CabalFmt/Refactoring/Fragments.hs
--- a/src/CabalFmt/Refactoring/Fragments.hs
+++ b/src/CabalFmt/Refactoring/Fragments.hs
@@ -44,7 +44,7 @@
                         displayWarning $ "Fragment " ++ p ++ " contains a section " ++ showSection name arg ++ ", expecting field " ++ show n ++ "."
                         pure Nothing
                     (C.Section name@(C.Name _ _) arg _, C.Field (C.Name _ n') _ : _) -> do
-                        displayWarning $ "Fragment " ++ p ++ " contains a field " ++ show n' ++ ", expection section " ++ showSection name arg ++ "."
+                        displayWarning $ "Fragment " ++ p ++ " contains a field " ++ show n' ++ ", expecting section " ++ showSection name arg ++ "."
                         pure Nothing
 
                     (C.Field name@(C.Name _ n) _, C.Field (C.Name _ n') fls' : rest) -> do
@@ -66,7 +66,7 @@
                         then do
                             pure (Just (C.Section name arg (noCommentsPragmas fs')))
                         else do
-                            displayWarning $ "Fragment " ++ p ++ " contains a section " ++ showSection name arg ++ ", expection section " ++ showSection name' arg' ++ "."
+                            displayWarning $ "Fragment " ++ p ++ " contains a section " ++ showSection name arg ++ ", expecting section " ++ showSection name' arg' ++ "."
                             pure Nothing
   where
     noCommentsPragmas :: Functor f => [f ann] -> [f CommentsPragmas]
diff --git a/src/CabalFmt/Refactoring/GlobFiles.hs b/src/CabalFmt/Refactoring/GlobFiles.hs
--- a/src/CabalFmt/Refactoring/GlobFiles.hs
+++ b/src/CabalFmt/Refactoring/GlobFiles.hs
@@ -7,12 +7,14 @@
     refactoringGlobFiles,
 ) where
 
-import qualified Distribution.Fields     as C
+import qualified Distribution.Fields   as C
+import qualified System.FilePath       as Native
+import qualified System.FilePath.Posix as Posix
 
-import CabalFmt.Prelude
-import CabalFmt.Monad
 import CabalFmt.Glob
+import CabalFmt.Monad
 import CabalFmt.Pragma
+import CabalFmt.Prelude
 import CabalFmt.Refactoring.Type
 
 refactoringGlobFiles :: FieldRefactoring
@@ -41,5 +43,8 @@
 
     match' :: MonadCabalFmt r m => Glob -> m [FilePath]
     match' g@(Glob dir _) = do
-        files <- map (\fp -> dir ++ "/" ++ fp) <$> getFiles dir 
-        return $ filter (match g) files
+        files <- map (\fp -> dir Native.</> fp) <$> getFiles dir
+        return $ map toPosix $ filter (match g) files
+
+    toPosix :: FilePath -> FilePath
+    toPosix = Posix.joinPath . Native.splitDirectories
diff --git a/tests-interval/version-interval-tests.hs b/tests-interval/version-interval-tests.hs
new file mode 100644
--- /dev/null
+++ b/tests-interval/version-interval-tests.hs
@@ -0,0 +1,367 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+module Main (main) where
+
+import Control.Monad                   (replicateM)
+import Distribution.Parsec             (eitherParsec)
+import Distribution.Types.Version
+       (Version, mkVersion, validVersion, versionNumbers)
+import Distribution.Types.VersionRange
+       (VersionRange, VersionRangeF (..), anyVersion, earlierVersion,
+       intersectVersionRanges, laterVersion, majorBoundVersion, notThisVersion,
+       orEarlierVersion, orLaterVersion, projectVersionRange, thisVersion,
+       unionVersionRanges, withinRange, withinVersion)
+import Distribution.Version            (transformCaretUpper)
+import Math.NumberTheory.Logarithms    (intLog2)
+import Test.QuickCheck                 (Arbitrary (..), (===))
+import Test.Tasty                      (TestTree, defaultMain, testGroup)
+import Test.Tasty.HUnit                (testCase, (@?=))
+import Test.Tasty.QuickCheck           (testProperty)
+
+import qualified Test.QuickCheck as QC
+
+import VersionInterval
+
+main :: IO ()
+main = defaultMain $ testGroup "version-interval"
+    [ testGroup "Validity"
+        [ testProperty "validVersion" validVersion
+        , testProperty "validVersionInterval" validVersionInterval
+        , testProperty "validVersionIntervals" $ \vr ->
+            let intervals = toVersionIntervals vr
+            in QC.counterexample (show intervals) $ validVersionIntervals intervals
+        ]
+
+    , testGroup "VersionInterval"
+        [ testProperty "intersect valid" $ \a b ->
+            let ab = intersectInterval a b
+            in maybe (QC.property True) (\ab' -> QC.counterexample ("intersection: " ++ show ab') $ validVersionInterval ab') ab
+
+        , testProperty "intersect complete" intersect_complete
+        , testProperty "intersect complete lax" intersect_complete_lax
+        ]
+
+    , testGroup "stage1"
+        [ testProperty "valid" stage1_valid
+        , testProperty "complete" stage1_complete
+        , testProperty "complete lax" stage1_complete_lax
+
+        , testProperty "valid ex1" $ stage1_valid
+            (intersectVersionRanges (majorBoundVersion (mkVersion [0])) (thisVersion (mkVersion [1])))
+
+        , testProperty "valid ex2" $ stage1_valid
+            (intersectVersionRanges (majorBoundVersion (mkVersion [0])) (orLaterVersion (mkVersion [1])))
+
+        , testProperty "complete ex1" $ stage1_complete
+            (intersectVersionRanges (majorBoundVersion (mkVersion [0])) (thisVersion (mkVersion [6])))
+            (mkVersion [6])
+
+        , testProperty "complete ex2" $ stage1_complete
+            (intersectVersionRanges (majorBoundVersion (mkVersion [0])) (orLaterVersion (mkVersion [1])))
+
+        , testProperty "complete lax ex2" $ stage1_complete_lax
+            (intersectVersionRanges (majorBoundVersion (mkVersion [0])) (orLaterVersion (mkVersion [1])))
+        ]
+
+    , testGroup "stage2"
+        [ testProperty "valid" stage2_valid
+        , testProperty "involutive" stage2_involutive
+        , testProperty "complete" stage2_complete
+        , testProperty "complete_lax" stage2_complete_lax
+        ]
+
+    , testGroup "stage3"
+        [ testProperty "valid" stage3_valid
+        , testProperty "involutive" stage3_involutive
+        , testProperty "complete" stage3_complete
+        , testProperty "complete_lax" stage3_complete_lax
+
+        , testProperty "complete ex1" $ stage3_complete
+           [VI (LB (mkVersion [0])) (MB (mkVersion [0])) NoUB,VI (LB (mkVersion [0,0])) NoMB NoUB]
+           (mkVersion [0])
+
+        , testProperty "complete lax ex1" $ stage3_complete_lax
+            [VI (LB (mkVersion [0,0])) (MB (mkVersion [0])) (UB (mkVersion [1])),VI (LB (mkVersion [0,0,0])) (MB (mkVersion [1])) (UB (mkVersion [1]))]
+            (mkVersion [1])
+
+        , testProperty "valid ex2" $ stage3_valid
+            (stage1 id (intersectVersionRanges (majorBoundVersion (mkVersion [0])) (orLaterVersion (mkVersion [1]))))
+
+        , testProperty "complete ex2" $ stage3_complete
+            (stage1 id (intersectVersionRanges (majorBoundVersion (mkVersion [0])) (orLaterVersion (mkVersion [1]))))
+
+        , testProperty "complete lax ex2" $ stage3_complete_lax
+            (stage1 id (intersectVersionRanges (majorBoundVersion (mkVersion [0])) (orLaterVersion (mkVersion [1]))))
+
+        , testProperty "valid ex3" $ stage3_valid
+            [VI (LB (mkVersion [0,0])) (MB (mkVersion [0])) NoUB,VI (LB (mkVersion [0,0])) NoMB NoUB]
+        ]
+
+    , testGroup "normalise"
+        [ normaliseExample ">=1 && <2"                               ">=1 && <2"
+        , normaliseExample "^>=1"                                    "^>=1"
+        , normaliseExample "^>=1 || ^>=2"                            "^>=1 || ^>=2"
+        , normaliseExample "^>=1.2 || ^>=1.3 || ^>=1.4"              ">=1.2 && <1.4 || ^>=1.4"
+        , normaliseExample "^>=1.2 || ^>=2.0"                        "^>=1.2 || ^>=2.0"
+        , normaliseExample ">=1.2 && <1.4 || ^>=1.4 || ^>=1.5"       ">=1.2 && <1.5 || ^>=1.5"
+        , normaliseExample ">=1.2 && <2.4 || ^>=2.4 || ^>=2.5"       ">=1.2 && <2.5 || ^>=2.5"
+        , normaliseExample "^>=1.2.0.0 || ^>=1.3.0.0 || ^>=1.4.0.0"  "^>=1.2.0.0 || ^>=1.3.0.0 || ^>=1.4.0.0"
+
+        , normaliseExample "==3.1.4"           "==3.1.4"
+        , normaliseExample "<3.1.4 || >3.1.4"  "<3.1.4 || >=3.1.4.0"
+
+        , normaliseExample "^>=1.2 && <2.0 || ^>=2.0"                "^>=1.2 || ^>=2.0"
+        , normaliseExample "^>=1.2 && <3.0 || ^>=2.0"                "^>=1.2 || ^>=2.0"
+        , normaliseExample "^>=1.2 || ^>=2.0 && <3"                  "^>=1.2 || ^>=2.0"
+        , normaliseExample "(^>=1.2 || ^>=2.0) && <3"                "^>=1.2 && <2.0 || ^>=2.0 && <3"
+        , normaliseExample "(>=1.2 || >=2.0) && <3"                  ">=1.2 && <3"
+
+        , normaliseExample "<1 || >=1.0"   "<1 || >=1.0"
+        , normaliseExample "<=1 || >=1.0"  ">=0"
+        , normaliseExample ">0 && <0.0"    "<0"
+
+        , normaliseExample "^>=1.5.0.1 || ^>=1.6.0.1 || >=1.9 && <1.13"
+                           "^>=1.5.0.1 || ^>=1.6.0.1 || >=1.9 && <1.12 || ^>=1.12"
+
+        , cannotNormaliseExample "^>=0 && >=0.1" IntervalsEmpty
+
+        , testProperty "involutive"   normalise_involutive
+
+        , testProperty "complete"     normalise_complete
+        , testProperty "complete_lax" normalise_complete_lax
+
+        , testProperty "involutive ex1" $ normalise_involutive $
+            intersectVersionRanges (majorBoundVersion (mkVersion [3])) (laterVersion (mkVersion [3]))
+        ]
+    ]
+
+normaliseExample :: String -> String -> TestTree
+normaliseExample input expected = testCase input $ do
+    input'   <- either fail return $ eitherParsec input
+    expected' <- either fail return $ eitherParsec expected
+
+    VersionInterval.normaliseVersionRange input' @?= Right expected'
+
+cannotNormaliseExample :: String -> ConversionProblem -> TestTree
+cannotNormaliseExample input problem = testCase ("cannot " ++ input) $ do
+    input'   <- either fail return $ eitherParsec input
+
+    VersionInterval.normaliseVersionRange input' @?= Left problem
+
+-------------------------------------------------------------------------------
+-- Intersect
+-------------------------------------------------------------------------------
+
+intersect_complete :: VersionInterval -> VersionInterval -> Version -> QC.Property
+intersect_complete a b v =
+    QC.counterexample ("intersection: " ++ show (ab, inA, inB)) $ (inA && inB) === inAB
+  where
+    ab   = intersectInterval a b
+    inA  = withinInterval v a
+    inB  = withinInterval v b
+    inAB = maybe False (withinInterval v) ab
+
+intersect_complete_lax :: VersionInterval -> VersionInterval -> Version -> QC.Property
+intersect_complete_lax a b v =
+    QC.counterexample ("intersection: " ++ show (ab, inA, inB)) $ (inA && inB) === inAB
+  where
+    ab   = intersectInterval a b
+    inA  = withinIntervalLax v a
+    inB  = withinIntervalLax v b
+    inAB = maybe False (withinIntervalLax v) ab
+
+-------------------------------------------------------------------------------
+-- Stage 1
+-------------------------------------------------------------------------------
+
+stage1_valid :: VersionRange -> QC.Property
+stage1_valid vr = QC.counterexample ("stage1: " ++ show is) $ QC.property $ all validVersionInterval is
+  where
+    is = stage1 id vr
+
+stage1_complete :: VersionRange -> Version -> QC.Property
+stage1_complete vr v = QC.counterexample ("stage1: " ++ show is) $ withinRange v vr === any (withinInterval v) is
+  where
+    is = stage1 id vr
+
+stage1_complete_lax :: VersionRange -> Version -> QC.Property
+stage1_complete_lax vr v = QC.counterexample ("stage1: " ++ show is) $ withinRangeLax v vr === any (withinIntervalLax v) is
+  where
+    is = stage1 id vr
+
+-------------------------------------------------------------------------------
+-- Stage 2
+-------------------------------------------------------------------------------
+
+stage2_valid :: [VersionInterval] -> QC.Property
+stage2_valid is' = QC.counterexample ("stage2: " ++ show is) $ QC.property $ all validVersionInterval is
+  where
+    is = stage2 is'
+
+stage2_involutive :: [VersionInterval] -> QC.Property
+stage2_involutive is' = is1 === is2
+  where
+    is1 = stage2 is'
+    is2 = stage2 is1
+
+stage2_complete :: [VersionInterval] -> Version -> QC.Property
+stage2_complete is' v = QC.counterexample ("stage2: " ++ show is) $ any (withinInterval v) is' === any (withinInterval v) is
+  where
+    is = stage2 is'
+
+stage2_complete_lax :: [VersionInterval] -> Version -> QC.Property
+stage2_complete_lax is' v = QC.counterexample ("stage2: " ++ show is) $ any (withinIntervalLax v) is' === any (withinIntervalLax v) is
+  where
+    is = stage2 is'
+
+-------------------------------------------------------------------------------
+-- Stage 3
+-------------------------------------------------------------------------------
+
+stage3_valid :: [VersionInterval] -> QC.Property
+stage3_valid is' = QC.counterexample ("stage3: " ++ show is) $ QC.property $ all validVersionInterval is
+  where
+    is = stage3 (stage2 is')
+
+stage3_involutive :: [VersionInterval] -> QC.Property
+stage3_involutive is' = is1 === is2
+  where
+    is1 = stage3 (stage2 is')
+    is2 = stage3 is1
+
+stage3_complete :: [VersionInterval] -> Version -> QC.Property
+stage3_complete is' v = QC.counterexample ("stage3: " ++ show is) $ any (withinInterval v) is' === any (withinInterval v) is
+  where
+    is = stage3 (stage2 is')
+
+stage3_complete_lax :: [VersionInterval] -> Version -> QC.Property
+stage3_complete_lax is' v = QC.counterexample ("stage3: " ++ show is) $ any (withinIntervalLax v) is' === any (withinIntervalLax v) is
+  where
+    is = stage3 (stage2 is')
+
+-------------------------------------------------------------------------------
+-- Normalise
+-------------------------------------------------------------------------------
+
+normalise_involutive :: VersionRange -> QC.Property
+normalise_involutive vr = vr1 === vr2 where
+    vr1 = VersionInterval.normaliseVersionRange vr
+    vr2 = VersionInterval.normaliseVersionRange =<< vr1
+
+normalise_complete :: VersionRange -> Version -> QC.Property
+normalise_complete vr v = case VersionInterval.normaliseVersionRange vr of
+    Left _    -> QC.property True
+    Right vr' -> QC.counterexample ("normalised: " ++ show vr') $ withinRange v vr === withinRange v vr'
+
+normalise_complete_lax :: VersionRange -> Version -> QC.Property
+normalise_complete_lax vr v = case VersionInterval.normaliseVersionRange vr of
+    Left _    -> QC.property True
+    Right vr' -> QC.counterexample ("normalised: " ++ show vr') $ withinRangeLax v vr === withinRangeLax v vr'
+
+-------------------------------------------------------------------------------
+-- Predicates
+-------------------------------------------------------------------------------
+
+withinInterval :: Version -> VersionInterval -> Bool
+withinInterval v (VI l m u) = viGreater l && viLessM m && viLess u where
+    viGreater (LB v') = v >= v'
+
+    viLessM NoMB    = True
+    viLessM (MB v') = v < v'
+
+    viLess NoUB    = True
+    viLess (UB v') = v < v'
+
+withinIntervalLax :: Version -> VersionInterval -> Bool
+withinIntervalLax v (VI l _ u) = viGreater l && viLess u where
+    viGreater (LB v') = v >= v'
+
+    viLess NoUB    = True
+    viLess (UB v') = v < v'
+
+withinRangeLax :: Version -> VersionRange -> Bool
+withinRangeLax v vr = withinRange v (transformCaretUpper vr)
+
+-------------------------------------------------------------------------------
+-- QC instances
+-------------------------------------------------------------------------------
+
+instance Arbitrary Version where
+    arbitrary = QC.oneof
+        [ mkVersion <$> replicateM d vDigit
+        | d <- [1..4]
+        ]
+      where
+        vDigit :: QC.Gen Int
+        vDigit = QC.elements [0..9]
+
+    shrink v =
+        [ mkVersion v'
+        | v' <- shrink (versionNumbers v)
+        , not (null v')
+        ]
+
+instance Arbitrary VersionRange where
+    arbitrary = QC.sized $ \n -> genVersionRange (intLog2 (max 1 n))
+
+    shrink vr = case projectVersionRange vr of
+        LaterVersionF v -> laterVersion <$> shrink v
+        OrLaterVersionF v -> orLaterVersion <$> shrink v
+        EarlierVersionF v -> earlierVersion <$> shrink v
+        OrEarlierVersionF v -> orEarlierVersion <$> shrink v
+        ThisVersionF v -> thisVersion <$> shrink v
+        MajorBoundVersionF v -> majorBoundVersion <$> shrink v
+        UnionVersionRangesF l r -> l : r : fmap (uncurry unionVersionRanges) (shrink (l, r))
+        IntersectVersionRangesF l r -> l : r : fmap (uncurry intersectVersionRanges) (shrink (l, r))
+
+genVersionRange :: Int -> QC.Gen VersionRange
+genVersionRange n
+    | n <= 1 = QC.oneof
+        [ pure anyVersion
+        , thisVersion <$> arbitrary
+        , notThisVersion <$> arbitrary
+        , laterVersion <$> arbitrary
+        , earlierVersion <$> arbitrary
+        , orLaterVersion <$> arbitrary
+        , orEarlierVersion <$> arbitrary
+        , withinVersion  <$> arbitrary
+        , majorBoundVersion <$> arbitrary
+        ]
+    | otherwise = do
+        l <- QC.chooseInt (1, n - 1)
+        let r = n - l
+        QC.oneof
+            [ unionVersionRanges <$> genVersionRange l <*> genVersionRange r
+            , intersectVersionRanges <$> genVersionRange l <*> genVersionRange r
+            ]
+
+instance Arbitrary VersionInterval where
+    arbitrary = QC.suchThat (VI <$> arbitrary <*> arbitrary <*> arbitrary) validVersionInterval
+
+    shrink (VI l m u) =
+        [ vi
+        | (l', m', u') <- shrink (l, m, u)
+        , let vi = VI l' m' u'
+        , validVersionInterval vi
+        ]
+
+instance Arbitrary LB where
+    arbitrary = LB <$> arbitrary
+    shrink (LB v) = LB <$> shrink v
+
+instance Arbitrary UB where
+    arbitrary = QC.oneof
+        [ pure NoUB
+        , UB <$> arbitrary
+        ]
+
+    shrink NoUB     = []
+    shrink (UB v) = NoUB : map UB (shrink v)
+
+instance Arbitrary MB where
+    arbitrary = QC.oneof
+        [ pure NoMB
+        , MB <$> arbitrary
+        ]
+
+    shrink NoMB     = []
+    shrink (MB v) = NoMB : map MB (shrink v)
diff --git a/tests/Golden.hs b/tests/Golden.hs
--- a/tests/Golden.hs
+++ b/tests/Golden.hs
@@ -1,6 +1,8 @@
 module Main (main) where
 
 import System.FilePath            ((-<.>), (</>))
+import System.IO                  (hClose, hFlush)
+import System.IO.Temp             (withSystemTempFile)
 import System.Process             (readProcessWithExitCode)
 import Test.Tasty                 (TestTree, defaultMain, testGroup)
 import Test.Tasty.Golden.Advanced (goldenTest)
@@ -10,15 +12,17 @@
 import qualified Data.Map              as Map
 
 import CabalFmt         (cabalFmt)
-import CabalFmt.Prelude
 import CabalFmt.Monad   (runCabalFmt)
 import CabalFmt.Options (defaultOptions)
+import CabalFmt.Prelude
 
 main :: IO ()
 main = defaultMain $ testGroup "tests"
     [ goldenTest' "cabal-fmt"
     , goldenTest' "Cabal"
+    , goldenTest' "Cabal-notab"
     , goldenTest' "simple-example"
+    , goldenTest' "tree-diff"
 
     , goldenTest' "fragment-missing"
     , goldenTest' "fragment-empty"
@@ -50,8 +54,23 @@
                         return (toUTF8BS $ unlines (map ("-- " ++) ws) ++ output')
 
     cmp a b | a == b    = return Nothing
-            | otherwise = Just <$> readProcess' "diff" ["-u", goldenPath, "-"] (fromUTF8BS b)
+            | otherwise =
+        withSystemTempFile "cabal-fmt-test.txt" $ \fpA hdlA ->
+        withSystemTempFile "cabal-fmt-test.txt" $ \fpB hdlB -> do
+            BS.hPutStr hdlA a
+            BS.hPutStr hdlB b
+            hFlush hdlA
+            hFlush hdlB
+            hClose hdlA
+            hClose hdlB
 
+            Just . postProcess <$> readProcess' "diff" ["-u", fpA, fpB] ""
+
+    postProcess :: String -> String
+    postProcess = unlines . (["======"] ++) . map (concatMap char) . (++ ["======"]). lines where
+        char '\r' = "{CR}"
+        char c    = [c]
+
     readProcess' proc args input = do
         (_, out, _) <- readProcessWithExitCode proc args input
         return out
@@ -72,10 +91,10 @@
     , p "multiple.fragment"
         "build-depends: base\nghc-options: -Wall"
 
-    , p "cbits/header.h" "..."
-    , p "cbits/source1.c" "..."
-    , p "cbits/source2.c" "..."
-    , p "cbits/sub/source3.c" "..."
+    , p ("cbits" </> "header.h") "..."
+    , p ("cbits" </> "source1.c") "..."
+    , p ("cbits" </> "source2.c") "..."
+    , p ("cbits" </> "sub" </> "source3.c") "..."
     ]
   where
     p x y = (x, BS8.pack y)
