diff --git a/hls-refactor-plugin.cabal b/hls-refactor-plugin.cabal
--- a/hls-refactor-plugin.cabal
+++ b/hls-refactor-plugin.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               hls-refactor-plugin
-version:            1.0.0.0
+version:            1.1.0.0
 synopsis:           Exactprint refactorings for Haskell Language Server
 description:
   Please see the README on GitHub at <https://github.com/haskell/haskell-language-server#readme>
@@ -17,11 +17,11 @@
   test/data/**/*.hs
   test/data/**/*.yaml
 
+source-repository head
+    type:     git
+    location: https://github.com/haskell/haskell-language-server.git
+
 library
-  if impl(ghc >= 9.3)
-    buildable: False
-  else
-    buildable: True
   exposed-modules:  Development.IDE.GHC.ExactPrint
                     Development.IDE.GHC.Compat.ExactPrint
                     Development.IDE.Plugin.CodeAction
@@ -30,6 +30,11 @@
   other-modules:    Development.IDE.Plugin.CodeAction.Args
                     Development.IDE.Plugin.CodeAction.ExactPrint
                     Development.IDE.Plugin.CodeAction.PositionIndexed
+                    Development.IDE.Plugin.Plugins.AddArgument
+                    Development.IDE.Plugin.Plugins.Diagnostic
+                    Development.IDE.Plugin.Plugins.FillHole
+                    Development.IDE.Plugin.Plugins.FillTypeWildcard
+                    Development.IDE.Plugin.Plugins.ImportUtils
   default-extensions:
     BangPatterns
     CPP
@@ -63,8 +68,8 @@
     , ghc-boot
     , regex-tdfa
     , text-rope
-    , ghcide                ^>=1.8
-    , hls-plugin-api        ^>=1.3 || ^>=1.4 || ^>= 1.5
+    , ghcide                ^>=1.9
+    , hls-plugin-api        ^>=1.6
     , lsp
     , text
     , transformers
@@ -85,20 +90,17 @@
   default-language: Haskell2010
 
 test-suite tests
-  if impl(ghc >= 9.3)
-    buildable: False
-  else
-    buildable: True
   type:             exitcode-stdio-1.0
   default-language: Haskell2010
   hs-source-dirs:   test
   main-is:          Main.hs
+  other-modules:    Test.AddArgument
   ghc-options:      -O0 -threaded -rtsopts -with-rtsopts=-N -Wunused-imports
   build-depends:
     , base
     , filepath
     , hls-refactor-plugin
-    , hls-test-utils      ^>=1.4
+    , hls-test-utils      ^>=1.5
     , lens
     , lsp-types
     , text
@@ -109,6 +111,8 @@
     , extra
     , text-rope
     , containers
+    -- ghc is included to enable the MIN_VERSION_ghc macro
+    , ghc
     , ghcide
     , ghcide-test-utils
     , shake
diff --git a/src/Development/IDE/GHC/Compat/ExactPrint.hs b/src/Development/IDE/GHC/Compat/ExactPrint.hs
--- a/src/Development/IDE/GHC/Compat/ExactPrint.hs
+++ b/src/Development/IDE/GHC/Compat/ExactPrint.hs
@@ -2,9 +2,6 @@
 --   multiple ghc-exactprint versions, accepting that anything more ambitious is
 --   pretty much impossible with the GHC 9.2 redesign of ghc-exactprint
 module Development.IDE.GHC.Compat.ExactPrint
