auto-import 📥
A GHC plugin that automatically adds import statements to the module being compiled.
Usage
This plugin is intended to be used with GHCi or adjacent utilities such as
ghcid and ghciwatch as a developement tool, not as a package dependency.
You must first define a config file that specifies which modules are eligible
to be automatically imported. By default this file is named .autoimport and
can be placed in the home directory and/or in the root directory of your
Haskell project. If the file is found in both locations, the configs will be
merged with the local file taking precedence. The local file path can be overriden
by passing this plugin option to GHC: fplugin-opt=AutoImport:--import-cfg=path/to/file.
Here is an example .autoimport file:
Data.Text as T
Data.Text.IO as TIO
Data.Map (Map)
Data.Map as Map
Data.Maybe (fromMaybe, isJust, isNothing)
Data.Functor.Identity (Identity(runIdentity))
UnliftIO
There are two ways of specifying modules that should be automatically imported:
with a qualifier or with a list of identifiers.
Modules are identified by a qualifier if there is no list of identifiers
following the module name, along with an optional explicit qualifier using
as. If no explicit qualifier is given then the full module name is used as
the qualifier (such as UnliftIO in the example). Qualified imports will be
added for these modules whenever the qualifier is used in a module where it
does not correspond to an existing import.
If a list of identifiers is given then that module will be imported unqualified
with an explicit import list (or added to an existing import if the module is
already imported) when one of the given identifiers is used in a context where
it does not have a definition in scope. Note: wildcards for type and class
subterms is not supported, i.e. Identity(..) is not allowed in the config.
With the plugin enabled and the example config in scope, compiling the
following module:
tryReadFile :: FilePath -> IO (Either UnliftIO.IOException T.Text)
tryReadFile = UnliftIO.catchIO . TIO.readFile
defaultToZero :: Maybe Int -> Int
defaultToZero = fromMaybe 0
Results in the module file being automatically updated to:
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import qualified UnliftIO
import Data.Maybe (fromMaybe)
tryReadFile :: FilePath -> IO (Either UnliftIO.IOException T.Text)
tryReadFile = UnliftIO.tryIO . TIO.readFile
defaultToZero :: Maybe Int -> Int
defaultToZero = fromMaybe 0
(Note: the above would actually need to be compiled twice because GHC does not
emit the 'missing qualifier' and 'out of scope variable' errors together. The
missing qualifier errors occur first.)
The plugin works by intercepting GHC errors indicating that a qualifier or
identifier is not defined, and if it matches a line from the config, then the
corresponding import statement is inserted. Compilation is aborted when this
occurs.
Here is an example command for starting a REPL for a stack project with the
auto-import plugin enabled (you may need to add auto-import to your
extra-deps first):
stack repl my-project --package auto-import --ghci-options='-fplugin AutoSplit'
likewise for a cabal project (you may need to run cabal update first):
cabal repl my-project --build-depends auto-import --repl-options='-fplugin AutoSplit'
This plugin aims to support the four most recent major GHC releases.