-#if MIN_VERSION_ghc(9,3,0)
-    ( ) where
-#else
     ( ExactPrint
     , exactPrint
     , makeDeltaAst
@@ -33,6 +30,4 @@
 #else
 pattern Annotated :: ast -> ApiAnns -> Retrie.Annotated ast
 pattern Annotated {astA, annsA} <- ((,()) . Retrie.astA -> (astA, annsA))
-#endif
-
 #endif
diff --git a/src/Development/IDE/GHC/Dump.hs b/src/Development/IDE/GHC/Dump.hs
--- a/src/Development/IDE/GHC/Dump.hs
+++ b/src/Development/IDE/GHC/Dump.hs
@@ -1,25 +1,22 @@
 {-# LANGUAGE CPP #-}
 module Development.IDE.GHC.Dump(showAstDataHtml) where
-import           Data.Data                       hiding (Fixity)
-import           Development.IDE.GHC.Compat      hiding (NameAnn)
+import           Data.Data                             hiding (Fixity)
+import           Development.IDE.GHC.Compat            hiding (LocatedA,
+                                                        NameAnn)
 import           Development.IDE.GHC.Compat.ExactPrint
-#if MIN_VERSION_ghc(8,10,1)
 import           GHC.Hs.Dump
-#else
-import           HsDumpAst
-#endif
 #if MIN_VERSION_ghc(9,2,1)
-import qualified Data.ByteString                 as B
+import qualified Data.ByteString                       as B
 import           Development.IDE.GHC.Compat.Util
-import           Generics.SYB                    (ext1Q, ext2Q, extQ)
-import           GHC.Hs
+import           Generics.SYB                          (ext1Q, ext2Q, extQ)
+import           GHC.Hs                                hiding (AnnLet)
 #endif
 #if MIN_VERSION_ghc(9,0,1)
-import           GHC.Plugins
+import           GHC.Plugins                           hiding (AnnLet)
 #else
 import           GhcPlugins
 #endif
-import           Prelude                         hiding ((<>))
+import           Prelude                               hiding ((<>))
 
 -- | Show a GHC syntax tree in HTML.
 #if MIN_VERSION_ghc(9,2,1)
@@ -235,8 +232,13 @@
             annotationEpAnnHsCase :: EpAnn EpAnnHsCase -> SDoc
             annotationEpAnnHsCase = annotation' (text "EpAnn EpAnnHsCase")
 
+#if MIN_VERSION_ghc(9,4,0)
+            annotationEpAnnHsLet :: EpAnn NoEpAnns -> SDoc
+            annotationEpAnnHsLet = annotation' (text "EpAnn NoEpAnns")
+#else
             annotationEpAnnHsLet :: EpAnn AnnsLet -> SDoc
             annotationEpAnnHsLet = annotation' (text "EpAnn AnnsLet")
+#endif
 
             annotationAnnList :: EpAnn AnnList -> SDoc
             annotationAnnList = annotation' (text "EpAnn AnnList")
diff --git a/src/Development/IDE/GHC/ExactPrint.hs b/src/Development/IDE/GHC/ExactPrint.hs
--- a/src/Development/IDE/GHC/ExactPrint.hs
+++ b/src/Development/IDE/GHC/ExactPrint.hs
@@ -3,9 +3,6 @@
 
 -- | This module hosts various abstractions and utility functions to work with ghc-exactprint.
 module Development.IDE.GHC.ExactPrint
-#if MIN_VERSION_ghc(9,3,0)
-   (  ) where
-#else
     ( Graft(..),
       graftDecls,
       graftDeclsWithM,
@@ -20,11 +17,19 @@
       transform,
       transformM,
       ExactPrint(..),
+#if MIN_VERSION_ghc(9,2,1)
+      modifySmallestDeclWithM,
+      modifyMgMatchesT,
+      modifyMgMatchesT',
+      modifySigWithM,
+      genAnchor1,
+#endif
 #if !MIN_VERSION_ghc(9,2,0)
       Anns,
       Annotate,
       setPrecedingLinesT,
 #else
+      setPrecedingLines,
       addParens,
       addParensToCtxt,
       modifyAnns,
@@ -56,6 +61,7 @@
 import           Control.Monad.Zip
 import           Data.Bifunctor
 import           Data.Bool                               (bool)
+import           Data.Default                            (Default)
 import qualified Data.DList                              as DL
 import           Data.Either.Extra                       (mapLeft)
 import           Data.Foldable                           (Foldable (fold))
@@ -86,11 +92,14 @@
 import           Language.Haskell.GHC.ExactPrint.Parsers
 import           Language.LSP.Types
 import           Language.LSP.Types.Capabilities         (ClientCapabilities)
-import           Retrie.ExactPrint                       hiding (Annotated (..),
-                                                          parseDecl, parseExpr,
+import           Retrie.ExactPrint                       hiding (parseDecl,
+                                                          parseExpr,
                                                           parsePattern,
                                                           parseType)
-#if MIN_VERSION_ghc(9,2,0)
+#if MIN_VERSION_ghc(9,9,0)
+import           GHC.Plugins                             (showSDoc)
+import           GHC.Utils.Outputable                    (Outputable (ppr))
+#elif MIN_VERSION_ghc(9,2,0)
 import           GHC                                     (EpAnn (..),
                                                           NameAdornment (NameParens),
                                                           NameAnn (..),
@@ -101,9 +110,22 @@
                                                           spanAsAnchor)
 import           GHC.Parser.Annotation                   (AnnContext (..),
                                                           DeltaPos (SameLine),
-                                                          EpaLocation (EpaDelta))
+                                                          EpaLocation (EpaDelta),
+                                                          deltaPos)
 #endif
 
+#if MIN_VERSION_ghc(9,2,1)
+import Data.List (partition)
+import GHC (Anchor(..), realSrcSpan, AnchorOperation, DeltaPos(..), SrcSpanAnnN)
+import GHC.Types.SrcLoc (generatedSrcSpan)
+import Control.Lens ((&), _last)
+import Control.Lens.Operators ((%~))
+#endif
+
+#if MIN_VERSION_ghc(9,2,0)
+setPrecedingLines :: Default t => LocatedAn t a -> Int -> Int -> LocatedAn t a
+setPrecedingLines ast n c = setEntryDP ast (deltaPos n c)
+#endif
 ------------------------------------------------------------------------------
 
 data Log = LogShake Shake.Log deriving Show
@@ -114,10 +136,10 @@
 
 instance Show (Annotated ParsedSource) where
   show _ = "<Annotated ParsedSource>"
- 
+
 instance NFData (Annotated ParsedSource) where
   rnf = rwhnf
- 
+
 data GetAnnotatedParsedSource = GetAnnotatedParsedSource
   deriving (Eq, Show, Typeable, GHC.Generic)
 
@@ -307,7 +329,7 @@
 getNeedsSpaceAndParenthesize dst a =
   -- Traverse the tree, looking for our replacement node. But keep track of
   -- the context (parent HsExpr constructor) we're in while we do it. This
-  -- lets us determine wehther or not we need parentheses.
+  -- lets us determine whether or not we need parentheses.
   let (needs_parens, needs_space) =
           everythingWithContext (Nothing, Nothing) (<>)
             ( mkQ (mempty, ) $ \x s -> case x of
@@ -374,7 +396,7 @@
 #if MIN_VERSION_ghc(9,2,0)
                                 val'' <-
                                     hoistTransform (either Fail.fail pure) $
-                                        annotate dflags True $ maybeParensAST val'
+                                        annotate dflags False $ maybeParensAST val'
                                 pure val''
 #else
                                 (anns, val'') <-
@@ -430,6 +452,138 @@
             | otherwise = DL.singleton (L src e) <> go rest
     modifyDeclsT (pure . DL.toList . go) a
 
+#if MIN_VERSION_ghc(9,2,1)
+
+-- | Replace the smallest declaration whose SrcSpan satisfies the given condition with a new
+-- list of declarations.
+--
+-- For example, if you would like to move a where-clause-defined variable to the same
+-- level as its parent HsDecl, you could use this function.
+--
+-- When matching declaration is found in the sub-declarations of `a`, `Just r` is also returned with the new `a`. If
+-- not declaration matched, then `Nothing` is returned.
+modifySmallestDeclWithM ::
+  forall a m r.
+  (HasDecls a, Monad m) =>
+  (SrcSpan -> m Bool) ->
+  (LHsDecl GhcPs -> TransformT m ([LHsDecl GhcPs], r)) ->
+  a ->
+  TransformT m (a, Maybe r)
+modifySmallestDeclWithM validSpan f a = do
+  let modifyMatchingDecl [] = pure (DL.empty, Nothing)
+      modifyMatchingDecl (ldecl@(L src _) : rest) =
+        lift (validSpan $ locA src) >>= \case
+            True -> do
+              (decs', r) <- f ldecl
+              pure $ (DL.fromList decs' <> DL.fromList rest, Just r)
+            False -> first (DL.singleton ldecl <>) <$> modifyMatchingDecl rest
+  modifyDeclsT' (fmap (first DL.toList) . modifyMatchingDecl) a
+
+generatedAnchor :: AnchorOperation -> Anchor
+generatedAnchor anchorOp = GHC.Anchor (GHC.realSrcSpan generatedSrcSpan) anchorOp
+
+setAnchor :: Anchor -> SrcSpanAnnN -> SrcSpanAnnN
+setAnchor anc (SrcSpanAnn (EpAnn _ nameAnn comments) span) =
+  SrcSpanAnn (EpAnn anc nameAnn comments) span
+setAnchor _ spanAnnN = spanAnnN
+
+removeTrailingAnns :: SrcSpanAnnN -> SrcSpanAnnN
+removeTrailingAnns (SrcSpanAnn (EpAnn anc nameAnn comments) span) =
+  let nameAnnSansTrailings = nameAnn {nann_trailing = []}
+  in SrcSpanAnn (EpAnn anc nameAnnSansTrailings comments) span
+removeTrailingAnns spanAnnN = spanAnnN
+
+-- | Modify the type signature for the given IdP. This function handles splitting a multi-sig
+-- SigD into multiple SigD if the type signature is changed.
+--
+-- For example, update the type signature for `foo` from `Int` to `Bool`:
+--
+-- - foo :: Int
+-- + foo :: Bool
+--
+-- - foo, bar :: Int
+-- + bar :: Int
+-- + foo :: Bool
+--
+-- - foo, bar, baz :: Int
+-- + bar, baz :: Int
+-- + foo :: Bool
+modifySigWithM ::
+  forall a m.
+  (HasDecls a, Monad m) =>
+  IdP GhcPs ->
+  (LHsSigType GhcPs -> LHsSigType GhcPs) ->
+  a ->
+  TransformT m a
+modifySigWithM queryId f a = do
+  let modifyMatchingSigD :: [LHsDecl GhcPs] -> TransformT m (DL.DList (LHsDecl GhcPs))
+      modifyMatchingSigD [] = pure (DL.empty)
+      modifyMatchingSigD (ldecl@(L annSigD (SigD xsig (TypeSig xTypeSig ids (HsWC xHsWc lHsSig)))) : rest)
+        | queryId `elem` (unLoc <$> ids) = do
+            let newSig = f lHsSig
+            -- If this signature update caused no change, then we don't need to split up multi-signatures
+            if newSig `geq` lHsSig
+              then pure $ DL.singleton ldecl <> DL.fromList rest
+              else case partition ((== queryId) . unLoc) ids of
+                ([L annMatchedId matchedId], otherIds) ->
+                  let matchedId' = L (setAnchor genAnchor0 $ removeTrailingAnns annMatchedId) matchedId
+                      matchedIdSig =
+                        let sig' = SigD xsig (TypeSig xTypeSig [matchedId'] (HsWC xHsWc newSig))
+                            epAnn = bool (noAnnSrcSpanDP generatedSrcSpan (DifferentLine 1 0)) annSigD (null otherIds)
+                        in L epAnn sig'
+                      otherSig = case otherIds of
+                        [] -> []
+                        (L (SrcSpanAnn epAnn span) id1:ids) -> [
+                          let epAnn' = case epAnn of
+                                EpAnn _ nameAnn commentsId1 -> EpAnn genAnchor0 nameAnn commentsId1
+                                EpAnnNotUsed -> EpAnn genAnchor0 mempty emptyComments
+                              ids' = L (SrcSpanAnn epAnn' span) id1:ids
+                              ids'' = ids' & _last %~ first removeTrailingAnns
+                            in L annSigD (SigD xsig (TypeSig xTypeSig ids'' (HsWC xHsWc lHsSig)))
+                            ]
+                  in pure $ DL.fromList otherSig <> DL.singleton matchedIdSig <> DL.fromList rest
+                _ -> error "multiple ids matched"
+      modifyMatchingSigD (ldecl : rest) = (DL.singleton ldecl <>) <$> modifyMatchingSigD rest
+  modifyDeclsT (fmap DL.toList . modifyMatchingSigD) a
+
+genAnchor0 :: Anchor
+genAnchor0 = generatedAnchor m0
+
+genAnchor1 :: Anchor
+genAnchor1 = generatedAnchor m1
+
+-- | Apply a transformation to the decls contained in @t@
+modifyDeclsT' :: (HasDecls t, HasTransform m)
+             => ([LHsDecl GhcPs] -> m ([LHsDecl GhcPs], r))
+             -> t -> m (t, r)
+modifyDeclsT' action t = do
+  decls <- liftT $ hsDecls t
+  (decls', r) <- action decls
+  t' <- liftT $ replaceDecls t decls'
+  pure (t', r)
+
+-- | Modify each LMatch in a MatchGroup
+modifyMgMatchesT ::
+  Monad m =>
+  MatchGroup GhcPs (LHsExpr GhcPs) ->
+  (LMatch GhcPs (LHsExpr GhcPs) -> TransformT m (LMatch GhcPs (LHsExpr GhcPs))) ->
+  TransformT m (MatchGroup GhcPs (LHsExpr GhcPs))
+modifyMgMatchesT mg f = fst <$> modifyMgMatchesT' mg (fmap (, ()) . f) () ((.) pure . const)
+
+-- | Modify the each LMatch in a MatchGroup
+modifyMgMatchesT' ::
+  Monad m =>
+  MatchGroup GhcPs (LHsExpr GhcPs) ->
+  (LMatch GhcPs (LHsExpr GhcPs) -> TransformT m (LMatch GhcPs (LHsExpr GhcPs), r)) ->
+  r ->
+  (r -> r -> m r) ->
+  TransformT m (MatchGroup GhcPs (LHsExpr GhcPs), r)
+modifyMgMatchesT' (MG xMg (L locMatches matches) originMg) f def combineResults = do
+  (unzip -> (matches', rs)) <- mapM f matches
+  r' <- lift $ foldM combineResults def rs
+  pure $ (MG xMg (L locMatches matches') originMg, r')
+#endif
+
 graftSmallestDeclsWithM ::
     forall a.
     (HasDecls a) =>
@@ -468,7 +622,17 @@
     modifyDeclsT (fmap DL.toList . go) a
 
 
-class (Data ast, Typeable l, Outputable l, Outputable ast) => ASTElement l ast | ast -> l where
+-- In 9.2+, we need `Default l` to do `setPrecedingLines` on annotated elements.
+-- In older versions, we pass around annotations explicitly, so the instance isn't needed.
+class
+    ( Data ast
+    , Typeable l
+    , Outputable l
+    , Outputable ast
+#if MIN_VERSION_ghc(9,2,0)
+    , Default l
+#endif
+    ) => ASTElement l ast | ast -> l where
     parseAST :: Parser (LocatedAn l ast)
     maybeParensAST :: LocatedAn l ast -> LocatedAn l ast
     {- | Construct a 'Graft', replacing the node at the given 'SrcSpan' with
@@ -489,13 +653,8 @@
     graft = graftExpr
 
 instance p ~ GhcPs => ASTElement AnnListItem (Pat p) where
-#if __GLASGOW_HASKELL__ == 808
-    parseAST = fmap (fmap $ right $ second dL) . parsePattern
-    maybeParensAST = dL . parenthesizePat appPrec . unLoc
-#else
     parseAST = parsePattern
     maybeParensAST = parenthesizePat appPrec
-#endif
 
 instance p ~ GhcPs => ASTElement AnnListItem (HsType p) where
     parseAST = parseType
@@ -525,6 +684,7 @@
 
 ------------------------------------------------------------------------------
 
+
 -- | Given an 'LHSExpr', compute its exactprint annotations.
 --   Note that this function will throw away any existing annotations (and format)
 annotate :: (ASTElement l ast, Outputable l)
@@ -536,9 +696,12 @@
 annotate dflags needs_space ast = do
     uniq <- show <$> uniqueSrcSpanT
     let rendered = render dflags ast
-#if MIN_VERSION_ghc(9,2,0)
+#if MIN_VERSION_ghc(9,4,0)
+    expr' <- lift $ mapLeft (showSDoc dflags . ppr) $ parseAST dflags uniq rendered
+    pure $ setPrecedingLines expr' 0 (bool 0 1 needs_space)
+#elif MIN_VERSION_ghc(9,2,0)
     expr' <- lift $ mapLeft show $ parseAST dflags uniq rendered
-    pure expr'
+    pure $ setPrecedingLines expr' 0 (bool 0 1 needs_space)
 #else
     (anns, expr') <- lift $ mapLeft show $ parseAST dflags uniq rendered
     let anns' = setPrecedingLines expr' 0 (bool 0 1 needs_space) anns
@@ -547,6 +710,7 @@
 
 -- | Given an 'LHsDecl', compute its exactprint annotations.
 annotateDecl :: DynFlags -> LHsDecl GhcPs -> TransformT (Either String) (LHsDecl GhcPs)
+#if !MIN_VERSION_ghc(9,2,0)
 -- The 'parseDecl' function fails to parse 'FunBind' 'ValD's which contain
 -- multiple matches. To work around this, we split the single
 -- 'FunBind'-of-multiple-'Match'es into multiple 'FunBind's-of-one-'Match',
@@ -559,17 +723,6 @@
     let set_matches matches =
           ValD ext fb { fun_matches = mg { mg_alts = L alt_src matches }}
 
-#if MIN_VERSION_ghc(9,2,0)
-    alts' <- for alts $ \alt -> do
-      uniq <- show <$> uniqueSrcSpanT
-      let rendered = render dflags $ set_matches [alt]
-      lift (mapLeft show $ parseDecl dflags uniq rendered) >>= \case
-        (L _ (ValD _ FunBind { fun_matches = MG { mg_alts = L _ [alt']}}))
-           -> pure alt'
-        _ ->  lift $ Left "annotateDecl: didn't parse a single FunBind match"
-
-    pure $ L src $ set_matches alts'
-#else
     (anns', alts') <- fmap unzip $ for alts $ \alt -> do
       uniq <- show <$> uniqueSrcSpanT
       let rendered = render dflags $ set_matches [alt]
@@ -584,8 +737,12 @@
 annotateDecl dflags ast = do
     uniq <- show <$> uniqueSrcSpanT
     let rendered = render dflags ast
-#if MIN_VERSION_ghc(9,2,0)
-    lift $ mapLeft show $ parseDecl dflags uniq rendered
+#if MIN_VERSION_ghc(9,4,0)
+    expr' <- lift $ mapLeft (showSDoc dflags . ppr) $ parseDecl dflags uniq rendered
+    pure $ setPrecedingLines expr' 1 0
+#elif MIN_VERSION_ghc(9,2,0)
+    expr' <- lift $ mapLeft show $ parseDecl dflags uniq rendered
+    pure $ setPrecedingLines expr' 1 0
 #else
     (anns, expr') <- lift $ mapLeft show $ parseDecl dflags uniq rendered
     let anns' = setPrecedingLines expr' 1 0 anns
@@ -667,6 +824,4 @@
 isCommaAnn :: TrailingAnn -> Bool
 isCommaAnn AddCommaAnn{} = True
 isCommaAnn _             = False
-#endif
-
 #endif
diff --git a/src/Development/IDE/Plugin/CodeAction.hs b/src/Development/IDE/Plugin/CodeAction.hs
--- a/src/Development/IDE/Plugin/CodeAction.hs
+++ b/src/Development/IDE/Plugin/CodeAction.hs
@@ -19,9 +19,9 @@
                                                                     (&&&),
                                                                     (>>>))
 import           Control.Concurrent.STM.Stats                      (atomically)
+import           Control.Monad.Extra
 import           Control.Monad.IO.Class
 import           Control.Monad.Trans.Maybe
-import           Control.Monad.Extra
 import           Data.Aeson
 import           Data.Char
 import qualified Data.DList                                        as DL
@@ -37,56 +37,67 @@
 import           Data.Ord                                          (comparing)
 import qualified Data.Set                                          as S
 import qualified Data.Text                                         as T
+import qualified Data.Text.Encoding                                as T
 import qualified Data.Text.Utf16.Rope                              as Rope
-import           Data.Tuple.Extra                                  (fst3)
-import           Development.IDE.Types.Logger                      hiding (group)
 import           Development.IDE.Core.Rules
 import           Development.IDE.Core.RuleTypes
 import           Development.IDE.Core.Service
-import           Development.IDE.GHC.Compat
+import           Development.IDE.Core.Shake                        hiding (Log)
+import           Development.IDE.GHC.Compat                        hiding
+                                                                   (ImplicitPrelude)
 import           Development.IDE.GHC.Compat.ExactPrint
 import           Development.IDE.GHC.Compat.Util
 import           Development.IDE.GHC.Error
 import           Development.IDE.GHC.ExactPrint
-import qualified Development.IDE.GHC.ExactPrint                   as E
+import qualified Development.IDE.GHC.ExactPrint                    as E
 import           Development.IDE.GHC.Util                          (printOutputable,
                                                                     printRdrName)
-import           Development.IDE.Core.Shake                   hiding (Log)
 import           Development.IDE.Plugin.CodeAction.Args
 import           Development.IDE.Plugin.CodeAction.ExactPrint
-import           Development.IDE.Plugin.CodeAction.Util
 import           Development.IDE.Plugin.CodeAction.PositionIndexed
+import           Development.IDE.Plugin.CodeAction.Util
 import           Development.IDE.Plugin.Completions.Types
+import qualified Development.IDE.Plugin.Plugins.AddArgument
+import           Development.IDE.Plugin.Plugins.Diagnostic
+import           Development.IDE.Plugin.Plugins.FillHole           (suggestFillHole)
+import           Development.IDE.Plugin.Plugins.FillTypeWildcard   (suggestFillTypeWildcard)
+import           Development.IDE.Plugin.Plugins.ImportUtils
 import           Development.IDE.Plugin.TypeLenses                 (suggestSignature)
 import           Development.IDE.Types.Exports
 import           Development.IDE.Types.Location
+import           Development.IDE.Types.Logger                      hiding
+                                                                   (group)
 import           Development.IDE.Types.Options
+import           GHC.Exts                                          (fromList)
 import qualified GHC.LanguageExtensions                            as Lang
+#if MIN_VERSION_ghc(9,4,0)
+import           GHC.Parser.Annotation                             (TokenLocation (..))
+#endif
 import           Ide.PluginUtils                                   (subRange)
 import           Ide.Types
 import qualified Language.LSP.Server                               as LSP
-import           Language.LSP.Types                                (ApplyWorkspaceEditParams(..), CodeAction (..),
+import           Language.LSP.Types                                (ApplyWorkspaceEditParams (..),
+                                                                    CodeAction (..),
                                                                     CodeActionContext (CodeActionContext, _diagnostics),
-                                                                    CodeActionKind (CodeActionQuickFix, CodeActionUnknown),
+                                                                    CodeActionKind (CodeActionQuickFix),
                                                                     CodeActionParams (CodeActionParams),
                                                                     Command,
                                                                     Diagnostic (..),
-                                                                    MessageType (..),
-                                                                    ShowMessageParams (..),
                                                                     List (..),
+                                                                    MessageType (..),
                                                                     ResponseError,
                                                                     SMethod (..),
+                                                                    ShowMessageParams (..),
                                                                     TextDocumentIdentifier (TextDocumentIdentifier),
                                                                     TextEdit (TextEdit, _range),
                                                                     UInt,
                                                                     WorkspaceEdit (WorkspaceEdit, _changeAnnotations, _changes, _documentChanges),
                                                                     type (|?) (InR),
                                                                     uriToFilePath)
-import           GHC.Exts                                           (fromList)
 import           Language.LSP.VFS                                  (VirtualFile,
                                                                     _file_text)
-import           Text.Regex.TDFA                                   (mrAfter,
-                                                                    (=~), (=~~))
+import qualified Text.Fuzzy.Parallel                               as TFP
+import           Text.Regex.TDFA                                   ((=~), (=~~))
 #if MIN_VERSION_ghc(9,2,0)
 import           GHC                                               (AddEpAnn (AddEpAnn),
                                                                     Anchor (anchor_op),
@@ -95,9 +106,7 @@
                                                                     DeltaPos (..),
                                                                     EpAnn (..),
                                                                     EpaLocation (..),
-                                                                    LEpaComment,
-                                                                    LocatedA)
-
+                                                                    LEpaComment)
 #else
 import           Language.Haskell.GHC.ExactPrint.Types             (Annotation (annsDP),
                                                                     DeltaPos,
@@ -135,13 +144,11 @@
             wrap suggestExportUnusedTopBinding
           , wrap suggestModuleTypo
           , wrap suggestFixConstructorImport
-          , wrap suggestNewImport
-#if !MIN_VERSION_ghc(9,3,0)
           , wrap suggestExtendImport
           , wrap suggestImportDisambiguation
           , wrap suggestNewOrExtendImportForClassMethod
           , wrap suggestHideShadow
-#endif
+          , wrap suggestNewImport
           ]
           plId
    in mkExactprintPluginDescriptor recorder $ old {pluginHandlers = pluginHandlers old <> mkPluginHandler STextDocumentCodeAction codeAction }
@@ -151,11 +158,9 @@
   mkGhcideCAsPlugin [
       wrap $ suggestSignature True
     , wrap suggestFillTypeWildcard
-    , wrap suggestAddTypeAnnotationToSatisfyContraints
-#if !MIN_VERSION_ghc(9,3,0)
+    , wrap suggestAddTypeAnnotationToSatisfyConstraints
     , wrap removeRedundantConstraints
     , wrap suggestConstraint
-#endif
     ]
     plId
 
@@ -163,10 +168,9 @@
 bindingsPluginDescriptor recorder plId = mkExactprintPluginDescriptor recorder $
   mkGhcideCAsPlugin [
       wrap suggestReplaceIdentifier
-#if !MIN_VERSION_ghc(9,3,0)
     , wrap suggestImplicitParameter
-#endif
     , wrap suggestNewDefinition
+    , wrap Development.IDE.Plugin.Plugins.AddArgument.plugin
     , wrap suggestDeleteUnusedBinding
     ]
     plId
@@ -242,7 +246,7 @@
                   Nothing -> newThing
                   Just p  -> p <> "(" <> newThing <> ")"
             t <- liftMaybe $ snd <$> newImportToEdit n ps (fromMaybe "" contents)
-            return (nfp, WorkspaceEdit {_changes=Just (fromList [(doc,List [t])]), _documentChanges=Nothing, _changeAnnotations=Nothing})
+            return (nfp, WorkspaceEdit {_changes=Just (GHC.Exts.fromList [(doc,List [t])]), _documentChanges=Nothing, _changeAnnotations=Nothing})
   | otherwise =
     mzero
 
@@ -369,7 +373,6 @@
 --  imported from ‘Data.ByteString’ at B.hs:6:1-22
 --  imported from ‘Data.ByteString.Lazy’ at B.hs:8:1-27
 --  imported from ‘Data.Text’ at B.hs:7:1-16
-#if !MIN_VERSION_ghc(9,3,0)
 suggestHideShadow :: Annotated ParsedSource -> T.Text -> Maybe TcModuleResult -> Maybe HieAstResult -> Diagnostic -> [(T.Text, [Either TextEdit Rewrite])]
 suggestHideShadow ps fileContents mTcM mHar Diagnostic {_message, _range}
   | Just [identifier, modName, s] <-
@@ -384,12 +387,12 @@
     Just matched <- allMatchRegexUnifySpaces _message "imported from ‘([^’]+)’ at ([^ ]*)",
     mods <- [(modName, s) | [_, modName, s] <- matched],
     result <- nubOrdBy (compare `on` fst) $ mods >>= uncurry (suggests identifier),
-    hideAll <- ("Hide " <> identifier <> " from all occurence imports", concat $ snd <$> result) =
+    hideAll <- ("Hide " <> identifier <> " from all occurrence imports", concatMap snd result) =
     result <> [hideAll]
   | otherwise = []
   where
     L _ HsModule {hsmodImports} = astA ps
- 
+
     suggests identifier modName s
       | Just tcM <- mTcM,
         Just har <- mHar,
@@ -401,7 +404,6 @@
           then maybeToList $ (\(_, te) -> (title, [Left te])) <$> newImportToEdit (hideImplicitPreludeSymbol identifier) ps fileContents
           else maybeToList $ (title,) . pure . pure . hideSymbol (T.unpack identifier) <$> mDecl
       | otherwise = []
-#endif
 
 findImportDeclByModuleName :: [LImportDecl GhcPs] -> String -> Maybe (LImportDecl GhcPs)
 findImportDeclByModuleName decls modName = flip find decls $ \case
@@ -458,6 +460,12 @@
         = [("Remove import", [TextEdit (extendToWholeLineIfPossible contents _range) ""])]
     | otherwise = []
 
+
+-- Note [Removing imports is preferred]
+-- It's good to prefer the remove imports code action because an unused import
+-- is likely to be removed and less likely the warning will be disabled.
+-- Therefore actions to remove a single or all redundant imports should be
+-- preferred, so that the client can prioritize them higher.
 caRemoveRedundantImports :: Maybe ParsedModule -> Maybe T.Text -> [Diagnostic] -> [Diagnostic] -> Uri -> [Command |? CodeAction]
 caRemoveRedundantImports m contents digs ctxDigs uri
   | Just pm <- m,
@@ -481,7 +489,8 @@
         _diagnostics = Nothing
         _documentChanges = Nothing
         _edit = Just WorkspaceEdit{..}
-        _isPreferred = Nothing
+        -- See Note [Removing imports is preferred]
+        _isPreferred = Just True
         _command = Nothing
         _disabled = Nothing
         _xdata = Nothing
@@ -520,7 +529,8 @@
         _documentChanges = Nothing
         _edit = Just WorkspaceEdit{..}
         _command = Nothing
-        _isPreferred = Nothing
+        -- See Note [Removing imports is preferred]
+        _isPreferred = Just True
         _disabled = Nothing
         _xdata = Nothing
         _changeAnnotations = Nothing
@@ -534,7 +544,8 @@
         _documentChanges = Nothing
         _edit = Just WorkspaceEdit{..}
         _command = Nothing
-        _isPreferred = Nothing
+        -- See Note [Removing imports is preferred]
+        _isPreferred = Just True
         _disabled = Nothing
         _xdata = Nothing
         _changeAnnotations = Nothing
@@ -772,8 +783,8 @@
     exportsAs (TyClD _ FamDecl{tcdFam})        = Just (ExportFamily, reLoc $ fdLName tcdFam)
     exportsAs _                                = Nothing
 
-suggestAddTypeAnnotationToSatisfyContraints :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
-suggestAddTypeAnnotationToSatisfyContraints sourceOpt Diagnostic{_range=_range,..}
+suggestAddTypeAnnotationToSatisfyConstraints :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
+suggestAddTypeAnnotationToSatisfyConstraints sourceOpt Diagnostic{_range=_range,..}
 -- File.hs:52:41: warning:
 --     * Defaulting the following constraint to type ‘Integer’
 --        Num p0 arising from the literal ‘1’
@@ -813,6 +824,18 @@
     | otherwise = []
     where
       makeAnnotatedLit ty lit = "(" <> lit <> " :: " <> ty <> ")"
+#if MIN_VERSION_ghc(9,4,0)
+      pat multiple at inArg inExpr = T.concat [ ".*Defaulting the type variable "
+                                       , ".*to type ‘([^ ]+)’ "
+                                       , "in the following constraint"
+                                       , if multiple then "s" else ""
+                                       , ".*arising from the literal ‘(.+)’"
+                                       , if inArg then ".+In the.+argument" else ""
+                                       , if at then ".+at" else ""
+                                       , if inExpr then ".+In the expression" else ""
+                                       , ".+In the expression"
+                                       ]
+#else
       pat multiple at inArg inExpr = T.concat [ ".*Defaulting the following constraint"
                                        , if multiple then "s" else ""
                                        , " to type ‘([^ ]+)’ "
@@ -822,14 +845,19 @@
                                        , if inExpr then ".+In the expression" else ""
                                        , ".+In the expression"
                                        ]
+#endif
       codeEdit ty lit replacement =
         let title = "Add type annotation ‘" <> ty <> "’ to ‘" <> lit <> "’"
             edits = [TextEdit _range replacement]
         in  [( title, edits )]
 
-
-suggestReplaceIdentifier :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
-suggestReplaceIdentifier contents Diagnostic{_range=_range,..}
+-- | GHC strips out backticks in case of infix functions as well as single quote
+--   in case of quoted name when using TemplateHaskellQuotes. Which is not desired.
+--
+-- For example:
+-- 1.
+--
+-- @
 -- File.hs:52:41: error:
 --     * Variable not in scope:
 --         suggestAcion :: Maybe T.Text -> Range -> Range
@@ -841,49 +869,59 @@
 --       ‘T.isInfixOf’ (imported from Data.Text),
 --       ‘T.isSuffixOf’ (imported from Data.Text)
 --     Module ‘Data.Text’ does not export ‘isPrfixOf’.
+-- @
+--
+-- * action: \`suggestAcion\` will be renamed to \`suggestAction\` keeping back ticks around the function
+--
+-- 2.
+--
+-- @
+-- import Language.Haskell.TH (Name)
+-- foo :: Name
+-- foo = 'bread
+--
+-- File.hs:8:7: error:
+--     Not in scope: ‘bread’
+--       * Perhaps you meant one of these:
+--         ‘break’ (imported from Prelude), ‘read’ (imported from Prelude)
+--       * In the Template Haskell quotation 'bread
+-- @
+--
+-- * action: 'bread will be renamed to 'break keeping single quote on beginning of name
+suggestReplaceIdentifier :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
+suggestReplaceIdentifier contents Diagnostic{_range=_range,..}
     | renameSuggestions@(_:_) <- extractRenamableTerms _message
         = [ ("Replace with ‘" <> name <> "’", [mkRenameEdit contents _range name]) | name <- renameSuggestions ]
     | otherwise = []
 
 suggestNewDefinition :: IdeOptions -> ParsedModule -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
-suggestNewDefinition ideOptions parsedModule contents Diagnostic{_message, _range}
---     * Variable not in scope:
---         suggestAcion :: Maybe T.Text -> Range -> Range
-    | Just [name, typ] <- matchRegexUnifySpaces message "Variable not in scope: ([^ ]+) :: ([^*•]+)"
-    = newDefinitionAction ideOptions parsedModule _range name typ
-    | Just [name, typ] <- matchRegexUnifySpaces message "Found hole: _([^ ]+) :: ([^*•]+) Or perhaps"
-    , [(label, newDefinitionEdits)] <- newDefinitionAction ideOptions parsedModule _range name typ
-    = [(label, mkRenameEdit contents _range name : newDefinitionEdits)]
-    | otherwise = []
-    where
-      message = unifySpaces _message
+suggestNewDefinition ideOptions parsedModule contents Diagnostic {_message, _range}
+  | Just (name, typ) <- matchVariableNotInScope message =
+      newDefinitionAction ideOptions parsedModule _range name typ
+  | Just (name, typ) <- matchFoundHole message,
+    [(label, newDefinitionEdits)] <- newDefinitionAction ideOptions parsedModule _range name (Just typ) =
+      [(label, mkRenameEdit contents _range name : newDefinitionEdits)]
+  | otherwise = []
+  where
+    message = unifySpaces _message
 
-newDefinitionAction :: IdeOptions -> ParsedModule -> Range -> T.Text -> T.Text -> [(T.Text, [TextEdit])]
-newDefinitionAction IdeOptions{..} parsedModule Range{_start} name typ
-    | Range _ lastLineP : _ <-
+newDefinitionAction :: IdeOptions -> ParsedModule -> Range -> T.Text -> Maybe T.Text -> [(T.Text, [TextEdit])]
+newDefinitionAction IdeOptions {..} parsedModule Range {_start} name typ
+  | Range _ lastLineP : _ <-
       [ realSrcSpanToRange sp
-      | (L (locA -> l@(RealSrcSpan sp _)) _) <- hsmodDecls
-      , _start `isInsideSrcSpan` l]
-    , nextLineP <- Position{ _line = _line lastLineP + 1, _character = 0}
-    = [ ("Define " <> sig
-        , [TextEdit (Range nextLineP nextLineP) (T.unlines ["", sig, name <> " = _"])]
-        )]
-    | otherwise = []
+        | (L (locA -> l@(RealSrcSpan sp _)) _) <- hsmodDecls,
+          _start `isInsideSrcSpan` l
+      ],
+    nextLineP <- Position {_line = _line lastLineP + 1, _character = 0} =
+      [ ( "Define " <> sig,
+          [TextEdit (Range nextLineP nextLineP) (T.unlines ["", sig, name <> " = _"])]
+        )
+      ]
+  | otherwise = []
   where
     colon = if optNewColonConvention then " : " else " :: "
-    sig = name <> colon <> T.dropWhileEnd isSpace typ
-    ParsedModule{pm_parsed_source = L _ HsModule{hsmodDecls}} = parsedModule
-
-suggestFillTypeWildcard :: Diagnostic -> [(T.Text, TextEdit)]
-suggestFillTypeWildcard Diagnostic{_range=_range,..}
--- Foo.hs:3:8: error:
---     * Found type wildcard `_' standing for `p -> p1 -> p'
-
-    | "Found type wildcard" `T.isInfixOf` _message
-    , " standing for " `T.isInfixOf` _message
-    , typeSignature <- extractWildCardTypeSignature _message
-        =  [("Use type signature: ‘" <> typeSignature <> "’", TextEdit _range typeSignature)]
-    | otherwise = []
+    sig = name <> colon <> T.dropWhileEnd isSpace (fromMaybe "_" typ)
+    ParsedModule {pm_parsed_source = L _ HsModule {hsmodDecls}} = parsedModule
 
 {- Handles two variants with different formatting
 
@@ -911,90 +949,6 @@
         [modul, "(from", _] -> Just modul
         _                   -> Nothing
 
-
-suggestFillHole :: Diagnostic -> [(T.Text, TextEdit)]
-suggestFillHole Diagnostic{_range=_range,..}
-    | Just holeName <- extractHoleName _message
-    , (holeFits, refFits) <- processHoleSuggestions (T.lines _message) =
-      let isInfixHole = _message =~ addBackticks holeName :: Bool in
-        map (proposeHoleFit holeName False isInfixHole) holeFits
-        ++ map (proposeHoleFit holeName True isInfixHole) refFits
-    | otherwise = []
-    where
-      extractHoleName = fmap head . flip matchRegexUnifySpaces "Found hole: ([^ ]*)"
-      addBackticks text = "`" <> text <> "`"
-      addParens text = "(" <> text <> ")"
-      proposeHoleFit holeName parenthise isInfixHole name =
-        let isInfixOperator = T.head name == '('
-            name' = getOperatorNotation isInfixHole isInfixOperator name in
-          ( "replace " <> holeName <> " with " <> name
-          , TextEdit _range (if parenthise then addParens name' else name')
-          )
-      getOperatorNotation True False name                    = addBackticks name
-      getOperatorNotation True True name                     = T.drop 1 (T.dropEnd 1 name)
-      getOperatorNotation _isInfixHole _isInfixOperator name = name
-
-processHoleSuggestions :: [T.Text] -> ([T.Text], [T.Text])
-processHoleSuggestions mm = (holeSuggestions, refSuggestions)
-{-
-    • Found hole: _ :: LSP.Handlers
-
-      Valid hole fits include def
-      Valid refinement hole fits include
-        fromMaybe (_ :: LSP.Handlers) (_ :: Maybe LSP.Handlers)
-        fromJust (_ :: Maybe LSP.Handlers)
-        haskell-lsp-types-0.22.0.0:Language.LSP.Types.Window.$sel:_value:ProgressParams (_ :: ProgressParams
-                                                                                                        LSP.Handlers)
-        T.foldl (_ :: LSP.Handlers -> Char -> LSP.Handlers)
-                (_ :: LSP.Handlers)
-                (_ :: T.Text)
-        T.foldl' (_ :: LSP.Handlers -> Char -> LSP.Handlers)
-                 (_ :: LSP.Handlers)
-                 (_ :: T.Text)
--}
-  where
-    t = id @T.Text
-    holeSuggestions = do
-      -- get the text indented under Valid hole fits
-      validHolesSection <-
-        getIndentedGroupsBy (=~ t " *Valid (hole fits|substitutions) include") mm
-      -- the Valid hole fits line can contain a hole fit
-      holeFitLine <-
-        mapHead
-            (mrAfter . (=~ t " *Valid (hole fits|substitutions) include"))
-            validHolesSection
-      let holeFit = T.strip $ T.takeWhile (/= ':') holeFitLine
-      guard (not $ T.null holeFit)
-      return holeFit
-    refSuggestions = do -- @[]
-      -- get the text indented under Valid refinement hole fits
-      refinementSection <-
-        getIndentedGroupsBy (=~ t " *Valid refinement hole fits include") mm
-      -- get the text for each hole fit
-      holeFitLines <- getIndentedGroups (tail refinementSection)
-      let holeFit = T.strip $ T.unwords holeFitLines
-      guard $ not $ holeFit =~ t "Some refinement hole fits suppressed"
-      return holeFit
-
-    mapHead f (a:aa) = f a : aa
-    mapHead _ []     = []
-
--- > getIndentedGroups [" H1", "  l1", "  l2", " H2", "  l3"] = [[" H1,", "  l1", "  l2"], [" H2", "  l3"]]
-getIndentedGroups :: [T.Text] -> [[T.Text]]
-getIndentedGroups [] = []
-getIndentedGroups ll@(l:_) = getIndentedGroupsBy ((== indentation l) . indentation) ll
--- |
--- > getIndentedGroupsBy (" H" `isPrefixOf`) [" H1", "  l1", "  l2", " H2", "  l3"] = [[" H1", "  l1", "  l2"], [" H2", "  l3"]]
-getIndentedGroupsBy :: (T.Text -> Bool) -> [T.Text] -> [[T.Text]]
-getIndentedGroupsBy pred inp = case dropWhile (not.pred) inp of
-    (l:ll) -> case span (\l' -> indentation l < indentation l') ll of
-        (indented, rest) -> (l:indented) : getIndentedGroupsBy pred rest
-    _ -> []
-
-indentation :: T.Text -> Int
-indentation = T.length . T.takeWhile isSpace
-
-#if !MIN_VERSION_ghc(9,3,0)
 suggestExtendImport :: ExportsMap -> ParsedSource -> Diagnostic -> [(T.Text, CodeActionKind, Rewrite)]
 suggestExtendImport exportsMap (L _ HsModule {hsmodImports}) Diagnostic{_range=_range,..}
     | Just [binding, mod, srcspan] <-
@@ -1025,24 +979,23 @@
             ]
           | otherwise = []
         lookupExportMap binding mod
-          | Just match <- Map.lookup binding (getExportsMap exportsMap)
+          | let em = getExportsMap exportsMap
+                match1 = lookupOccEnv em (mkVarOrDataOcc binding)
+                match2 = lookupOccEnv em (mkTypeOcc binding)
+          , Just match <- match1 <> match2
           -- Only for the situation that data constructor name is same as type constructor name,
           -- let ident with parent be in front of the one without.
           , sortedMatch <- sortBy (\ident1 ident2 -> parent ident2 `compare` parent ident1) (Set.toList match)
           , idents <- filter (\ident -> moduleNameText ident == mod && (canUseDatacon || not (isDatacon ident))) sortedMatch
-          , (not . null) idents -- Ensure fallback while `idents` is empty
-          , ident <- head idents
+          , (ident:_) <- idents -- Ensure fallback while `idents` is empty
           = Just ident
 
             -- fallback to using GHC suggestion even though it is not always correct
           | otherwise
           = Just IdentInfo
-                { name = mkVarOcc $ T.unpack binding
-                , rendered = binding
+                { name = mkVarOrDataOcc binding
                 , parent = Nothing
-                , isDatacon = False
-                , moduleNameText = mod}
-#endif
+                , identModuleName  = mkModuleNameFS $ mkFastStringByteString $ T.encodeUtf8 mod}
 
 data HidingMode
     = HideOthers [ModuleTarget]
@@ -1068,7 +1021,6 @@
 isPreludeImplicit :: DynFlags -> Bool
 isPreludeImplicit = xopt Lang.ImplicitPrelude
 
-#if !MIN_VERSION_ghc(9,3,0)
 -- | Suggests disambiguation for ambiguous symbols.
 suggestImportDisambiguation ::
     DynFlags ->
@@ -1160,7 +1112,6 @@
                 <> "."
                 <> symbol
 suggestImportDisambiguation _ _ _ _ _ = []
-#endif
 
 occursUnqualified :: T.Text -> ImportDecl GhcPs -> Bool
 occursUnqualified symbol ImportDecl{..}
@@ -1183,7 +1134,6 @@
 targetModuleName (ExistingImp _) =
     error "Cannot happen!"
 
-#if !MIN_VERSION_ghc(9,3,0)
 disambiguateSymbol ::
     Annotated ParsedSource ->
     T.Text ->
@@ -1216,7 +1166,6 @@
                     liftParseAST @RdrName df $
                     T.unpack $ printOutputable $ L (mkGeneralSrcSpan  "") rdr
             ]
-#endif
 
 findImportDeclByRange :: [LImportDecl GhcPs] -> Range -> Maybe (LImportDecl GhcPs)
 findImportDeclByRange xs range = find (\(L (locA -> l) _)-> srcSpanToRange l == Just range) xs
@@ -1235,7 +1184,6 @@
     in [("Fix import of " <> fixedImport, TextEdit _range fixedImport)]
   | otherwise = []
 
-#if !MIN_VERSION_ghc(9,3,0)
 -- | Suggests a constraint for a declaration for which a constraint is missing.
 suggestConstraint :: DynFlags -> ParsedSource -> Diagnostic -> [(T.Text, Rewrite)]
 suggestConstraint df (makeDeltaAst -> parsedModule) diag@Diagnostic {..}
@@ -1317,12 +1265,10 @@
       [( "Add " <> implicitT <> " to the context of " <> T.pack (printRdrName funId)
         , appendConstraint (T.unpack implicitT) hsib_body)]
   | otherwise = []
-#endif
 
 findTypeSignatureName :: T.Text -> Maybe T.Text
 findTypeSignatureName t = matchRegexUnifySpaces t "([^ ]+) :: " <&> head
 
-#if !MIN_VERSION_ghc(9,3,0)
 -- | Suggests a constraint for a type signature with any number of existing constraints.
 suggestFunctionConstraint :: DynFlags -> ParsedSource -> Diagnostic -> T.Text -> [(T.Text, Rewrite)]
 
@@ -1366,7 +1312,7 @@
 
 -- | Suggests the removal of a redundant constraint for a type signature.
 removeRedundantConstraints :: DynFlags -> ParsedSource -> Diagnostic -> [(T.Text, Rewrite)]
-removeRedundantConstraints df (L _ HsModule {hsmodDecls}) Diagnostic{..}
+removeRedundantConstraints df (makeDeltaAst -> L _ HsModule {hsmodDecls}) Diagnostic{..}
 -- • Redundant constraint: Eq a
 -- • In the type signature for:
 --      foo :: forall a. Eq a => a -> a
@@ -1441,18 +1387,18 @@
         _message
         "‘([^’]*)’ is not a \\(visible\\) method of class ‘([^’]*)’",
     idents <-
-      maybe [] (Set.toList . Set.filter (\x -> parent x == Just className)) $
-        Map.lookup methodName $ getExportsMap packageExportsMap =
+      maybe [] (Set.toList . Set.filter (\x -> fmap occNameText (parent x) == Just className)) $
+        lookupOccEnv (getExportsMap packageExportsMap) (mkVarOrDataOcc methodName) =
     mconcat $ suggest <$> idents
   | otherwise = []
   where
-    suggest identInfo@IdentInfo {moduleNameText}
+    suggest identInfo
       | importStyle <- NE.toList $ importStyles identInfo,
-        mImportDecl <- findImportDeclByModuleName (hsmodImports . unLoc . astA $ ps) (T.unpack moduleNameText) =
+        mImportDecl <- findImportDeclByModuleName (hsmodImports . unLoc . astA $ ps) (T.unpack moduleText) =
         case mImportDecl of
           -- extend
           Just decl ->
-            [ ( "Add " <> renderImportStyle style <> " to the import list of " <> moduleNameText,
+            [ ( "Add " <> renderImportStyle style <> " to the import list of " <> moduleText,
                 quickFixImportKind' "extend" style,
                 [Right $ uncurry extendImport (unImportStyle style) decl]
               )
@@ -1463,13 +1409,13 @@
             | Just (range, indent) <- newImportInsertRange ps fileContents
             ->
              (\(kind, unNewImport -> x) -> (x, kind, [Left $ TextEdit range (x <> "\n" <> T.replicate indent " ")])) <$>
-            [ (quickFixImportKind' "new" style, newUnqualImport moduleNameText rendered False)
+            [ (quickFixImportKind' "new" style, newUnqualImport moduleText rendered False)
               | style <- importStyle,
                 let rendered = renderImportStyle style
             ]
-              <> [(quickFixImportKind "new.all", newImportAll moduleNameText)]
+              <> [(quickFixImportKind "new.all", newImportAll moduleText)]
             | otherwise -> []
-#endif
+        where moduleText = moduleNameText identInfo
 
 suggestNewImport :: ExportsMap -> Annotated ParsedSource -> T.Text -> Diagnostic -> [(T.Text, CodeActionKind, TextEdit)]
 suggestNewImport packageExportsMap ps fileContents Diagnostic{_message}
@@ -1484,35 +1430,67 @@
   , Just (range, indent) <- newImportInsertRange ps fileContents
   , extendImportSuggestions <- matchRegexUnifySpaces msg
     "Perhaps you want to add ‘[^’]*’ to the import list in the import of ‘([^’]*)’"
-  = sortOn fst3 [(imp, kind, TextEdit range (imp <> "\n" <> T.replicate indent " "))
-    | (kind, unNewImport -> imp) <- constructNewImportSuggestions packageExportsMap (qual <|> qual', thingMissing) extendImportSuggestions
-    ]
+  = let suggestions = nubSortBy simpleCompareImportSuggestion
+          (constructNewImportSuggestions packageExportsMap (qual <|> qual', thingMissing) extendImportSuggestions) in
+    map (\(ImportSuggestion _ kind (unNewImport -> imp)) -> (imp, kind, TextEdit range (imp <> "\n" <> T.replicate indent " "))) suggestions
   where
     L _ HsModule {..} = astA ps
 suggestNewImport _ _ _ _ = []
 
 constructNewImportSuggestions
-  :: ExportsMap -> (Maybe T.Text, NotInScope) -> Maybe [T.Text] -> [(CodeActionKind, NewImport)]
-constructNewImportSuggestions exportsMap (qual, thingMissing) notTheseModules = nubOrdOn snd
+  :: ExportsMap -> (Maybe T.Text, NotInScope) -> Maybe [T.Text] -> [ImportSuggestion]
+constructNewImportSuggestions exportsMap (qual, thingMissing) notTheseModules = nubOrdBy simpleCompareImportSuggestion
   [ suggestion
-  | Just name <- [T.stripPrefix (maybe "" (<> ".") qual) $ notInScope thingMissing]
-  , identInfo <- maybe [] Set.toList $ Map.lookup name (getExportsMap exportsMap)
-  , canUseIdent thingMissing identInfo
-  , moduleNameText identInfo `notElem` fromMaybe [] notTheseModules
-  , suggestion <- renderNewImport identInfo
+  | Just name <- [T.stripPrefix (maybe "" (<> ".") qual) $ notInScope thingMissing] -- strip away qualified module names from the unknown name
+  , identInfo <- maybe [] Set.toList $ (lookupOccEnv (getExportsMap exportsMap) (mkVarOrDataOcc name)) <> (lookupOccEnv (getExportsMap exportsMap) (mkTypeOcc name)) -- look up the modified unknown name in the export map
+  , canUseIdent thingMissing identInfo                                              -- check if the identifier information retrieved can be used
+  , moduleNameText identInfo `notElem` fromMaybe [] notTheseModules                 -- check if the module of the identifier is allowed
+  , suggestion <- renderNewImport identInfo                                         -- creates a list of import suggestions for the retrieved identifier information
   ]
  where
-  renderNewImport :: IdentInfo -> [(CodeActionKind, NewImport)]
+  renderNewImport :: IdentInfo -> [ImportSuggestion]
   renderNewImport identInfo
     | Just q <- qual
-    = [(quickFixImportKind "new.qualified", newQualImport m q)]
+    = [ImportSuggestion importanceScore (quickFixImportKind "new.qualified") (newQualImport m q)]
     | otherwise
-    = [(quickFixImportKind' "new" importStyle, newUnqualImport m (renderImportStyle importStyle) False)
+    = [ImportSuggestion importanceScore (quickFixImportKind' "new" importStyle) (newUnqualImport m (renderImportStyle importStyle) False)
       | importStyle <- NE.toList $ importStyles identInfo] ++
-      [(quickFixImportKind "new.all", newImportAll m)]
+      [ImportSuggestion importanceScore (quickFixImportKind "new.all") (newImportAll m)]
     where
+        -- The importance score takes 2 metrics into account. The first being the similarity using
+        -- the Text.Fuzzy.Parallel.match function. The second is a factor of the relation between
+        -- the modules prefix import suggestion and the unknown identifier names.
+        importanceScore
+          | Just q <- qual
+          = let
+              similarityScore = fromIntegral $ unpackMatchScore (TFP.match (T.toLower q) (T.toLower m)) :: Double
+              (maxLength, minLength) = case (T.length q, T.length m) of
+                 (la, lb)
+                   | la >= lb -> (fromIntegral la, fromIntegral lb)
+                   | otherwise -> (fromIntegral lb, fromIntegral la)
+              lengthPenaltyFactor = 100 * minLength / maxLength
+            in max 0 (floor (similarityScore * lengthPenaltyFactor))
+          | otherwise
+          = 0
+          where
+            unpackMatchScore pScore
+              | Just score <- pScore = score
+              | otherwise = 0
         m = moduleNameText identInfo
 
+data ImportSuggestion = ImportSuggestion !Int !CodeActionKind !NewImport
+  deriving ( Eq )
+
+-- | Implements a lexicographic order for import suggestions that ignores the code action.
+-- First it compares the importance score in DESCENDING order.
+-- If the scores are equal it compares the import names alphabetical order.
+--
+-- TODO: this should be a correct Ord instance but CodeActionKind does not implement a Ord
+-- which would lead to an unlawful Ord instance.
+simpleCompareImportSuggestion :: ImportSuggestion -> ImportSuggestion -> Ordering
+simpleCompareImportSuggestion (ImportSuggestion s1 _ i1) (ImportSuggestion s2 _ i2)
+  = flip compare s1 s2 <> compare i1 i2
+
 newtype NewImport = NewImport {unNewImport :: T.Text}
   deriving (Show, Eq, Ord)
 
@@ -1553,11 +1531,7 @@
 
 -- | find line number right after module ... where
 findPositionAfterModuleName :: Annotated ParsedSource
-#if MIN_VERSION_ghc(9,2,0)
                             -> LocatedA ModuleName
-#else
-                            -> Located ModuleName
-#endif
                             -> Maybe Int
 findPositionAfterModuleName ps hsmodName' = do
     -- Note that 'where' keyword and comments are not part of the AST. They belongs to
@@ -1578,7 +1552,7 @@
     prevSrcSpan = maybe (getLoc hsmodName') getLoc hsmodExports
 
     -- The relative position of 'where' keyword (in lines, relative to the previous AST node).
-    -- The exact-print API changed a lot in ghc-9.2, so we need to handle it seperately for different compiler versions.
+    -- The exact-print API changed a lot in ghc-9.2, so we need to handle it separately for different compiler versions.
     whereKeywordLineOffset :: Maybe Int
 #if MIN_VERSION_ghc(9,2,0)
     whereKeywordLineOffset = case hsmodAnn of
@@ -1611,7 +1585,7 @@
         deltaPos <- fmap NE.head . NE.nonEmpty .mapMaybe filterWhere $ annsDP ann
         pure $ deltaRow deltaPos
 
-    -- Before ghc 9.2, DeltaPos doesn't take comment into acccount, so we don't need to sum line offset of comments.
+    -- Before ghc 9.2, DeltaPos doesn't take comment into account, so we don't need to sum line offset of comments.
     filterWhere :: (KeywordId, DeltaPos) -> Maybe DeltaPos
     filterWhere (keywordId, deltaPos) =
         if keywordId == G AnnWhere then Just deltaPos else Nothing
@@ -1751,8 +1725,13 @@
 extractDoesNotExportModuleName :: T.Text -> Maybe T.Text
 extractDoesNotExportModuleName x
   | Just [m] <-
+#if MIN_VERSION_ghc(9,4,0)
+    matchRegexUnifySpaces x "the module ‘([^’]*)’ does not export"
+      <|> matchRegexUnifySpaces x "nor ‘([^’]*)’ export"
+#else
     matchRegexUnifySpaces x "Module ‘([^’]*)’ does not export"
       <|> matchRegexUnifySpaces x "nor ‘([^’]*)’ exports"
+#endif
   = Just m
   | otherwise
   = Nothing
@@ -1760,73 +1739,17 @@
 
 
 mkRenameEdit :: Maybe T.Text -> Range -> T.Text -> TextEdit
-mkRenameEdit contents range name =
-    if maybeIsInfixFunction == Just True
-      then TextEdit range ("`" <> name <> "`")
-      else TextEdit range name
+mkRenameEdit contents range name
+    | maybeIsInfixFunction == Just True = TextEdit range ("`" <> name <> "`")
+    | maybeIsTemplateFunction == Just True = TextEdit range ("'" <> name)
+    | otherwise = TextEdit range name
   where
     maybeIsInfixFunction = do
       curr <- textInRange range <$> contents
       pure $ "`" `T.isPrefixOf` curr && "`" `T.isSuffixOf` curr
-
-
--- | Extract the type and surround it in parentheses except in obviously safe cases.
---
--- Inferring when parentheses are actually needed around the type signature would
--- require understanding both the precedence of the context of the hole and of
--- the signature itself. Inserting them (almost) unconditionally is ugly but safe.
-extractWildCardTypeSignature :: T.Text -> T.Text
-extractWildCardTypeSignature msg
-  | enclosed || not isApp || isToplevelSig = sig
-  | otherwise                              = "(" <> sig <> ")"
-  where
-    msgSigPart      = snd $ T.breakOnEnd "standing for " msg
-    (sig, rest)     = T.span (/='’') . T.dropWhile (=='‘') . T.dropWhile (/='‘') $ msgSigPart
-    -- If we're completing something like ‘foo :: _’ parens can be safely omitted.
-    isToplevelSig   = errorMessageRefersToToplevelHole rest
-    -- Parenthesize type applications, e.g. (Maybe Char).
-    isApp           = T.any isSpace sig
-    -- Do not add extra parentheses to lists, tuples and already parenthesized types.
-    enclosed        = not (T.null sig) && (T.head sig, T.last sig) `elem` [('(', ')'), ('[', ']')]
-
--- | Detect whether user wrote something like @foo :: _@ or @foo :: (_, Int)@.
--- The former is considered toplevel case for which the function returns 'True',
--- the latter is not toplevel and the returned value is 'False'.
---
--- When type hole is at toplevel then there’s a line starting with
--- "• In the type signature" which ends with " :: _" like in the
--- following snippet:
---
--- source/library/Language/Haskell/Brittany/Internal.hs:131:13: error:
---     • Found type wildcard ‘_’ standing for ‘HsDecl GhcPs’
---       To use the inferred type, enable PartialTypeSignatures
---     • In the type signature: decl :: _
---       In an equation for ‘splitAnnots’:
---           splitAnnots m@HsModule {hsmodAnn, hsmodDecls}
---             = undefined
---             where
---                 ann :: SrcSpanAnnA
---                 decl :: _
---                 L ann decl = head hsmodDecls
---     • Relevant bindings include
---       [REDACTED]
---
--- When type hole is not at toplevel there’s a stack of where
--- the hole was located ending with "In the type signature":
---
--- source/library/Language/Haskell/Brittany/Internal.hs:130:20: error:
---     • Found type wildcard ‘_’ standing for ‘GhcPs’
---       To use the inferred type, enable PartialTypeSignatures
---     • In the first argument of ‘HsDecl’, namely ‘_’
---       In the type ‘HsDecl _’
---       In the type signature: decl :: HsDecl _
---     • Relevant bindings include
---       [REDACTED]
-errorMessageRefersToToplevelHole :: T.Text -> Bool
-errorMessageRefersToToplevelHole msg =
-  not (T.null prefix) && " :: _" `T.isSuffixOf` T.takeWhile (/= '\n') rest
-  where
-    (prefix, rest) = T.breakOn "• In the type signature:" msg
+    maybeIsTemplateFunction = do
+      curr <- textInRange range <$> contents
+      pure $ "'" `T.isPrefixOf` curr
 
 extractRenamableTerms :: T.Text -> [T.Text]
 extractRenamableTerms msg
@@ -1915,7 +1838,19 @@
     ranges' _ = []
 
 rangesForBinding' :: String -> LIE GhcPs -> [SrcSpan]
-rangesForBinding' b (L (locA -> l) x@IEVar{}) | T.unpack (printOutputable x) == b = [l]
+#if !MIN_VERSION_ghc(9,2,0)
+rangesForBinding' b (L (locA -> l) (IEVar _ nm))
+  | L _ (IEPattern (L _ b')) <- nm
+  , T.unpack (printOutputable b') == b
+  = [l]
+#else
+rangesForBinding' b (L (locA -> l) (IEVar _ nm))
+  | L _ (IEPattern _ (L _ b')) <- nm
+  , T.unpack (printOutputable b') == b
+  = [l]
+#endif
+rangesForBinding' b (L (locA -> l) x@IEVar{})
+  | T.unpack (printOutputable x) == b = [l]
 rangesForBinding' b (L (locA -> l) x@IEThingAbs{}) | T.unpack (printOutputable x) == b = [l]
 rangesForBinding' b (L (locA -> l) (IEThingAll _ x)) | T.unpack (printOutputable x) == b = [l]
 #if !MIN_VERSION_ghc(9,2,0)
@@ -1931,29 +1866,16 @@
 #endif
 rangesForBinding' _ _ = []
 
--- | 'matchRegex' combined with 'unifySpaces'
-matchRegexUnifySpaces :: T.Text -> T.Text -> Maybe [T.Text]
-matchRegexUnifySpaces message = matchRegex (unifySpaces message)
-
 -- | 'allMatchRegex' combined with 'unifySpaces'
 allMatchRegexUnifySpaces :: T.Text -> T.Text -> Maybe [[T.Text]]
 allMatchRegexUnifySpaces message =
     allMatchRegex (unifySpaces message)
 
--- | Returns Just (the submatches) for the first capture, or Nothing.
-matchRegex :: T.Text -> T.Text -> Maybe [T.Text]
-matchRegex message regex = case message =~~ regex of
-    Just (_ :: T.Text, _ :: T.Text, _ :: T.Text, bindings) -> Just bindings
-    Nothing                                                -> Nothing
-
 -- | Returns Just (all matches) for the first capture, or Nothing.
 allMatchRegex :: T.Text -> T.Text -> Maybe [[T.Text]]
 allMatchRegex message regex = message =~~ regex
 
 
-unifySpaces :: T.Text -> T.Text
-unifySpaces    = T.unwords . T.words
-
 -- functions to help parse multiple import suggestions
 
 -- | Returns the first match if found
@@ -1991,72 +1913,3 @@
                             _            -> Nothing
   imps <- regExImports imports
   return (binding, imps)
-
--- | Possible import styles for an 'IdentInfo'.
---
--- The first 'Text' parameter corresponds to the 'rendered' field of the
--- 'IdentInfo'.
-data ImportStyle
-    = ImportTopLevel T.Text
-      -- ^ Import a top-level export from a module, e.g., a function, a type, a
-      -- class.
-      --
-      -- > import M (?)
-      --
-      -- Some exports that have a parent, like a type-class method or an
-      -- associated type/data family, can still be imported as a top-level
-      -- import.
-      --
-      -- Note that this is not the case for constructors, they must always be
-      -- imported as part of their parent data type.
-
-    | ImportViaParent T.Text T.Text
-      -- ^ Import an export (first parameter) through its parent (second
-      -- parameter).
-      --
-      -- import M (P(?))
-      --
-      -- @P@ and @?@ can be a data type and a constructor, a class and a method,
-      -- a class and an associated type/data family, etc.
-
-    | ImportAllConstructors T.Text
-      -- ^ Import all constructors for a specific data type.
-      --
-      -- import M (P(..))
-      --
-      -- @P@ can be a data type or a class.
-  deriving Show
-
-importStyles :: IdentInfo -> NonEmpty ImportStyle
-importStyles IdentInfo {parent, rendered, isDatacon}
-  | Just p <- parent
-    -- Constructors always have to be imported via their parent data type, but
-    -- methods and associated type/data families can also be imported as
-    -- top-level exports.
-  = ImportViaParent rendered p
-      :| [ImportTopLevel rendered | not isDatacon]
-      <> [ImportAllConstructors p]
-  | otherwise
-  = ImportTopLevel rendered :| []
-
--- | Used for adding new imports
-renderImportStyle :: ImportStyle -> T.Text
-renderImportStyle (ImportTopLevel x)   = x
-renderImportStyle (ImportViaParent x p@(T.uncons -> Just ('(', _))) = "type " <> p <> "(" <> x <> ")"
-renderImportStyle (ImportViaParent x p) = p <> "(" <> x <> ")"
-renderImportStyle (ImportAllConstructors p) = p <> "(..)"
-
--- | Used for extending import lists
-unImportStyle :: ImportStyle -> (Maybe String, String)
-unImportStyle (ImportTopLevel x)        = (Nothing, T.unpack x)
-unImportStyle (ImportViaParent x y)     = (Just $ T.unpack y, T.unpack x)
-unImportStyle (ImportAllConstructors x) = (Just $ T.unpack x, wildCardSymbol)
-
-
-quickFixImportKind' :: T.Text -> ImportStyle -> CodeActionKind
-quickFixImportKind' x (ImportTopLevel _) = CodeActionUnknown $ "quickfix.import." <> x <> ".list.topLevel"
-quickFixImportKind' x (ImportViaParent _ _) = CodeActionUnknown $ "quickfix.import." <> x <> ".list.withParent"
-quickFixImportKind' x (ImportAllConstructors _) = CodeActionUnknown $ "quickfix.import." <> x <> ".list.allConstructors"
-
-quickFixImportKind :: T.Text -> CodeActionKind
-quickFixImportKind x = CodeActionUnknown $ "quickfix.import." <> x
diff --git a/src/Development/IDE/Plugin/CodeAction/Args.hs b/src/Development/IDE/Plugin/CodeAction/Args.hs
--- a/src/Development/IDE/Plugin/CodeAction/Args.hs
+++ b/src/Development/IDE/Plugin/CodeAction/Args.hs
@@ -13,9 +13,12 @@
 where
 
 import           Control.Concurrent.STM.Stats                 (readTVarIO)
+import           Control.Monad.Except                         (ExceptT (..),
+                                                               runExceptT)
 import           Control.Monad.Reader
 import           Control.Monad.Trans.Maybe
-import           Data.Either                                  (fromRight)
+import           Data.Either                                  (fromRight,
+                                                               partitionEithers)
 import qualified Data.HashMap.Strict                          as Map
 import           Data.IORef.Extra
 import           Data.Maybe                                   (fromMaybe)
@@ -26,10 +29,8 @@
 import           Development.IDE.GHC.Compat
 import           Development.IDE.GHC.Compat.ExactPrint
 import           Development.IDE.GHC.ExactPrint
-#if !MIN_VERSION_ghc(9,3,0)
 import           Development.IDE.Plugin.CodeAction.ExactPrint (Rewrite,
                                                                rewriteToEdit)
-#endif
 import           Development.IDE.Plugin.TypeLenses            (GetGlobalBindingTypeSigs (GetGlobalBindingTypeSigs),
                                                                GlobalBindingTypeSigsResult)
 import           Development.IDE.Spans.LocalBindings          (Bindings)
@@ -46,7 +47,7 @@
 
 type GhcideCodeActionResult = [(CodeActionTitle, Maybe CodeActionKind, Maybe CodeActionPreferred, [TextEdit])]
 
-type GhcideCodeAction = ReaderT CodeActionArgs IO GhcideCodeActionResult
+type GhcideCodeAction = ExceptT ResponseError (ReaderT CodeActionArgs IO) GhcideCodeActionResult
 
 -------------------------------------------------------------------------------------------------
 
@@ -72,20 +73,20 @@
         Just (_, txt) -> pure txt
         _             -> pure Nothing
   caaDf <- onceIO $ fmap (ms_hspp_opts . pm_mod_summary) <$> caaParsedModule
-#if !MIN_VERSION_ghc(9,3,0)
   caaAnnSource <- onceIO $ runRule GetAnnotatedParsedSource
-#endif
   caaTmr <- onceIO $ runRule TypeCheck
   caaHar <- onceIO $ runRule GetHieAst
   caaBindings <- onceIO $ runRule GetBindings
   caaGblSigs <- onceIO $ runRule GetGlobalBindingTypeSigs
-  liftIO $
-    concat
-      <$> sequence
-        [ runReaderT codeAction caa
+  results <- liftIO $
+
+      sequence
+        [ runReaderT (runExceptT codeAction) caa
           | caaDiagnostic <- diags,
             let caa = CodeActionArgs {..}
         ]
+  let (errs, successes) = partitionEithers results
+  pure $ concat successes
 
 mkCA :: T.Text -> Maybe CodeActionKind -> Maybe Bool -> [Diagnostic] -> WorkspaceEdit -> (Command |? CodeAction)
 mkCA title kind isPreferred diags edit =
@@ -117,7 +118,6 @@
 instance ToTextEdit TextEdit where
   toTextEdit _ = pure . pure
 
-#if !MIN_VERSION_ghc(9,3,0)
 instance ToTextEdit Rewrite where
   toTextEdit CodeActionArgs {..} rw = fmap (fromMaybe []) $
     runMaybeT $ do
@@ -129,7 +129,6 @@
       let r = rewriteToEdit df rw
 #endif
       pure $ fromRight [] r
-#endif
 
 instance ToTextEdit a => ToTextEdit [a] where
   toTextEdit caa = foldMap (toTextEdit caa)
@@ -149,11 +148,7 @@
     caaParsedModule :: IO (Maybe ParsedModule),
     caaContents     :: IO (Maybe T.Text),
     caaDf           :: IO (Maybe DynFlags),
-#if MIN_VERSION_ghc(9,3,0)
-    caaAnnSource    :: IO (Maybe ParsedSource),
-#else
     caaAnnSource    :: IO (Maybe (Annotated ParsedSource)),
-#endif
     caaTmr          :: IO (Maybe TcModuleResult),
     caaHar          :: IO (Maybe HieAstResult),
     caaBindings     :: IO (Maybe Bindings),
@@ -194,44 +189,49 @@
 instance ToCodeAction a => ToCodeAction (Maybe a) where
   toCodeAction = maybe (pure []) toCodeAction
 
+instance ToCodeAction a => ToCodeAction (Either ResponseError a) where
+  toCodeAction = either (\err -> ExceptT $ ReaderT $ \_ -> pure $ Left err) toCodeAction
+
 instance ToTextEdit a => ToCodeAction (CodeActionTitle, a) where
-  toCodeAction (title, te) = ReaderT $ \caa -> pure . (title,Just CodeActionQuickFix,Nothing,) <$> toTextEdit caa te
+  toCodeAction (title, te) = ExceptT $ ReaderT $ \caa -> Right . pure . (title,Just CodeActionQuickFix,Nothing,) <$> toTextEdit caa te
 
 instance ToTextEdit a => ToCodeAction (CodeActionTitle, CodeActionKind, a) where
-  toCodeAction (title, kind, te) = ReaderT $ \caa -> pure . (title,Just kind,Nothing,) <$> toTextEdit caa te
+  toCodeAction (title, kind, te) = ExceptT $ ReaderT $ \caa -> Right . pure . (title,Just kind,Nothing,) <$> toTextEdit caa te
 
 instance ToTextEdit a => ToCodeAction (CodeActionTitle, CodeActionPreferred, a) where
-  toCodeAction (title, isPreferred, te) = ReaderT $ \caa -> pure . (title,Just CodeActionQuickFix,Just isPreferred,) <$> toTextEdit caa te
+  toCodeAction (title, isPreferred, te) = ExceptT $ ReaderT $ \caa -> Right . pure . (title,Just CodeActionQuickFix,Just isPreferred,) <$> toTextEdit caa te
 
 instance ToTextEdit a => ToCodeAction (CodeActionTitle, CodeActionKind, CodeActionPreferred, a) where
-  toCodeAction (title, kind, isPreferred, te) = ReaderT $ \caa -> pure . (title,Just kind,Just isPreferred,) <$> toTextEdit caa te
+  toCodeAction (title, kind, isPreferred, te) = ExceptT $ ReaderT $ \caa -> Right . pure . (title,Just kind,Just isPreferred,) <$> toTextEdit caa te
 
 -------------------------------------------------------------------------------------------------
 
 toCodeAction1 :: (ToCodeAction r) => (CodeActionArgs -> IO (Maybe a)) -> (Maybe a -> r) -> GhcideCodeAction
-toCodeAction1 get f = ReaderT $ \caa -> get caa >>= flip runReaderT caa . toCodeAction . f
+toCodeAction1 get f = ExceptT . ReaderT $ \caa -> do
+                          caaMay <- get caa
+                          flip runReaderT caa . runExceptT . toCodeAction . f $ caaMay
 
 toCodeAction2 :: (ToCodeAction r) => (CodeActionArgs -> IO (Maybe a)) -> (a -> r) -> GhcideCodeAction
-toCodeAction2 get f = ReaderT $ \caa ->
+toCodeAction2 get f = ExceptT . ReaderT $ \caa ->
   get caa >>= \case
-    Just x -> flip runReaderT caa . toCodeAction . f $ x
-    _      -> pure []
+    Just x -> flip runReaderT caa . runExceptT . toCodeAction . f $ x
+    _      -> pure $ Right []
 
 toCodeAction3 :: (ToCodeAction r) => (CodeActionArgs -> IO a) -> (a -> r) -> GhcideCodeAction
-toCodeAction3 get f = ReaderT $ \caa -> get caa >>= flip runReaderT caa . toCodeAction . f
+toCodeAction3 get f = ExceptT . ReaderT $ \caa -> get caa >>= flip runReaderT caa . runExceptT . toCodeAction . f
 
 -- | this instance returns a delta AST, useful for exactprint transforms
 instance ToCodeAction r => ToCodeAction (ParsedSource -> r) where
 #if !MIN_VERSION_ghc(9,3,0)
-  toCodeAction f = ReaderT $ \caa@CodeActionArgs {caaAnnSource = x} ->
+  toCodeAction f = ExceptT . ReaderT $ \caa@CodeActionArgs {caaAnnSource = x} ->
     x >>= \case
-      Just s -> flip runReaderT caa . toCodeAction . f . astA $ s
-      _      -> pure []
+      Just s -> flip runReaderT caa . runExceptT . toCodeAction . f . astA $ s
+      _      -> pure $ Right []
 #else
-  toCodeAction f = ReaderT $ \caa@CodeActionArgs {caaParsedModule = x} ->
+  toCodeAction f = ExceptT . ReaderT $ \caa@CodeActionArgs {caaParsedModule = x} ->
     x >>= \case
-      Just s -> flip runReaderT caa . toCodeAction . f . pm_parsed_source $ s
-      _      -> pure []
+      Just s -> flip runReaderT caa . runExceptT . toCodeAction . f . pm_parsed_source $ s
+      _      -> pure $ Right []
 #endif
 
 instance ToCodeAction r => ToCodeAction (ExportsMap -> r) where
@@ -241,7 +241,7 @@
   toCodeAction = toCodeAction3 caaIdeOptions
 
 instance ToCodeAction r => ToCodeAction (Diagnostic -> r) where
-  toCodeAction f = ReaderT $ \caa@CodeActionArgs {caaDiagnostic = x} -> flip runReaderT caa . toCodeAction $ f x
+  toCodeAction f = ExceptT . ReaderT $ \caa@CodeActionArgs {caaDiagnostic = x} -> flip runReaderT caa . runExceptT . toCodeAction $ f x
 
 instance ToCodeAction r => ToCodeAction (Maybe ParsedModule -> r) where
   toCodeAction = toCodeAction1 caaParsedModule
@@ -261,13 +261,11 @@
 instance ToCodeAction r => ToCodeAction (DynFlags -> r) where
   toCodeAction = toCodeAction2 caaDf
 
-#if !MIN_VERSION_ghc(9,3,0)
 instance ToCodeAction r => ToCodeAction (Maybe (Annotated ParsedSource) -> r) where
   toCodeAction = toCodeAction1 caaAnnSource
 
 instance ToCodeAction r => ToCodeAction (Annotated ParsedSource -> r) where
   toCodeAction = toCodeAction2 caaAnnSource
-#endif
 
 instance ToCodeAction r => ToCodeAction (Maybe TcModuleResult -> r) where
   toCodeAction = toCodeAction1 caaTmr
diff --git a/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs b/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs
--- a/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs
+++ b/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs
@@ -48,7 +48,8 @@
                                  IsUnicodeSyntax (NormalSyntax),
                                  NameAdornment (NameParens),
                                  TrailingAnn (AddCommaAnn), addAnns, ann,
-                                 emptyComments, reAnnL)
+                                 emptyComments, noSrcSpanA, reAnnL)
+import Language.Haskell.GHC.ExactPrint.ExactPrint      (makeDeltaAst, showAst)
 #else
 import           Control.Applicative                   (Alternative ((<|>)))
 import           Control.Monad.Extra                   (whenJust)
@@ -62,6 +63,7 @@
                                                         KeywordId (G), mkAnnKey)
 #endif
 
+
 ------------------------------------------------------------------------------
 
 -- | Construct a 'Rewrite', replacing the node at the given 'SrcSpan' with the
@@ -196,26 +198,30 @@
 removeConstraint toRemove = go . traceAst "REMOVE_CONSTRAINT_input"
   where
     go :: LHsType GhcPs -> Rewrite
-#if !MIN_VERSION_ghc(9,2,0)
-    go (L l it@HsQualTy{hst_ctxt = L l' ctxt, hst_body}) = Rewrite (locA l) $ \_ -> do
-#else
+#if MIN_VERSION_ghc(9,2,0) && !MIN_VERSION_ghc(9,4,0)
     go (L l it@HsQualTy{hst_ctxt = Just (L l' ctxt), hst_body}) = Rewrite (locA l) $ \_ -> do
+#else
+    go (L l it@HsQualTy{hst_ctxt = L l' ctxt, hst_body}) = Rewrite (locA l) $ \_ -> do
 #endif
       let ctxt' = filter (not . toRemove) ctxt
           removeStuff = (toRemove <$> headMaybe ctxt) == Just True
-#if !MIN_VERSION_ghc(9,2,0)
-      when removeStuff  $
-        setEntryDPT hst_body (DP (0, 0))
-      return $ L l $ it{hst_ctxt =  L l' ctxt'}
-#else
+#if MIN_VERSION_ghc(9,2,0)
       let hst_body' = if removeStuff then resetEntryDP hst_body else hst_body
       return $ case ctxt' of
           [] -> hst_body'
           _ -> do
             let ctxt'' = over _last (first removeComma) ctxt'
+#if MIN_VERSION_ghc(9,4,0)
+            L l $ it{ hst_ctxt = L l' ctxt''
+#else
             L l $ it{ hst_ctxt = Just $ L l' ctxt''
+#endif
                     , hst_body = hst_body'
                     }
+#else
+      when removeStuff  $
+        setEntryDPT hst_body (DP (0, 0))
+      return $ L l $ it{hst_ctxt =  L l' ctxt'}
 #endif
     go (L _ (HsParTy _ ty)) = go ty
     go (L _ HsForAllTy{hst_body}) = go hst_body
@@ -231,10 +237,12 @@
   Rewrite
 appendConstraint constraintT = go . traceAst "appendConstraint"
  where
-#if !MIN_VERSION_ghc(9,2,0)
+#if MIN_VERSION_ghc(9,4,0)
   go (L l it@HsQualTy{hst_ctxt = L l' ctxt}) = Rewrite (locA l) $ \df -> do
-#else
+#elif MIN_VERSION_ghc(9,2,0)
   go (L l it@HsQualTy{hst_ctxt = Just (L l' ctxt)}) = Rewrite (locA l) $ \df -> do
+#else
+  go (L l it@HsQualTy{hst_ctxt = L l' ctxt}) = Rewrite (locA l) $ \df -> do
 #endif
     constraint <- liftParseAST df constraintT
 #if !MIN_VERSION_ghc(9,2,0)
@@ -258,8 +266,12 @@
             [L _ (HsParTy EpAnn{anns=AnnParen{ap_close}} _)] -> Just ap_close
             _ -> Nothing
         ctxt' = over _last (first addComma) $ map dropHsParTy ctxt
+#if MIN_VERSION_ghc(9,4,0)
+    return $ L l $ it{hst_ctxt = L l'' $ ctxt' ++ [constraint]}
+#else
     return $ L l $ it{hst_ctxt = Just $ L l'' $ ctxt' ++ [constraint]}
 #endif
+#endif
   go (L _ HsForAllTy{hst_body}) = go hst_body
   go (L _ (HsParTy _ ty)) = go ty
   go ast@(L l _) = Rewrite (locA l) $ \df -> do
@@ -267,7 +279,16 @@
     constraint <- liftParseAST df constraintT
     lContext <- uniqueSrcSpanT
     lTop <- uniqueSrcSpanT
-#if !MIN_VERSION_ghc(9,2,0)
+#if MIN_VERSION_ghc(9,2,0)
+#if MIN_VERSION_ghc(9,4,0)
+    let context = reAnnL annCtxt emptyComments $ L lContext [resetEntryDP constraint]
+#else
+    let context = Just $ reAnnL annCtxt emptyComments $ L lContext [resetEntryDP constraint]
+#endif
+        annCtxt = AnnContext (Just (NormalSyntax, epl 1)) [epl 0 | needsParens] [epl 0 | needsParens]
+        needsParens = hsTypeNeedsParens sigPrec $ unLoc constraint
+    ast <- pure $ setEntryDP ast (SameLine 1)
+#else
     let context = L lContext [constraint]
     addSimpleAnnT context dp00 $
       (G AnnDarrow, DP (0, 1)) :
@@ -277,11 +298,6 @@
           ]
         | hsTypeNeedsParens sigPrec $ unLoc constraint
         ]
-#else
-    let context = Just $ reAnnL annCtxt emptyComments $ L lContext [resetEntryDP constraint]
-        annCtxt = AnnContext (Just (NormalSyntax, epl 1)) [epl 0 | needsParens] [epl 0 | needsParens]
-        needsParens = hsTypeNeedsParens sigPrec $ unLoc constraint
-    ast <- pure $ setEntryDP ast (SameLine 1)
 #endif
 
     return $ reLocA $ L lTop $ HsQualTy noExtField context ast
@@ -336,8 +352,16 @@
   Rewrite (locA l) $ \df -> do
     case mparent of
       -- This will also work for `ImportAllConstructors`
+#if !MIN_VERSION_ghc(9,2,0)
       Just parent -> extendImportViaParent df parent identifier lDecl
       _           -> extendImportTopLevel identifier lDecl
+#else
+      -- Parsed source in GHC 9.4 uses absolute position annotation (RealSrcSpan),
+      -- while rewriting relies on relative positions. ghc-exactprint has the utility
+      -- makeDeltaAst for relativization.
+      Just parent -> extendImportViaParent df parent identifier (makeDeltaAst lDecl)
+      _           -> extendImportTopLevel identifier (makeDeltaAst lDecl)
+#endif
 
 -- | Add an identifier or a data type to import list. Expects a Delta AST
 --
@@ -385,7 +409,7 @@
             nodeHasComma x = isJust $ Map.lookup (mkAnnKey x) anns >>= find isAnnComma . annsDP
         when shouldAddTrailingComma (addTrailingCommaT x)
 
-        -- Parens are attachted to `lies`, so if `lies` was empty previously,
+        -- Parens are attached to `lies`, so if `lies` was empty previously,
         -- we need change the ann key from `[]` to `:` to keep parens and other anns.
         unless hasSibling $
           transferAnn (L l' lies) (L l' [x]) id
@@ -435,7 +459,7 @@
           childLIE = reLocA $ L srcChild $ IEName childRdr
 #if !MIN_VERSION_ghc(9,2,0)
           x :: LIE GhcPs = L ll' $ IEThingWith noExtField absIE NoIEWildcard [childLIE] []
-      -- take anns from ThingAbs, and attatch parens to it
+      -- take anns from ThingAbs, and attach parens to it
       transferAnn lAbs x $ \old -> old{annsDP = annsDP old ++ [(G AnnOpenP, DP (0, 1)), (G AnnCloseP, dp00)]}
       addSimpleAnnT childRdr dp00 [(G AnnVal, dp00)]
 #else
@@ -506,7 +530,7 @@
 #else
       let parentLIE = reLocA $ L srcParent $ (if isParentOperator then IEType (epl 0) parentRdr' else IEName parentRdr')
           parentRdr' = modifyAnns parentRdr $ \case
-              it@NameAnn{nann_adornment = NameParens} -> it{nann_open = epl 1}
+              it@NameAnn{nann_adornment = NameParens} -> it{nann_open = epl 1, nann_close = epl 0}
               other -> other
           childLIE = reLocA $ L srcChild $ IEName childRdr
 #endif
@@ -518,7 +542,7 @@
       addSimpleAnnT parentRdr (DP (0, if hasSibling then 1 else 0)) $ unqalDP 1 isParentOperator
       addSimpleAnnT childRdr (DP (0, 0)) [(G AnnVal, dp00)]
       addSimpleAnnT x (DP (0, 0)) [(G AnnOpenP, DP (0, 1)), (G AnnCloseP, DP (0, 0))]
-      -- Parens are attachted to `pre`, so if `pre` was empty previously,
+      -- Parens are attached to `pre`, so if `pre` was empty previously,
       -- we need change the ann key from `[]` to `:` to keep parens and other anns.
       unless hasSibling $
         transferAnn (L l' $ reverse pre) (L l' [x]) id
@@ -538,7 +562,7 @@
 addCommaInImportList ::
   -- | Initial list
   [LocatedAn AnnListItem a]
-  -- | Additionnal item
+  -- | Additional item
   -> LocatedAn AnnListItem a
   -> [LocatedAn AnnListItem a]
 addCommaInImportList lies x =
diff --git a/src/Development/IDE/Plugin/CodeAction/Util.hs b/src/Development/IDE/Plugin/CodeAction/Util.hs
--- a/src/Development/IDE/Plugin/CodeAction/Util.hs
+++ b/src/Development/IDE/Plugin/CodeAction/Util.hs
@@ -1,23 +1,24 @@
 module Development.IDE.Plugin.CodeAction.Util where
 
-#if MIN_VERSION_ghc(9,2,0)
-import           GHC.Utils.Outputable
-#else
-import           Development.IDE.GHC.Util
-import           Development.IDE.GHC.Compat.Util
-import           Development.IDE.GHC.Compat
-#endif
-import           Data.Data                         (Data)
-import qualified Data.Unique                       as U
+import           Data.Data                             (Data)
+import           Data.Time.Clock.POSIX                 (POSIXTime,
+                                                        getCurrentTime,
+                                                        utcTimeToPOSIXSeconds)
+import qualified Data.Unique                           as U
 import           Debug.Trace
 import           Development.IDE.GHC.Compat.ExactPrint as GHC
+import           Development.IDE.GHC.Dump              (showAstDataHtml)
 import           GHC.Stack
-import           System.Environment.Blank          (getEnvDefault)
+import           System.Environment.Blank              (getEnvDefault)
 import           System.IO.Unsafe
 import           Text.Printf
-import           Development.IDE.GHC.Dump          (showAstDataHtml)
-import           Data.Time.Clock.POSIX             (POSIXTime, getCurrentTime,
-                                                    utcTimeToPOSIXSeconds)
+#if MIN_VERSION_ghc(9,2,0)
+import           GHC.Utils.Outputable
+#else
+import           Development.IDE.GHC.Compat
+import           Development.IDE.GHC.Compat.Util
+import           Development.IDE.GHC.Util
+#endif
 --------------------------------------------------------------------------------
 -- Tracing exactprint terms
 
diff --git a/src/Development/IDE/Plugin/Plugins/AddArgument.hs b/src/Development/IDE/Plugin/Plugins/AddArgument.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/IDE/Plugin/Plugins/AddArgument.hs
@@ -0,0 +1,167 @@
+{-# LANGUAGE CPP #-}
+module Development.IDE.Plugin.Plugins.AddArgument (plugin) where
+
+#if MIN_VERSION_ghc(9,4,0)
+import           Development.IDE.GHC.ExactPrint            (epl)
+import           GHC.Parser.Annotation                     (TokenLocation (..))
+#endif
+#if !MIN_VERSION_ghc(9,2,1)
+import qualified Data.Text                                 as T
+import           Language.LSP.Types
+#else
+import           Control.Monad                             (join)
+import           Control.Monad.Except                      (lift)
+import           Data.Bifunctor                            (Bifunctor (..))
+import           Data.Either.Extra                         (maybeToEither)
+import qualified Data.Text                                 as T
+import           Development.IDE.GHC.Compat
+import           Development.IDE.GHC.Compat.ExactPrint     (exactPrint,
+                                                            makeDeltaAst)
+import           Development.IDE.GHC.Error                 (spanContainsRange)
+import           Development.IDE.GHC.ExactPrint            (genAnchor1,
+                                                            modifyMgMatchesT',
+                                                            modifySigWithM,
+                                                            modifySmallestDeclWithM)
+import           Development.IDE.Plugin.Plugins.Diagnostic
+import           GHC                                       (EpAnn (..),
+                                                            SrcSpanAnn' (SrcSpanAnn),
+                                                            SrcSpanAnnA,
+                                                            SrcSpanAnnN,
+                                                            TrailingAnn (..),
+                                                            emptyComments,
+                                                            noAnn)
+import           GHC.Hs                                    (IsUnicodeSyntax (..))
+import           GHC.Types.SrcLoc                          (generatedSrcSpan)
+import           Ide.PluginUtils                           (makeDiffTextEdit,
+                                                            responseError)
+import           Language.Haskell.GHC.ExactPrint           (TransformT,
+                                                            noAnnSrcSpanDP1,
+                                                            runTransformT)
+import           Language.Haskell.GHC.ExactPrint.Transform (d1)
+import           Language.LSP.Types
+#endif
+
+#if !MIN_VERSION_ghc(9,2,1)
+plugin :: [(T.Text, [TextEdit])]
+plugin = []
+#else
+-- When GHC tells us that a variable is not bound, it will tell us either:
+--  - there is an unbound variable with a given type
+--  - there is an unbound variable (GHC provides no type suggestion)
+--
+-- When we receive either of these errors, we produce a text edit that will add a new argument (as a new pattern in the
+-- last position of each LHS of the top-level bindings for this HsDecl).
+--
+-- NOTE When adding a new argument to a declaration, the corresponding argument's type in declaration's signature might
+--      not be the last type in the signature, such as:
+--         foo :: a -> b -> c -> d
+--         foo a b = \c -> ...
+--      In this case a new argument would have to add its type between b and c in the signature.
+plugin :: ParsedModule -> Diagnostic -> Either ResponseError [(T.Text, [TextEdit])]
+plugin parsedModule Diagnostic {_message, _range}
+  | Just (name, typ) <- matchVariableNotInScope message = addArgumentAction parsedModule _range name typ
+  | Just (name, typ) <- matchFoundHoleIncludeUnderscore message = addArgumentAction parsedModule _range name (Just typ)
+  | otherwise = pure []
+  where
+    message = unifySpaces _message
+
+-- Given a name for the new binding, add a new pattern to the match in the last position,
+-- returning how many patterns there were in this match prior to the transformation:
+--      addArgToMatch "foo" `bar arg1 arg2 = ...`
+--   => (`bar arg1 arg2 foo = ...`, 2)
+addArgToMatch :: T.Text -> GenLocated l (Match GhcPs body) -> (GenLocated l (Match GhcPs body), Int)
+addArgToMatch name (L locMatch (Match xMatch ctxMatch pats rhs)) =
+  let unqualName = mkRdrUnqual $ mkVarOcc $ T.unpack name
+      newPat = L (noAnnSrcSpanDP1 generatedSrcSpan) $ VarPat NoExtField (noLocA unqualName)
+  in (L locMatch (Match xMatch ctxMatch (pats <> [newPat]) rhs), Prelude.length pats)
+
+-- Attempt to insert a binding pattern into each match for the given LHsDecl; succeeds only if the function is a FunBind.
+-- Also return:
+--   - the declaration's name
+--   - the number of bound patterns in the declaration's matches prior to the transformation
+--
+-- For example:
+--    insertArg "new_pat" `foo bar baz = 1`
+-- => (`foo bar baz new_pat = 1`, Just ("foo", 2))
+appendFinalPatToMatches :: T.Text -> LHsDecl GhcPs -> TransformT (Either ResponseError) (LHsDecl GhcPs, Maybe (GenLocated SrcSpanAnnN RdrName, Int))
+appendFinalPatToMatches name = \case
+  (L locDecl (ValD xVal (FunBind xFunBind idFunBind mg coreFunBind))) -> do
+    (mg', numPatsMay) <- modifyMgMatchesT' mg (pure . second Just . addArgToMatch name) Nothing combineMatchNumPats
+    numPats <- lift $ maybeToEither (responseError "Unexpected empty match group in HsDecl") numPatsMay
+    let decl' = L locDecl (ValD xVal (FunBind xFunBind idFunBind mg' coreFunBind))
+    pure (decl', Just (idFunBind, numPats))
+  decl -> pure (decl, Nothing)
+  where
+    combineMatchNumPats  Nothing other = pure other
+    combineMatchNumPats  other Nothing = pure other
+    combineMatchNumPats  (Just l) (Just r)
+      | l == r = pure (Just l)
+      | otherwise = Left $ responseError "Unexpected different numbers of patterns in HsDecl MatchGroup"
+
+-- The add argument works as follows:
+--  1. Attempt to add the given name as the last pattern of the declaration that contains `range`.
+--  2. If such a declaration exists, use that declaration's name to modify the signature of said declaration, if it
+--     has a type signature.
+--
+-- NOTE For the following situation, the type signature is not updated (it's unclear what should happen):
+--   type FunctionTySyn = () -> Int
+--   foo :: FunctionTySyn
+--   foo () = new_def
+--
+-- TODO instead of inserting a typed hole; use GHC's suggested type from the error
+addArgumentAction :: ParsedModule -> Range -> T.Text -> Maybe T.Text -> Either ResponseError [(T.Text, [TextEdit])]
+addArgumentAction (ParsedModule _ moduleSrc _ _) range name _typ = do
+    (newSource, _, _) <- runTransformT $ do
+      (moduleSrc', join -> matchedDeclNameMay) <- addNameAsLastArgOfMatchingDecl (makeDeltaAst moduleSrc)
+      case matchedDeclNameMay of
+          Just (matchedDeclName, numPats) -> modifySigWithM (unLoc matchedDeclName) (addTyHoleToTySigArg numPats) moduleSrc'
+          Nothing -> pure moduleSrc'
+    let diff = makeDiffTextEdit (T.pack $ exactPrint moduleSrc) (T.pack $ exactPrint newSource)
+    pure [("Add argument ‘" <> name <> "’ to function", fromLspList diff)]
+  where
+    addNameAsLastArgOfMatchingDecl = modifySmallestDeclWithM spanContainsRangeOrErr addNameAsLastArg
+    addNameAsLastArg = fmap (first (:[])) . appendFinalPatToMatches name
+
+    spanContainsRangeOrErr = maybeToEither (responseError "SrcSpan was not valid range") . (`spanContainsRange` range)
+
+-- Transform an LHsType into a list of arguments and return type, to make transformations easier.
+hsTypeToFunTypeAsList :: LHsType GhcPs -> ([(SrcSpanAnnA, XFunTy GhcPs, HsArrow GhcPs, LHsType GhcPs)], LHsType GhcPs)
+hsTypeToFunTypeAsList = \case
+  L spanAnnA (HsFunTy xFunTy arrow lhs rhs) ->
+    let (rhsArgs, rhsRes) = hsTypeToFunTypeAsList rhs
+    in ((spanAnnA, xFunTy, arrow, lhs):rhsArgs, rhsRes)
+  ty -> ([], ty)
+
+-- The inverse of `hsTypeToFunTypeAsList`
+hsTypeFromFunTypeAsList :: ([(SrcSpanAnnA, XFunTy GhcPs, HsArrow GhcPs, LHsType GhcPs)], LHsType GhcPs) -> LHsType GhcPs
+hsTypeFromFunTypeAsList (args, res) =
+  foldr (\(spanAnnA, xFunTy, arrow, argTy) res -> L spanAnnA $ HsFunTy xFunTy arrow argTy res) res args
+
+-- Add a typed hole to a type signature in the given argument position:
+--   0 `foo :: ()` => foo :: _ -> ()
+--   2 `foo :: FunctionTySyn` => foo :: FunctionTySyn
+--   1 `foo :: () -> () -> Int` => foo :: () -> _ -> () -> Int
+addTyHoleToTySigArg :: Int -> LHsSigType GhcPs -> (LHsSigType GhcPs)
+addTyHoleToTySigArg loc (L annHsSig (HsSig xHsSig tyVarBndrs lsigTy)) =
+    let (args, res) = hsTypeToFunTypeAsList lsigTy
+#if MIN_VERSION_ghc(9,4,0)
+        wildCardAnn = SrcSpanAnn (EpAnn genAnchor1 (AnnListItem []) emptyComments) generatedSrcSpan
+        arrowAnn = TokenLoc (epl 1)
+        newArg = (SrcSpanAnn mempty generatedSrcSpan, noAnn, HsUnrestrictedArrow (L arrowAnn HsNormalTok), L wildCardAnn $ HsWildCardTy noExtField)
+#else
+        wildCardAnn = SrcSpanAnn (EpAnn genAnchor1 (AnnListItem [AddRarrowAnn d1]) emptyComments) generatedSrcSpan
+        newArg = (SrcSpanAnn mempty generatedSrcSpan, noAnn, HsUnrestrictedArrow NormalSyntax, L wildCardAnn $ HsWildCardTy noExtField)
+#endif
+        -- NOTE if the location that the argument wants to be placed at is not one more than the number of arguments
+        --      in the signature, then we return the original type signature.
+        --      This situation most likely occurs due to a function type synonym in the signature
+        insertArg n _ | n < 0 = error "Not possible"
+        insertArg 0 as = newArg:as
+        insertArg _ [] = []
+        insertArg n (a:as) = a : insertArg (n - 1) as
+        lsigTy' = hsTypeFromFunTypeAsList (insertArg loc args, res)
+    in L annHsSig (HsSig xHsSig tyVarBndrs lsigTy')
+
+fromLspList :: List a -> [a]
+fromLspList (List a) = a
+#endif
diff --git a/src/Development/IDE/Plugin/Plugins/Diagnostic.hs b/src/Development/IDE/Plugin/Plugins/Diagnostic.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/IDE/Plugin/Plugins/Diagnostic.hs
@@ -0,0 +1,53 @@
+module Development.IDE.Plugin.Plugins.Diagnostic (
+  matchVariableNotInScope,
+  matchRegexUnifySpaces,
+  unifySpaces,
+  matchFoundHole,
+  matchFoundHoleIncludeUnderscore,
+  )
+  where
+
+import           Data.Bifunctor  (Bifunctor (..))
+import qualified Data.Text       as T
+import           Text.Regex.TDFA ((=~~))
+
+unifySpaces :: T.Text -> T.Text
+unifySpaces    = T.unwords . T.words
+
+-- | Returns Just (the submatches) for the first capture, or Nothing.
+matchRegex :: T.Text -> T.Text -> Maybe [T.Text]
+matchRegex message regex = case message =~~ regex of
+    Just (_ :: T.Text, _ :: T.Text, _ :: T.Text, bindings) -> Just bindings
+    Nothing                                                -> Nothing
+
+-- | 'matchRegex' combined with 'unifySpaces'
+matchRegexUnifySpaces :: T.Text -> T.Text -> Maybe [T.Text]
+matchRegexUnifySpaces message = matchRegex (unifySpaces message)
+
+matchFoundHole :: T.Text -> Maybe (T.Text, T.Text)
+matchFoundHole message
+  | Just [name, typ] <- matchRegexUnifySpaces message "Found hole: _([^ ]+) :: ([^*•]+) Or perhaps" =
+      Just (name, typ)
+  | otherwise = Nothing
+
+matchFoundHoleIncludeUnderscore :: T.Text -> Maybe (T.Text, T.Text)
+matchFoundHoleIncludeUnderscore message = first ("_" <>) <$> matchFoundHole message
+
+matchVariableNotInScope :: T.Text -> Maybe (T.Text, Maybe T.Text)
+matchVariableNotInScope message
+  --     * Variable not in scope:
+  --         suggestAcion :: Maybe T.Text -> Range -> Range
+  --     * Variable not in scope:
+  --         suggestAcion
+  | Just (name, typ) <- matchVariableNotInScopeTyped message = Just (name, Just typ)
+  | Just name <- matchVariableNotInScopeUntyped message = Just (name, Nothing)
+  | otherwise = Nothing
+  where
+    matchVariableNotInScopeTyped message
+      | Just [name, typ] <- matchRegexUnifySpaces message "Variable not in scope: ([^ ]+) :: ([^*•]+)" =
+          Just (name, typ)
+      | otherwise = Nothing
+    matchVariableNotInScopeUntyped message
+      | Just [name] <- matchRegexUnifySpaces message "Variable not in scope: ([^ ]+)" =
+          Just name
+      | otherwise = Nothing
diff --git a/src/Development/IDE/Plugin/Plugins/FillHole.hs b/src/Development/IDE/Plugin/Plugins/FillHole.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/IDE/Plugin/Plugins/FillHole.hs
@@ -0,0 +1,104 @@
+module Development.IDE.Plugin.Plugins.FillHole
+  ( suggestFillHole
+  ) where
+
+import           Control.Monad                             (guard)
+import           Data.Char
+import qualified Data.Text                                 as T
+import           Development.IDE.Plugin.Plugins.Diagnostic
+import           Language.LSP.Types                        (Diagnostic (..),
+                                                            TextEdit (TextEdit))
+import           Text.Regex.TDFA                           (MatchResult (..),
+                                                            (=~))
+
+suggestFillHole :: Diagnostic -> [(T.Text, TextEdit)]
+suggestFillHole Diagnostic{_range=_range,..}
+    | Just holeName <- extractHoleName _message
+    , (holeFits, refFits) <- processHoleSuggestions (T.lines _message) =
+      let isInfixHole = _message =~ addBackticks holeName :: Bool in
+        map (proposeHoleFit holeName False isInfixHole) holeFits
+        ++ map (proposeHoleFit holeName True isInfixHole) refFits
+    | otherwise = []
+    where
+      extractHoleName = fmap (headOrThrow "impossible") . flip matchRegexUnifySpaces "Found hole: ([^ ]*)"
+      addBackticks text = "`" <> text <> "`"
+      addParens text = "(" <> text <> ")"
+      proposeHoleFit holeName parenthise isInfixHole name =
+        case T.uncons name of
+          Nothing -> error "impossible: empty name provided by ghc"
+          Just (firstChr, _) ->
+            let isInfixOperator = firstChr == '('
+                name' = getOperatorNotation isInfixHole isInfixOperator name in
+              ( "replace " <> holeName <> " with " <> name
+              , TextEdit _range (if parenthise then addParens name' else name')
+              )
+      getOperatorNotation True False name                    = addBackticks name
+      getOperatorNotation True True name                     = T.drop 1 (T.dropEnd 1 name)
+      getOperatorNotation _isInfixHole _isInfixOperator name = name
+      headOrThrow msg = \case
+        [] -> error msg
+        (x:_) -> x
+
+processHoleSuggestions :: [T.Text] -> ([T.Text], [T.Text])
+processHoleSuggestions mm = (holeSuggestions, refSuggestions)
+{-
+    • Found hole: _ :: LSP.Handlers
+
+      Valid hole fits include def
+      Valid refinement hole fits include
+        fromMaybe (_ :: LSP.Handlers) (_ :: Maybe LSP.Handlers)
+        fromJust (_ :: Maybe LSP.Handlers)
+        haskell-lsp-types-0.22.0.0:Language.LSP.Types.Window.$sel:_value:ProgressParams (_ :: ProgressParams
+                                                                                                        LSP.Handlers)
+        T.foldl (_ :: LSP.Handlers -> Char -> LSP.Handlers)
+                (_ :: LSP.Handlers)
+                (_ :: T.Text)
+        T.foldl' (_ :: LSP.Handlers -> Char -> LSP.Handlers)
+                 (_ :: LSP.Handlers)
+                 (_ :: T.Text)
+-}
+  where
+    t = id @T.Text
+    holeSuggestions = do
+      -- get the text indented under Valid hole fits
+      validHolesSection <-
+        getIndentedGroupsBy (=~ t " *Valid (hole fits|substitutions) include") mm
+      -- the Valid hole fits line can contain a hole fit
+      holeFitLine <-
+        mapHead
+            (mrAfter . (=~ t " *Valid (hole fits|substitutions) include"))
+            validHolesSection
+      let holeFit = T.strip $ T.takeWhile (/= ':') holeFitLine
+      guard (not $ T.null holeFit)
+      return holeFit
+    refSuggestions = do -- @[]
+      -- get the text indented under Valid refinement hole fits
+      refinementSection <-
+        getIndentedGroupsBy (=~ t " *Valid refinement hole fits include") mm
+      case refinementSection of
+        [] -> error "GHC provided invalid hole fit options"
+        (_:refinementSection) -> do
+          -- get the text for each hole fit
+          holeFitLines <- getIndentedGroups refinementSection
+          let holeFit = T.strip $ T.unwords holeFitLines
+          guard $ not $ holeFit =~ t "Some refinement hole fits suppressed"
+          return holeFit
+
+    mapHead f (a:aa) = f a : aa
+    mapHead _ []     = []
+
+-- > getIndentedGroups [" H1", "  l1", "  l2", " H2", "  l3"] = [[" H1,", "  l1", "  l2"], [" H2", "  l3"]]
+getIndentedGroups :: [T.Text] -> [[T.Text]]
+getIndentedGroups [] = []
+getIndentedGroups ll@(l:_) = getIndentedGroupsBy ((== indentation l) . indentation) ll
+-- |
+-- > getIndentedGroupsBy (" H" `isPrefixOf`) [" H1", "  l1", "  l2", " H2", "  l3"] = [[" H1", "  l1", "  l2"], [" H2", "  l3"]]
+getIndentedGroupsBy :: (T.Text -> Bool) -> [T.Text] -> [[T.Text]]
+getIndentedGroupsBy pred inp = case dropWhile (not.pred) inp of
+    (l:ll) -> case span (\l' -> indentation l < indentation l') ll of
+        (indented, rest) -> (l:indented) : getIndentedGroupsBy pred rest
+    _ -> []
+
+indentation :: T.Text -> Int
+indentation = T.length . T.takeWhile isSpace
+
diff --git a/src/Development/IDE/Plugin/Plugins/FillTypeWildcard.hs b/src/Development/IDE/Plugin/Plugins/FillTypeWildcard.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/IDE/Plugin/Plugins/FillTypeWildcard.hs
@@ -0,0 +1,78 @@
+module Development.IDE.Plugin.Plugins.FillTypeWildcard
+  ( suggestFillTypeWildcard
+  ) where
+
+import           Data.Char
+import qualified Data.Text          as T
+import           Language.LSP.Types (Diagnostic (..), TextEdit (TextEdit))
+
+suggestFillTypeWildcard :: Diagnostic -> [(T.Text, TextEdit)]
+suggestFillTypeWildcard Diagnostic{_range=_range,..}
+-- Foo.hs:3:8: error:
+--     * Found type wildcard `_' standing for `p -> p1 -> p'
+    | "Found type wildcard" `T.isInfixOf` _message
+    , " standing for " `T.isInfixOf` _message
+    , typeSignature <- extractWildCardTypeSignature _message
+        =  [("Use type signature: ‘" <> typeSignature <> "’", TextEdit _range typeSignature)]
+    | otherwise = []
+
+-- | Extract the type and surround it in parentheses except in obviously safe cases.
+--
+-- Inferring when parentheses are actually needed around the type signature would
+-- require understanding both the precedence of the context of the hole and of
+-- the signature itself. Inserting them (almost) unconditionally is ugly but safe.
+extractWildCardTypeSignature :: T.Text -> T.Text
+extractWildCardTypeSignature msg
+  | enclosed || not isApp || isToplevelSig = sig
+  | otherwise                              = "(" <> sig <> ")"
+  where
+    msgSigPart      = snd $ T.breakOnEnd "standing for " msg
+    (sig, rest)     = T.span (/='’') . T.dropWhile (=='‘') . T.dropWhile (/='‘') $ msgSigPart
+    -- If we're completing something like ‘foo :: _’ parens can be safely omitted.
+    isToplevelSig   = errorMessageRefersToToplevelHole rest
+    -- Parenthesize type applications, e.g. (Maybe Char).
+    isApp           = T.any isSpace sig
+    -- Do not add extra parentheses to lists, tuples and already parenthesized types.
+    enclosed        =
+      case T.uncons sig of
+        Nothing -> error "GHC provided invalid type"
+        Just (firstChr, _) -> not (T.null sig) && (firstChr, T.last sig) `elem` [('(', ')'), ('[', ']')]
+
+-- | Detect whether user wrote something like @foo :: _@ or @foo :: (_, Int)@.
+-- The former is considered toplevel case for which the function returns 'True',
+-- the latter is not toplevel and the returned value is 'False'.
+--
+-- When type hole is at toplevel then there’s a line starting with
+-- "• In the type signature" which ends with " :: _" like in the
+-- following snippet:
+--
+-- source/library/Language/Haskell/Brittany/Internal.hs:131:13: error:
+--     • Found type wildcard ‘_’ standing for ‘HsDecl GhcPs’
+--       To use the inferred type, enable PartialTypeSignatures
+--     • In the type signature: decl :: _
+--       In an equation for ‘splitAnnots’:
+--           splitAnnots m@HsModule {hsmodAnn, hsmodDecls}
+--             = undefined
+--             where
+--                 ann :: SrcSpanAnnA
+--                 decl :: _
+--                 L ann decl = head hsmodDecls
+--     • Relevant bindings include
+--       [REDACTED]
+--
+-- When type hole is not at toplevel there’s a stack of where
+-- the hole was located ending with "In the type signature":
+--
+-- source/library/Language/Haskell/Brittany/Internal.hs:130:20: error:
+--     • Found type wildcard ‘_’ standing for ‘GhcPs’
+--       To use the inferred type, enable PartialTypeSignatures
+--     • In the first argument of ‘HsDecl’, namely ‘_’
+--       In the type ‘HsDecl _’
+--       In the type signature: decl :: HsDecl _
+--     • Relevant bindings include
+--       [REDACTED]
+errorMessageRefersToToplevelHole :: T.Text -> Bool
+errorMessageRefersToToplevelHole msg =
+  not (T.null prefix) && " :: _" `T.isSuffixOf` T.takeWhile (/= '\n') rest
+  where
+    (prefix, rest) = T.breakOn "• In the type signature:" msg
diff --git a/src/Development/IDE/Plugin/Plugins/ImportUtils.hs b/src/Development/IDE/Plugin/Plugins/ImportUtils.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/IDE/Plugin/Plugins/ImportUtils.hs
@@ -0,0 +1,85 @@
+module Development.IDE.Plugin.Plugins.ImportUtils
+  ( ImportStyle(..),
+    quickFixImportKind',
+    quickFixImportKind,
+    renderImportStyle,
+    unImportStyle,
+    importStyles
+  ) where
+
+import           Data.List.NonEmpty                           (NonEmpty ((:|)))
+import qualified Data.Text                                    as T
+import           Development.IDE.Plugin.CodeAction.ExactPrint (wildCardSymbol)
+import           Development.IDE.Types.Exports
+import           Language.LSP.Types                           (CodeActionKind (..))
+
+-- | Possible import styles for an 'IdentInfo'.
+--
+-- The first 'Text' parameter corresponds to the 'rendered' field of the
+-- 'IdentInfo'.
+data ImportStyle
+    = ImportTopLevel T.Text
+      -- ^ Import a top-level export from a module, e.g., a function, a type, a
+      -- class.
+      --
+      -- > import M (?)
+      --
+      -- Some exports that have a parent, like a type-class method or an
+      -- associated type/data family, can still be imported as a top-level
+      -- import.
+      --
+      -- Note that this is not the case for constructors, they must always be
+      -- imported as part of their parent data type.
+
+    | ImportViaParent T.Text T.Text
+      -- ^ Import an export (first parameter) through its parent (second
+      -- parameter).
+      --
+      -- import M (P(?))
+      --
+      -- @P@ and @?@ can be a data type and a constructor, a class and a method,
+      -- a class and an associated type/data family, etc.
+
+    | ImportAllConstructors T.Text
+      -- ^ Import all constructors for a specific data type.
+      --
+      -- import M (P(..))
+      --
+      -- @P@ can be a data type or a class.
+  deriving Show
+
+importStyles :: IdentInfo -> NonEmpty ImportStyle
+importStyles i@(IdentInfo {parent})
+  | Just p <- pr
+    -- Constructors always have to be imported via their parent data type, but
+    -- methods and associated type/data families can also be imported as
+    -- top-level exports.
+  = ImportViaParent rend p
+      :| [ImportTopLevel rend | not (isDatacon i)]
+      <> [ImportAllConstructors p]
+  | otherwise
+  = ImportTopLevel rend :| []
+  where rend = rendered i
+        pr = occNameText <$> parent
+
+-- | Used for adding new imports
+renderImportStyle :: ImportStyle -> T.Text
+renderImportStyle (ImportTopLevel x)   = x
+renderImportStyle (ImportViaParent x p@(T.uncons -> Just ('(', _))) = "type " <> p <> "(" <> x <> ")"
+renderImportStyle (ImportViaParent x p) = p <> "(" <> x <> ")"
+renderImportStyle (ImportAllConstructors p) = p <> "(..)"
+
+-- | Used for extending import lists
+unImportStyle :: ImportStyle -> (Maybe String, String)
+unImportStyle (ImportTopLevel x)        = (Nothing, T.unpack x)
+unImportStyle (ImportViaParent x y)     = (Just $ T.unpack y, T.unpack x)
+unImportStyle (ImportAllConstructors x) = (Just $ T.unpack x, wildCardSymbol)
+
+
+quickFixImportKind' :: T.Text -> ImportStyle -> CodeActionKind
+quickFixImportKind' x (ImportTopLevel _) = CodeActionUnknown $ "quickfix.import." <> x <> ".list.topLevel"
+quickFixImportKind' x (ImportViaParent _ _) = CodeActionUnknown $ "quickfix.import." <> x <> ".list.withParent"
+quickFixImportKind' x (ImportAllConstructors _) = CodeActionUnknown $ "quickfix.import." <> x <> ".list.allConstructors"
+
+quickFixImportKind :: T.Text -> CodeActionKind
+quickFixImportKind x = CodeActionUnknown $ "quickfix.import." <> x
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -39,7 +39,6 @@
                                                            SemanticTokenRelative (length),
                                                            SemanticTokensEdit (_start),
                                                            mkRange)
-import qualified Language.LSP.Types                       as LSP
 import           Language.LSP.Types.Capabilities
 import qualified Language.LSP.Types.Lens                  as L
 import           System.Directory
@@ -57,20 +56,25 @@
 import           Development.IDE.Plugin.CodeAction        (matchRegExMultipleImports)
 import           Test.Hls
 
+import           Control.Applicative                      (liftA2)
 import qualified Development.IDE.Plugin.CodeAction        as Refactor
 import qualified Development.IDE.Plugin.HLS.GhcIde        as GhcIde
+import qualified Test.AddArgument
 
 main :: IO ()
 main = defaultTestRunner tests
 
-refactorPlugin :: [PluginDescriptor IdeState]
-refactorPlugin =
-      [ Refactor.iePluginDescriptor mempty "ghcide-code-actions-imports-exports"
-      , Refactor.typeSigsPluginDescriptor mempty "ghcide-code-actions-type-signatures"
-      , Refactor.bindingsPluginDescriptor mempty "ghcide-code-actions-bindings"
-      , Refactor.fillHolePluginDescriptor mempty "ghcide-code-actions-fill-holes"
-      , Refactor.extendImportPluginDescriptor mempty "ghcide-completions-1"
-      ] ++ GhcIde.descriptors mempty
+refactorPlugin :: IO [PluginDescriptor IdeState]
+refactorPlugin = do
+  exactprintLog <- pluginTestRecorder
+  ghcideLog <- pluginTestRecorder
+  pure $
+      [ Refactor.iePluginDescriptor exactprintLog "ghcide-code-actions-imports-exports"
+      , Refactor.typeSigsPluginDescriptor exactprintLog "ghcide-code-actions-type-signatures"
+      , Refactor.bindingsPluginDescriptor exactprintLog "ghcide-code-actions-bindings"
+      , Refactor.fillHolePluginDescriptor exactprintLog "ghcide-code-actions-fill-holes"
+      , Refactor.extendImportPluginDescriptor exactprintLog "ghcide-completions-1"
+      ] ++ GhcIde.descriptors ghcideLog
 
 tests :: TestTree
 tests =
@@ -99,7 +103,8 @@
               doTest = do
                   ir <- getInitializeResponse
                   let Just ExecuteCommandOptions {_commands = List commands} = getActual $ innerCaps ir
-                  zipWithM_ (\e o -> T.isSuffixOf e o @? show (e,o)) expected commands
+                  -- Check if expected exists in commands. Note that commands can arrive in different order.
+                  mapM_ (\e -> any (\o -> T.isSuffixOf e o) commands @? show (expected, show commands)) expected
 
     acquire :: IO (ResponseMessage Initialize)
     acquire = run initializeResponse
@@ -213,19 +218,19 @@
             "not imported"
             ["module A where", "import Text.Printf ()", "FormatParse"]
             (Position 2 10)
-            "FormatParse {"
-            ["module A where", "import Text.Printf (FormatParse (FormatParse))", "FormatParse"]
+            "FormatParse"
+            ["module A where", "import Text.Printf (FormatParse)", "FormatParse"]
         , completionCommandTest
             "parent imported"
             ["module A where", "import Text.Printf (FormatParse)", "FormatParse"]
             (Position 2 10)
-            "FormatParse {"
+            "FormatParse"
             ["module A where", "import Text.Printf (FormatParse (FormatParse))", "FormatParse"]
         , completionNoCommandTest
             "already imported"
             ["module A where", "import Text.Printf (FormatParse (FormatParse))", "FormatParse"]
             (Position 2 10)
-            "FormatParse {"
+            "FormatParse"
         ]
         , testGroup "Package completion"
           [ completionCommandTest
@@ -256,7 +261,8 @@
   _ <- waitForDiagnostics
   compls <- skipManyTill anyMessage (getCompletions docId pos)
   let wantedC = find ( \case
-            CompletionItem {_insertText = Just x} -> wanted `T.isPrefixOf` x
+            CompletionItem {_insertText = Just x
+                           ,_command    = Just _} -> wanted `T.isPrefixOf` x
             _                                     -> False
             ) compls
   case wantedC of
@@ -319,6 +325,9 @@
   , exportUnusedTests
   , addImplicitParamsConstraintTests
   , removeExportTests
+#if MIN_VERSION_ghc(9,2,1)
+  , Test.AddArgument.tests
+#endif
   ]
 
 insertImportTests :: TestTree
@@ -465,12 +474,12 @@
       "NoExplicitExports.expected.hs"
       "import Data.Monoid"
   , checkImport
-      "add to correctly placed exisiting import"
+      "add to correctly placed existing import"
       "ImportAtTop.hs"
       "ImportAtTop.expected.hs"
       "import Data.Monoid"
   , checkImport
-      "add to multiple correctly placed exisiting imports"
+      "add to multiple correctly placed existing imports"
       "MultipleImportsAtTop.hs"
       "MultipleImportsAtTop.expected.hs"
       "import Data.Monoid"
@@ -599,7 +608,7 @@
       doc <- createDoc "Testing.hs" "haskell" content
       _ <- waitForDiagnostics
       actionsOrCommands <- getCodeActions doc (Range (Position 3 12) (Position 3 20))
-      [fixTypo] <- pure [action | InR action@CodeAction{ _title = actionTitle } <- actionsOrCommands, "monus" `T.isInfixOf` actionTitle ]
+      [fixTypo] <- pure [action | InR action@CodeAction{ _title = actionTitle } <- actionsOrCommands, "monus" `T.isInfixOf` actionTitle , "Replace" `T.isInfixOf` actionTitle]
       executeCodeAction fixTypo
       contentAfterAction <- documentContents doc
       let expectedContentAfterAction = T.unlines
@@ -609,6 +618,28 @@
             , "foo x y = x `monus` y"
             ]
       liftIO $ expectedContentAfterAction @=? contentAfterAction
+  , testSession "change template function" $ do
+      let content = T.unlines
+            [ "{-# LANGUAGE TemplateHaskellQuotes #-}"
+            , "module Testing where"
+            , "import Language.Haskell.TH (Name)"
+            , "foo :: Name"
+            , "foo = 'bread"
+            ]
+      doc <- createDoc "Testing.hs" "haskell" content
+      diags <- waitForDiagnostics
+      actionsOrCommands <- getCodeActions doc (Range (Position 4 6) (Position 4 12))
+      [fixTypo] <- pure [action | InR action@CodeAction{ _title = actionTitle } <- actionsOrCommands, "break" `T.isInfixOf` actionTitle ]
+      executeCodeAction fixTypo
+      contentAfterAction <- documentContents doc
+      let expectedContentAfterAction = T.unlines
+            [ "{-# LANGUAGE TemplateHaskellQuotes #-}"
+            , "module Testing where"
+            , "import Language.Haskell.TH (Name)"
+            , "foo :: Name"
+            , "foo = 'break"
+            ]
+      liftIO $ expectedContentAfterAction @=? contentAfterAction
   ]
 
 typeWildCardActionTests :: TestTree
@@ -716,6 +747,7 @@
         contentAfterAction <- documentContents doc
         liftIO $ expectedContentAfterAction @=? contentAfterAction
 
+
 {-# HLINT ignore "Use nubOrd" #-}
 removeImportTests :: TestTree
 removeImportTests = testGroup "remove import actions"
@@ -1261,7 +1293,8 @@
                     , "b :: A"
                     , "b = ConstructorFoo"
                     ])
-        , testSession "extend single line qualified import with value" $ template
+        , ignoreForGHC94 "On GHC 9.4, the error messages with -fdefer-type-errors don't have necessary imported target srcspan info." $
+          testSession "extend single line qualified import with value" $ template
             [("ModuleA.hs", T.unlines
                     [ "module ModuleA where"
                     , "stuffA :: Double"
@@ -1432,7 +1465,7 @@
                     , "import A (pattern Some)"
                     , "k (Some x) = x"
                     ])
-        , ignoreForGHC92 "Diagnostic message has no suggestions" $
+        , ignoreFor (BrokenForGHC [GHC92, GHC94]) "Diagnostic message has no suggestions" $
           testSession "type constructor name same as data constructor name" $ template
             [("ModuleA.hs", T.unlines
                     [ "module ModuleA where"
@@ -1485,7 +1518,7 @@
             actionsOrCommands <- getCodeActions docB range
             let codeActions =
                   filter
-                    (T.isPrefixOf "Add" . codeActionTitle)
+                    (liftA2 (&&) (T.isPrefixOf "Add") (not . T.isPrefixOf "Add argument") . codeActionTitle)
                     [ca | InR ca <- actionsOrCommands]
                 actualTitles = codeActionTitle <$> codeActions
             -- Note that we are not testing the order of the actions, as the
@@ -1636,8 +1669,10 @@
     , test True []          "f = empty"                   []                "import Control.Applicative (empty)"
     , test True []          "f = empty"                   []                "import Control.Applicative"
     , test True []          "f = (&)"                     []                "import Data.Function ((&))"
-    , test True []          "f = NE.nonEmpty"             []                "import qualified Data.List.NonEmpty as NE"
-    , test True []          "f = Data.List.NonEmpty.nonEmpty" []            "import qualified Data.List.NonEmpty"
+    , ignoreForGHC94 "On GHC 9.4 the error message doesn't contain the qualified module name: https://gitlab.haskell.org/ghc/ghc/-/issues/20472"
+      $ test True []          "f = NE.nonEmpty"             []                "import qualified Data.List.NonEmpty as NE"
+    , ignoreForGHC94 "On GHC 9.4 the error message doesn't contain the qualified module name: https://gitlab.haskell.org/ghc/ghc/-/issues/20472"
+      $ test True []          "f = Data.List.NonEmpty.nonEmpty" []            "import qualified Data.List.NonEmpty"
     , test True []          "f :: Typeable a => a"        ["f = undefined"] "import Data.Typeable (Typeable)"
     , test True []          "f = pack"                    []                "import Data.Text (pack)"
     , test True []          "f :: Text"                   ["f = undefined"] "import Data.Text (Text)"
@@ -1645,15 +1680,18 @@
     , test True []          "f = (&) [] id"               []                "import Data.Function ((&))"
     , test True []          "f = (.|.)"                   []                "import Data.Bits (Bits((.|.)))"
     , test True []          "f = (.|.)"                   []                "import Data.Bits ((.|.))"
-    , test True []          "f :: a ~~ b"                 []                "import Data.Type.Equality (type (~~))"
-    , test True
+    , test True []          "f :: a ~~ b"                 []                "import Data.Type.Equality ((~~))"
+    , ignoreForGHC94 "On GHC 9.4 the error message doesn't contain the qualified module name: https://gitlab.haskell.org/ghc/ghc/-/issues/20472"
+      $ test True
       ["qualified Data.Text as T"
       ]                     "f = T.putStrLn"              []                "import qualified Data.Text.IO as T"
-    , test True
+    , ignoreForGHC94 "On GHC 9.4 the error message doesn't contain the qualified module name: https://gitlab.haskell.org/ghc/ghc/-/issues/20472"
+      $ test True
       [ "qualified Data.Text as T"
       , "qualified Data.Function as T"
       ]                     "f = T.putStrLn"              []                "import qualified Data.Text.IO as T"
-    , test True
+    , ignoreForGHC94 "On GHC 9.4 the error message doesn't contain the qualified module name: https://gitlab.haskell.org/ghc/ghc/-/issues/20472"
+      $ test True
       [ "qualified Data.Text as T"
       , "qualified Data.Function as T"
       , "qualified Data.Functor as T"
@@ -1817,7 +1855,6 @@
     auxFiles = ["AVec.hs", "BVec.hs", "CVec.hs", "DVec.hs", "EVec.hs", "FVec.hs"]
     withTarget file locs k = runWithExtraFiles "hiding" $ \dir -> do
         doc <- openDoc file "haskell"
-        waitForProgressDone
         void $ expectDiagnostics [(file, [(DsError, loc, "Ambiguous occurrence") | loc <- locs])]
         actions <- getAllCodeActions doc
         k dir doc actions
@@ -1830,7 +1867,7 @@
     [ testGroup
         "single"
         [ testOneCodeAction
-            "hide unsued"
+            "hide unused"
             "Hide on from Data.Function"
             (1, 2)
             (1, 4)
@@ -1843,7 +1880,7 @@
             , "g on = on"
             ]
         , testOneCodeAction
-            "extend hiding unsued"
+            "extend hiding unused"
             "Hide on from Data.Function"
             (1, 2)
             (1, 4)
@@ -1854,7 +1891,7 @@
             , "f on = on"
             ]
         , testOneCodeAction
-            "delete unsued"
+            "delete unused"
             "Hide on from Data.Function"
             (1, 2)
             (1, 4)
@@ -1956,7 +1993,7 @@
             ]
         , testOneCodeAction
             "auto hide all"
-            "Hide ++ from all occurence imports"
+            "Hide ++ from all occurrence imports"
             (2, 2)
             (2, 6)
             [ "import B"
@@ -2025,7 +2062,7 @@
       docB <- createDoc "ModuleB.hs" "haskell" (T.unlines $ txtB ++ txtB')
       _ <- waitForDiagnostics
       InR action@CodeAction { _title = actionTitle } : _
-                  <- sortOn (\(InR CodeAction{_title=x}) -> x) <$>
+                  <- filter (\(InR CodeAction{_title=x}) -> "Define" `T.isPrefixOf` x) <$>
                      getCodeActions docB (R 0 0 0 50)
       liftIO $ actionTitle @?= "Define select :: [Bool] -> Bool"
       executeCodeAction action
@@ -2049,7 +2086,7 @@
       docB <- createDoc "ModuleB.hs" "haskell" (T.unlines $ txtB ++ txtB')
       _ <- waitForDiagnostics
       InR action@CodeAction { _title = actionTitle } : _
-                  <- sortOn (\(InR CodeAction{_title=x}) -> x) <$>
+                  <- filter (\(InR CodeAction{_title=x}) -> "Define" `T.isPrefixOf` x) <$>
                      getCodeActions docB (R 0 0 0 50)
       liftIO $ actionTitle @?= "Define select :: [Bool] -> Bool"
       executeCodeAction action
@@ -2083,7 +2120,7 @@
     docB <- createDoc "ModuleB.hs" "haskell" (T.unlines start)
     _ <- waitForDiagnostics
     InR action@CodeAction { _title = actionTitle } : _
-                <- sortOn (\(InR CodeAction{_title=x}) -> x) <$>
+                <- filter (\(InR CodeAction{_title=x}) -> "Define" `T.isPrefixOf` x) <$>
                     getCodeActions docB (R 1 0 0 50)
     liftIO $ actionTitle @?= "Define select :: Int -> Bool"
     executeCodeAction action
@@ -2109,14 +2146,38 @@
     docB <- createDoc "ModuleB.hs" "haskell" (T.unlines start)
     _ <- waitForDiagnostics
     InR action@CodeAction { _title = actionTitle } : _
-                <- sortOn (\(InR CodeAction{_title=x}) -> x) <$>
+                <- filter (\(InR CodeAction{_title=x}) -> "Define" `T.isPrefixOf` x) <$>
                     getCodeActions docB (R 1 0 0 50)
     liftIO $ actionTitle @?= "Define select :: Int -> Bool"
     executeCodeAction action
     contentAfterAction <- documentContents docB
     liftIO $ contentAfterAction @?= T.unlines expected
+    , testSession "insert new function definition - untyped error" $ do
+      let txtB =
+            ["foo = select"
+            ]
+          txtB' =
+            [""
+            ,"someOtherCode = ()"
+            ]
+      docB <- createDoc "ModuleB.hs" "haskell" (T.unlines $ txtB ++ txtB')
+      _ <- waitForDiagnostics
+      InR action@CodeAction { _title = actionTitle } : _
+                  <- filter (\(InR CodeAction{_title=x}) -> "Define" `T.isPrefixOf` x) <$>
+                     getCodeActions docB (R 0 0 0 50)
+      liftIO $ actionTitle @?= "Define select :: _"
+      executeCodeAction action
+      contentAfterAction <- documentContents docB
+      liftIO $ contentAfterAction @?= T.unlines (txtB ++
+        [ ""
+        , "select :: _"
+        , "select = _"
+        ]
+        ++ txtB')
   ]
 
+#if MIN_VERSION_ghc(9,2,1)
+#endif
 
 deleteUnusedDefinitionTests :: TestTree
 deleteUnusedDefinitionTests = testGroup "delete unused definition action"
@@ -2271,7 +2332,11 @@
                , ""
                , "f = 1"
                ])
+#if MIN_VERSION_ghc(9,4,0)
+    [ (DsWarning, (3, 4), "Defaulting the type variable") ]
+#else
     [ (DsWarning, (3, 4), "Defaulting the following constraint") ]
+#endif
     "Add type annotation ‘Integer’ to ‘1’"
     (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}"
                , "module A (f) where"
@@ -2288,7 +2353,11 @@
                , "    let x = 3"
                , "    in x"
                ])
+#if MIN_VERSION_ghc(9,4,0)
+    [ (DsWarning, (4, 12), "Defaulting the type variable") ]
+#else
     [ (DsWarning, (4, 12), "Defaulting the following constraint") ]
+#endif
     "Add type annotation ‘Integer’ to ‘3’"
     (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}"
                , "module A where"
@@ -2306,7 +2375,11 @@
                , "    let x = let y = 5 in y"
                , "    in x"
                ])
+#if MIN_VERSION_ghc(9,4,0)
+    [ (DsWarning, (4, 20), "Defaulting the type variable") ]
+#else
     [ (DsWarning, (4, 20), "Defaulting the following constraint") ]
+#endif
     "Add type annotation ‘Integer’ to ‘5’"
     (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}"
                , "module A where"
@@ -2325,9 +2398,15 @@
                , ""
                , "f = seq \"debug\" traceShow \"debug\""
                ])
+#if MIN_VERSION_ghc(9,4,0)
+    [ (DsWarning, (6, 8), "Defaulting the type variable")
+    , (DsWarning, (6, 16), "Defaulting the type variable")
+    ]
+#else
     [ (DsWarning, (6, 8), "Defaulting the following constraint")
     , (DsWarning, (6, 16), "Defaulting the following constraint")
     ]
+#endif
     ("Add type annotation ‘" <> listOfChar <> "’ to ‘\"debug\"’")
     (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}"
                , "{-# LANGUAGE OverloadedStrings #-}"
@@ -2337,7 +2416,7 @@
                , ""
                , "f = seq (\"debug\" :: " <> listOfChar <> ") traceShow \"debug\""
                ])
-  , knownBrokenForGhcVersions [GHC92] "GHC 9.2 only has 'traceShow' in error span" $
+  , knownBrokenForGhcVersions [GHC92, GHC94] "GHC 9.2 only has 'traceShow' in error span" $
     testSession "add default type to satisfy two constraints" $
     testFor
     (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}"
@@ -2348,7 +2427,11 @@
                , ""
                , "f a = traceShow \"debug\" a"
                ])
+#if MIN_VERSION_ghc(9,4,0)
+    [ (DsWarning, (6, 6), "Defaulting the type variable") ]
+#else
     [ (DsWarning, (6, 6), "Defaulting the following constraint") ]
+#endif
     ("Add type annotation ‘" <> listOfChar <> "’ to ‘\"debug\"’")
     (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}"
                , "{-# LANGUAGE OverloadedStrings #-}"
@@ -2358,7 +2441,7 @@
                , ""
                , "f a = traceShow (\"debug\" :: " <> listOfChar <> ") a"
                ])
-  , knownBrokenForGhcVersions [GHC92] "GHC 9.2 only has 'traceShow' in error span" $
+  , knownBrokenForGhcVersions [GHC92, GHC94] "GHC 9.2 only has 'traceShow' in error span" $
     testSession "add default type to satisfy two constraints with duplicate literals" $
     testFor
     (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}"
@@ -2369,7 +2452,11 @@
                , ""
                , "f = seq (\"debug\" :: [Char]) (seq (\"debug\" :: [Char]) (traceShow \"debug\"))"
                ])
+#if MIN_VERSION_ghc(9,4,0)
+    [ (DsWarning, (6, 54), "Defaulting the type variable") ]
+#else
     [ (DsWarning, (6, 54), "Defaulting the following constraint") ]
+#endif
     ("Add type annotation ‘" <> listOfChar <> "’ to ‘\"debug\"’")
     (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}"
                , "{-# LANGUAGE OverloadedStrings #-}"
@@ -2986,15 +3073,15 @@
     "Remove redundant constraints `(Monoid a, Show a)` from the context of the type signature for `foo`"
     (typeSignatureSpaces $ Just "Monoid a, Show a")
     (typeSignatureSpaces Nothing)
-    , check
+  , check
     "Remove redundant constraint `Eq a` from the context of the type signature for `foo`"
     typeSignatureLined1
     typeSignatureOneLine
-    , check
+  , check
     "Remove redundant constraints `(Eq a, Show a)` from the context of the type signature for `foo`"
     typeSignatureLined2
     typeSignatureOneLine
-    , check
+  , check
     "Remove redundant constraint `Show a` from the context of the type signature for `foo`"
     typeSignatureLined3
     typeSignatureLined3'
@@ -3064,7 +3151,7 @@
         (R 2 0 2 11)
         "Export ‘bar’"
         Nothing
-    , ignoreForGHC92 "Diagnostic message has no suggestions" $
+    , ignoreFor (BrokenForGHC [GHC92, GHC94]) "Diagnostic message has no suggestions" $
       testSession "type is exported but not the constructor of same name" $ template
         (T.unlines
               [ "{-# OPTIONS_GHC -Wunused-top-binds #-}"
@@ -3680,7 +3767,9 @@
 run' s = withTempDir $ \dir -> runInDir dir (s dir)
 
 runInDir :: FilePath -> Session a -> IO a
-runInDir dir = runSessionWithServer' refactorPlugin def def lspTestCaps dir
+runInDir dir act = do
+  plugin <- refactorPlugin
+  runSessionWithServer' plugin def def lspTestCaps dir act
 
 lspTestCaps :: ClientCapabilities
 lspTestCaps = fullCaps { _window = Just $ WindowClientCapabilities (Just True) Nothing Nothing }
@@ -3699,6 +3788,9 @@
 ignoreForGHC92 :: String -> TestTree -> TestTree
 ignoreForGHC92 = ignoreFor (BrokenForGHC [GHC92])
 
+ignoreForGHC94 :: String -> TestTree -> TestTree
+ignoreForGHC94 = knownIssueFor Broken (BrokenForGHC [GHC94])
+
 data BrokenTarget =
     BrokenSpecific OS [GhcVersion]
     -- ^Broken for `BrokenOS` with `GhcVersion`
@@ -3744,4 +3836,3 @@
 listOfChar :: T.Text
 listOfChar | ghcVersion >= GHC90 = "String"
            | otherwise = "[Char]"
-
diff --git a/test/Test/AddArgument.hs b/test/Test/AddArgument.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/AddArgument.hs
@@ -0,0 +1,74 @@
+{-# LANGUAGE AllowAmbiguousTypes   #-}
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE DataKinds             #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE GADTs                 #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE PolyKinds             #-}
+
+module Test.AddArgument (tests) where
+
+import           Data.List.Extra
+import qualified Data.Text                         as T
+import           Development.IDE.Types.Location
+import           Language.LSP.Test
+import           Language.LSP.Types                hiding
+                                                   (SemanticTokenAbsolute (length, line),
+                                                    SemanticTokenRelative (length),
+                                                    SemanticTokensEdit (_start),
+                                                    mkRange)
+import           Test.Tasty
+import           Test.Tasty.HUnit
+
+
+import           Test.Hls
+
+import qualified Development.IDE.Plugin.CodeAction as Refactor
+
+tests :: TestTree
+tests =
+  testGroup
+    "add argument"
+#if !MIN_VERSION_ghc(9,2,1)
+    []
+#else
+    [ mkGoldenAddArgTest' "Hole" (r 0 0 0 50) "_new_def",
+      mkGoldenAddArgTest "NoTypeSuggestion" (r 0 0 0 50),
+      mkGoldenAddArgTest "MultipleDeclAlts" (r 0 0 0 50),
+      mkGoldenAddArgTest "AddArgWithSig" (r 1 0 1 50),
+      mkGoldenAddArgTest "AddArgWithSigAndDocs" (r 8 0 8 50),
+      mkGoldenAddArgTest "AddArgFromLet" (r 2 0 2 50),
+      mkGoldenAddArgTest "AddArgFromWhere" (r 3 0 3 50),
+      mkGoldenAddArgTest "AddArgFromWhereComments" (r 3 0 3 50),
+      mkGoldenAddArgTest "AddArgWithTypeSynSig" (r 2 0 2 50),
+      mkGoldenAddArgTest "AddArgWithTypeSynSigContravariant" (r 2 0 2 50),
+      mkGoldenAddArgTest "AddArgWithLambda" (r 1 0 1 50),
+      mkGoldenAddArgTest "MultiSigFirst" (r 2 0 2 50),
+      mkGoldenAddArgTest "MultiSigLast" (r 2 0 2 50),
+      mkGoldenAddArgTest "MultiSigMiddle" (r 2 0 2 50)
+    ]
+  where
+    r x y x' y' = Range (Position x y) (Position x' y')
+
+mkGoldenAddArgTest :: FilePath -> Range -> TestTree
+mkGoldenAddArgTest testFileName range = mkGoldenAddArgTest' testFileName range "new_def"
+
+-- Make a golden test for the add argument action. Given varName is the name of the variable not yet defined.
+mkGoldenAddArgTest' :: FilePath -> Range -> T.Text -> TestTree
+mkGoldenAddArgTest' testFileName range varName = do
+    let action docB = do
+          _ <- waitForDiagnostics
+          InR action@CodeAction {_title = actionTitle} : _ <-
+            filter (\(InR CodeAction {_title = x}) -> "Add" `isPrefixOf` T.unpack x)
+              <$> getCodeActions docB range
+          liftIO $ actionTitle @?= ("Add argument ‘" <> varName <> "’ to function")
+          executeCodeAction action
+    goldenWithHaskellDoc
+      (mkPluginTestDescriptor Refactor.bindingsPluginDescriptor "ghcide-code-actions-bindings")
+      (testFileName <> " (golden)")
+      "test/data/golden/add-arg"
+      testFileName
+      "expected"
+      "hs"
+      action
+#endif
diff --git a/test/data/golden/add-arg/AddArgFromLet.expected.hs b/test/data/golden/add-arg/AddArgFromLet.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgFromLet.expected.hs
@@ -0,0 +1,6 @@
+foo :: Bool -> _ -> Int
+foo True new_def =
+  let bar = new_def
+  in bar
+
+foo False new_def = 1
diff --git a/test/data/golden/add-arg/AddArgFromLet.hs b/test/data/golden/add-arg/AddArgFromLet.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgFromLet.hs
@@ -0,0 +1,6 @@
+foo :: Bool -> Int
+foo True =
+  let bar = new_def
+  in bar
+
+foo False = 1
diff --git a/test/data/golden/add-arg/AddArgFromWhere.expected.hs b/test/data/golden/add-arg/AddArgFromWhere.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgFromWhere.expected.hs
@@ -0,0 +1,6 @@
+foo :: Bool -> _ -> Int
+foo True new_def = bar
+  where
+    bar = new_def
+
+foo False new_def = 1
diff --git a/test/data/golden/add-arg/AddArgFromWhere.hs b/test/data/golden/add-arg/AddArgFromWhere.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgFromWhere.hs
@@ -0,0 +1,6 @@
+foo :: Bool -> Int
+foo True = bar
+  where
+    bar = new_def
+
+foo False = 1
diff --git a/test/data/golden/add-arg/AddArgFromWhereComments.expected.hs b/test/data/golden/add-arg/AddArgFromWhereComments.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgFromWhereComments.expected.hs
@@ -0,0 +1,6 @@
+foo -- c1
+  -- | c2
+  {- c3 -} True new_def -- c4
+  = new_def
+
+foo False new_def = False
diff --git a/test/data/golden/add-arg/AddArgFromWhereComments.hs b/test/data/golden/add-arg/AddArgFromWhereComments.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgFromWhereComments.hs
@@ -0,0 +1,6 @@
+foo -- c1
+  -- | c2
+  {- c3 -} True -- c4
+  = new_def
+
+foo False = False
diff --git a/test/data/golden/add-arg/AddArgWithLambda.expected.hs b/test/data/golden/add-arg/AddArgWithLambda.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithLambda.expected.hs
@@ -0,0 +1,4 @@
+foo :: Bool -> _ -> () -> Int
+foo True new_def = \() -> new_def [True]
+
+foo False new_def = const 1
diff --git a/test/data/golden/add-arg/AddArgWithLambda.hs b/test/data/golden/add-arg/AddArgWithLambda.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithLambda.hs
@@ -0,0 +1,4 @@
+foo :: Bool -> () -> Int
+foo True = \() -> new_def [True]
+
+foo False = const 1
diff --git a/test/data/golden/add-arg/AddArgWithSig.expected.hs b/test/data/golden/add-arg/AddArgWithSig.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithSig.expected.hs
@@ -0,0 +1,4 @@
+foo :: Bool -> _ -> Int
+foo True new_def = new_def [True]
+
+foo False new_def = 1
diff --git a/test/data/golden/add-arg/AddArgWithSig.hs b/test/data/golden/add-arg/AddArgWithSig.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithSig.hs
@@ -0,0 +1,4 @@
+foo :: Bool -> Int
+foo True = new_def [True]
+
+foo False = 1
diff --git a/test/data/golden/add-arg/AddArgWithSigAndDocs.expected.hs b/test/data/golden/add-arg/AddArgWithSigAndDocs.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithSigAndDocs.expected.hs
@@ -0,0 +1,11 @@
+foo ::
+  -- c1
+  Bool -- c2
+  -- c3
+  -> -- c4
+  -- | c5
+  () -- c6
+  -> _ -> Int
+foo True () new_def = new_def [True]
+
+foo False () new_def = 1
diff --git a/test/data/golden/add-arg/AddArgWithSigAndDocs.hs b/test/data/golden/add-arg/AddArgWithSigAndDocs.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithSigAndDocs.hs
@@ -0,0 +1,11 @@
+foo ::
+  -- c1
+  Bool -- c2
+  -- c3
+  -> -- c4
+  -- | c5
+  () -- c6
+  -> Int
+foo True () = new_def [True]
+
+foo False () = 1
diff --git a/test/data/golden/add-arg/AddArgWithTypeSynSig.expected.hs b/test/data/golden/add-arg/AddArgWithTypeSynSig.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithTypeSynSig.expected.hs
@@ -0,0 +1,5 @@
+type FunctionTySyn = Bool -> Int
+foo :: FunctionTySyn
+foo True new_def = new_def [True]
+
+foo False new_def = 1
diff --git a/test/data/golden/add-arg/AddArgWithTypeSynSig.hs b/test/data/golden/add-arg/AddArgWithTypeSynSig.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithTypeSynSig.hs
@@ -0,0 +1,5 @@
+type FunctionTySyn = Bool -> Int
+foo :: FunctionTySyn
+foo True = new_def [True]
+
+foo False = 1
diff --git a/test/data/golden/add-arg/AddArgWithTypeSynSigContravariant.expected.hs b/test/data/golden/add-arg/AddArgWithTypeSynSigContravariant.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithTypeSynSigContravariant.expected.hs
@@ -0,0 +1,5 @@
+type FunctionTySyn = Bool -> Int
+foo :: FunctionTySyn -> () -> _ -> Int
+foo True () new_def = new_def [True]
+
+foo False () new_def = 1
diff --git a/test/data/golden/add-arg/AddArgWithTypeSynSigContravariant.hs b/test/data/golden/add-arg/AddArgWithTypeSynSigContravariant.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/AddArgWithTypeSynSigContravariant.hs
@@ -0,0 +1,5 @@
+type FunctionTySyn = Bool -> Int
+foo :: FunctionTySyn -> () -> Int
+foo True () = new_def [True]
+
+foo False () = 1
diff --git a/test/data/golden/add-arg/Hole.expected.hs b/test/data/golden/add-arg/Hole.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/Hole.expected.hs
@@ -0,0 +1,1 @@
+foo _new_def = _new_def
diff --git a/test/data/golden/add-arg/Hole.hs b/test/data/golden/add-arg/Hole.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/Hole.hs
@@ -0,0 +1,1 @@
+foo = _new_def
diff --git a/test/data/golden/add-arg/MultiSigFirst.expected.hs b/test/data/golden/add-arg/MultiSigFirst.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/MultiSigFirst.expected.hs
@@ -0,0 +1,6 @@
+bar :: Bool -> Int
+foo :: Bool -> _ -> Int
+bar = const 1
+foo True new_def = new_def [True]
+
+foo False new_def = 1
diff --git a/test/data/golden/add-arg/MultiSigFirst.hs b/test/data/golden/add-arg/MultiSigFirst.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/MultiSigFirst.hs
@@ -0,0 +1,5 @@
+foo, bar :: Bool -> Int
+bar = const 1
+foo True = new_def [True]
+
+foo False = 1
diff --git a/test/data/golden/add-arg/MultiSigLast.expected.hs b/test/data/golden/add-arg/MultiSigLast.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/MultiSigLast.expected.hs
@@ -0,0 +1,7 @@
+baz, bar :: Bool -> Int
+foo :: Bool -> _ -> Int
+bar = const 1
+foo True new_def = new_def [True]
+
+foo False new_def = 1
+baz = 1
diff --git a/test/data/golden/add-arg/MultiSigLast.hs b/test/data/golden/add-arg/MultiSigLast.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/MultiSigLast.hs
@@ -0,0 +1,6 @@
+baz, bar, foo :: Bool -> Int
+bar = const 1
+foo True = new_def [True]
+
+foo False = 1
+baz = 1
diff --git a/test/data/golden/add-arg/MultiSigMiddle.expected.hs b/test/data/golden/add-arg/MultiSigMiddle.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/MultiSigMiddle.expected.hs
@@ -0,0 +1,7 @@
+baz, bar :: Bool -> Int
+foo :: Bool -> _ -> Int
+bar = const 1
+foo True new_def = new_def [True]
+
+foo False new_def = 1
+baz = 1
diff --git a/test/data/golden/add-arg/MultiSigMiddle.hs b/test/data/golden/add-arg/MultiSigMiddle.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/MultiSigMiddle.hs
@@ -0,0 +1,6 @@
+baz, foo, bar :: Bool -> Int
+bar = const 1
+foo True = new_def [True]
+
+foo False = 1
+baz = 1
diff --git a/test/data/golden/add-arg/MultipleDeclAlts.expected.hs b/test/data/golden/add-arg/MultipleDeclAlts.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/MultipleDeclAlts.expected.hs
@@ -0,0 +1,2 @@
+foo True new_def = new_def
+foo False new_def = 1
diff --git a/test/data/golden/add-arg/MultipleDeclAlts.hs b/test/data/golden/add-arg/MultipleDeclAlts.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/MultipleDeclAlts.hs
@@ -0,0 +1,2 @@
+foo True = new_def
+foo False = 1
diff --git a/test/data/golden/add-arg/NoTypeSuggestion.expected.hs b/test/data/golden/add-arg/NoTypeSuggestion.expected.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/NoTypeSuggestion.expected.hs
@@ -0,0 +1,1 @@
+foo new_def = new_def
diff --git a/test/data/golden/add-arg/NoTypeSuggestion.hs b/test/data/golden/add-arg/NoTypeSuggestion.hs
new file mode 100644
--- /dev/null
+++ b/test/data/golden/add-arg/NoTypeSuggestion.hs
@@ -0,0 +1,1 @@
+foo = new_def
diff --git a/test/data/hiding/hie.yaml b/test/data/hiding/hie.yaml
--- a/test/data/hiding/hie.yaml
+++ b/test/data/hiding/hie.yaml
@@ -2,7 +2,6 @@
     direct:
         arguments:
         - -Wall
-        - HideFunction.hs
         - AVec.hs
         - BVec.hs
         - CVec.hs
