diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,258 @@
 # Changelog for haskell-language-server
 
+## 1.9.0.0
+
+- Binaries for GHC 9.4.3, GHC 9.4.4 and GHC 9.2.5.
+- Dropped support for GHC 8.8 and GHC 8.10.
+- New plugins including:
+  - Expanding record wild cards using hls-explicit-record-fields-plugin (#3304).
+  - Formatting cabal fields using cabal-fmt via hls-cabal-fmt-plugin (#2047).
+  - Warnings and errors for cabal files using hls-cabal-plugin (#2954).
+  - Folding ranges using hls-code-range-plugin (#3058).
+- Support for many plugins like the refactor, splice, retrie, gadt, hlint, fourmolu and class plugins.
+- Completion for record dot fields (#3080).
+- Performance and memory usage improvements.
+- And many more bug fixes and improvements!
+
+- Enable plugin tests in CI for GHC 9.4
+([#3420](https://github.com/haskell/haskell-language-server/pull/3420)) by @wz1000
+- Add a mergify action to update PRs
+([#3418](https://github.com/haskell/haskell-language-server/pull/3418)) by @michaelpj
+- GHC 9.4: Compute the source hash before the preprocessor
+([#3415](https://github.com/haskell/haskell-language-server/pull/3415)) by @wz1000
+- Clear the mi_globals field when generating an iface
+([#3414](https://github.com/haskell/haskell-language-server/pull/3414)) by @wz1000
+- Various strictness improvements
+([#3413](https://github.com/haskell/haskell-language-server/pull/3413)) by @wz1000
+- Remove unused GHC compat code
+([#3412](https://github.com/haskell/haskell-language-server/pull/3412)) by @fendor
+- Bump shake-bench to v0.2.0.0
+([#3411](https://github.com/haskell/haskell-language-server/pull/3411)) by @pepeiborra
+- Support fourmolu 0.10
+([#3410](https://github.com/haskell/haskell-language-server/pull/3410)) by @brandonchinn178
+- Fix nix build CI 
+([#3404](https://github.com/haskell/haskell-language-server/pull/3404)) by @wavewave
+- Fix fourmolu with -f-fixity-th in nix env
+([#3400](https://github.com/haskell/haskell-language-server/pull/3400)) by @wavewave
+- Correct list of GHC versions in caching.yml to match test.yml
+([#3397](https://github.com/haskell/haskell-language-server/pull/3397)) by @fendor
+- Add CI flows for 9.4.3
+([#3396](https://github.com/haskell/haskell-language-server/pull/3396)) by @pepeiborra
+- Bump technote-space/get-diff-action from 6.1.1 to 6.1.2
+([#3392](https://github.com/haskell/haskell-language-server/pull/3392)) by @dependabot[bot]
+- Unload once per linkable instead of once per splice
+([#3390](https://github.com/haskell/haskell-language-server/pull/3390)) by @wz1000
+- Fix table in ghc-version-support.md
+([#3389](https://github.com/haskell/haskell-language-server/pull/3389)) by @k4z4n0v4
+- Fix Nix CI, probably
+([#3388](https://github.com/haskell/haskell-language-server/pull/3388)) by @lf-
+- [hls-explicit-record-fields-plugin] Expand used fields only
+([#3386](https://github.com/haskell/haskell-language-server/pull/3386)) by @ozkutuk
+- Bump hlint version CI flow
+([#3384](https://github.com/haskell/haskell-language-server/pull/3384)) by @fendor
+- Bump fkirc/skip-duplicate-actions from 5.2.0 to 5.3.0
+([#3381](https://github.com/haskell/haskell-language-server/pull/3381)) by @dependabot[bot]
+- Reword intro section in releases.md
+([#3378](https://github.com/haskell/haskell-language-server/pull/3378)) by @fendor
+- Make redundant import removal work on PatSyn imports
+([#3377](https://github.com/haskell/haskell-language-server/pull/3377)) by @ozkutuk
+- Add CI flows for GHC 9.2.5
+([#3376](https://github.com/haskell/haskell-language-server/pull/3376)) by @fendor
+- Delete dead code in hls-test-utils
+([#3368](https://github.com/haskell/haskell-language-server/pull/3368)) by @fendor
+- Bump gha versions in setup-build/action.yml
+([#3366](https://github.com/haskell/haskell-language-server/pull/3366)) by @fendor
+- Wingman copy old to new
+([#3363](https://github.com/haskell/haskell-language-server/pull/3363)) by @santiweight
+- Cleanup Development.IDE.CodeAction
+([#3360](https://github.com/haskell/haskell-language-server/pull/3360)) by @santiweight
+- Use latest GHC 9.2 and 9.4 in flake.nix
+([#3354](https://github.com/haskell/haskell-language-server/pull/3354)) by @cydparser
+- wingman: move wingman to new directory
+([#3352](https://github.com/haskell/haskell-language-server/pull/3352)) by @santiweight
+- Introduce common code for Recorders in Plugin Tests
+([#3347](https://github.com/haskell/haskell-language-server/pull/3347)) by @fendor
+- Add `RangeMap` for unified "in-range" filtering
+([#3343](https://github.com/haskell/haskell-language-server/pull/3343)) by @ozkutuk
+- Docs: update and split neovim/vim configurations
+([#3342](https://github.com/haskell/haskell-language-server/pull/3342)) by @MrcJkb
+- Extract AddArgument modules
+([#3339](https://github.com/haskell/haskell-language-server/pull/3339)) by @santiweight
+- Add hls-cabal-fmt-plugin to hackage release CI script and HLS library
+([#3335](https://github.com/haskell/haskell-language-server/pull/3335)) by @fendor
+- Ensure at least 1 capability 
+([#3334](https://github.com/haskell/haskell-language-server/pull/3334)) by @pepeiborra
+- Add support for Fourmolu 0.9
+([#3331](https://github.com/haskell/haskell-language-server/pull/3331)) by @brandonchinn178
+- [skip ci] Add myself to CODEOWNERS
+([#3329](https://github.com/haskell/haskell-language-server/pull/3329)) by @ozkutuk
+- Typo fixes
+([#3325](https://github.com/haskell/haskell-language-server/pull/3325)) by @Deltaspace0
+- Gitlab CI improvements
+([#3324](https://github.com/haskell/haskell-language-server/pull/3324)) by @wz1000
+- Refactor overlay composition
+([#3323](https://github.com/haskell/haskell-language-server/pull/3323)) by @Gabriella439
+- Add support for `.env` shells to `flake.nix`
+([#3322](https://github.com/haskell/haskell-language-server/pull/3322)) by @Gabriella439
+- feat: update type signature during add argument action
+([#3321](https://github.com/haskell/haskell-language-server/pull/3321)) by @santiweight
+- Update refactor/splice/hlint/fourmolu/retrie/gadt plugin for GHC 9.4
+([#3317](https://github.com/haskell/haskell-language-server/pull/3317)) by @9999years
+- Remove stack from installation docs since it is not supported anymore
+([#3314](https://github.com/haskell/haskell-language-server/pull/3314)) by @fendor
+- Bump cachix/cachix-action from 11 to 12
+([#3310](https://github.com/haskell/haskell-language-server/pull/3310)) by @dependabot[bot]
+- Restore ability to run source plugins
+([#3309](https://github.com/haskell/haskell-language-server/pull/3309)) by @JakobBruenker
+- New plugin: Explicit record fields
+([#3304](https://github.com/haskell/haskell-language-server/pull/3304)) by @ozkutuk
+- support haddock-library 1.11
+([#3303](https://github.com/haskell/haskell-language-server/pull/3303)) by @kokobd
+- Record diagnostics source rule when testing
+([#3301](https://github.com/haskell/haskell-language-server/pull/3301)) by @pepeiborra
+- Make a test more reliable
+([#3300](https://github.com/haskell/haskell-language-server/pull/3300)) by @pepeiborra
+- Change default cabal install target name on docs/installation.md
+([#3298](https://github.com/haskell/haskell-language-server/pull/3298)) by @caiquefigueiredo
+- Bump technote-space/get-diff-action from 6.1.0 to 6.1.1
+([#3293](https://github.com/haskell/haskell-language-server/pull/3293)) by @dependabot[bot]
+- Bump cachix/install-nix-action from 17 to 18
+([#3292](https://github.com/haskell/haskell-language-server/pull/3292)) by @dependabot[bot]
+- Bump cachix/cachix-action from 10 to 11
+([#3291](https://github.com/haskell/haskell-language-server/pull/3291)) by @dependabot[bot]
+- Purge GHC 8.8
+([#3287](https://github.com/haskell/haskell-language-server/pull/3287)) by @michaelpj
+- Bump partial ghc support warning to 9.4
+([#3286](https://github.com/haskell/haskell-language-server/pull/3286)) by @andys8
+- Improved message for missing command or plugin
+([#3285](https://github.com/haskell/haskell-language-server/pull/3285)) by @andys8
+- Register Fourmolu plugin properties
+([#3284](https://github.com/haskell/haskell-language-server/pull/3284)) by @georgefst
+- Cleanup GHC macros (because min version is 8.8.4)
+([#3281](https://github.com/haskell/haskell-language-server/pull/3281)) by @andys8
+- Remove unlawful Ord instance and replace it by a compare function
+([#3279](https://github.com/haskell/haskell-language-server/pull/3279)) by @ChristophHochrainer
+- Exclude the implicit prelude import (#2798)
+([#3277](https://github.com/haskell/haskell-language-server/pull/3277)) by @ChristophHochrainer
+- Fix typos in documentation
+([#3274](https://github.com/haskell/haskell-language-server/pull/3274)) by @bendo
+- Use an importance score to order the suggested import code action
+([#3271](https://github.com/haskell/haskell-language-server/pull/3271)) by @ChristophHochrainer
+- Update plugin tutorial
+([#3266](https://github.com/haskell/haskell-language-server/pull/3266)) by @dyniec
+- configuration-ghc-94.nix: Fix references to lsp and lsp-types source
+([#3265](https://github.com/haskell/haskell-language-server/pull/3265)) by @akshaymankar
+- Add suggestions about licenses in cabal file
+([#3261](https://github.com/haskell/haskell-language-server/pull/3261)) by @dyniec
+- Fix action removes ticks from TemplateHaskellQuotes (#628)
+([#3260](https://github.com/haskell/haskell-language-server/pull/3260)) by @bendo
+- Hlint: A handful of fixes to hints
+([#3259](https://github.com/haskell/haskell-language-server/pull/3259)) by @andys8
+- Support ghc 9.4 for hls-class-plugin
+([#3258](https://github.com/haskell/haskell-language-server/pull/3258)) by @July541
+- Fix nix developement shell
+([#3257](https://github.com/haskell/haskell-language-server/pull/3257)) by @akshaymankar
+- GCH -> GHC
+([#3252](https://github.com/haskell/haskell-language-server/pull/3252)) by @michaelpj
+- Docs: Plugin Support hls-explicit-fixity-plugin
+([#3251](https://github.com/haskell/haskell-language-server/pull/3251)) by @andys8
+- Fix dead link to supported GHC versions
+([#3244](https://github.com/haskell/haskell-language-server/pull/3244)) by @buggymcbugfix
+- Update link to supported versions in README
+([#3242](https://github.com/haskell/haskell-language-server/pull/3242)) by @citrusmunch
+- Bump fkirc/skip-duplicate-actions from 5.1.0 to 5.2.0
+([#3239](https://github.com/haskell/haskell-language-server/pull/3239)) by @dependabot[bot]
+- Move new imports down the code action list
+([#3235](https://github.com/haskell/haskell-language-server/pull/3235)) by @kokobd
+- Improve memory characteristics of ExportsMap
+([#3231](https://github.com/haskell/haskell-language-server/pull/3231)) by @wz1000
+- [skip ci] Remove myself from codeowners
+([#3230](https://github.com/haskell/haskell-language-server/pull/3230)) by @jneira
+- Fix error in code range
+([#3229](https://github.com/haskell/haskell-language-server/pull/3229)) by @kokobd
+- Use nixpkgs variants of Sphinx packages
+([#3227](https://github.com/haskell/haskell-language-server/pull/3227)) by @ozkutuk
+- Bump fkirc/skip-duplicate-actions from 4.0.0 to 5.1.0
+([#3226](https://github.com/haskell/haskell-language-server/pull/3226)) by @dependabot[bot]
+- Add `source-repository` to all cabal files
+([#3219](https://github.com/haskell/haskell-language-server/pull/3219)) by @hololeap
+- hls-hlint-plugin: Update README.md
+([#3216](https://github.com/haskell/haskell-language-server/pull/3216)) by @hololeap
+-  wrapper.in: Require runtime ghc-pkgs to be an abi compatible superset of bootpkgs
+([#3214](https://github.com/haskell/haskell-language-server/pull/3214)) by @maralorn
+- Add diagnostics to Stan descriptor
+([#3213](https://github.com/haskell/haskell-language-server/pull/3213)) by @pepeiborra
+- Document the `stack` requirement in wrapper tests
+([#3212](https://github.com/haskell/haskell-language-server/pull/3212)) by @ozkutuk
+- Improve haddock comments
+([#3207](https://github.com/haskell/haskell-language-server/pull/3207)) by @kokobd
+- Implement sharing for hls-graph Keys
+([#3206](https://github.com/haskell/haskell-language-server/pull/3206)) by @wz1000
+- Improve hls-fixity-plugin
+([#3205](https://github.com/haskell/haskell-language-server/pull/3205)) by @wz1000
+- Implement completionItem/resolve
+([#3204](https://github.com/haskell/haskell-language-server/pull/3204)) by @wz1000
+- Sort vscode extension schema json by keys
+([#3203](https://github.com/haskell/haskell-language-server/pull/3203)) by @fendor
+- docs/supported-versions: Fix typo and more precise brittany support
+([#3201](https://github.com/haskell/haskell-language-server/pull/3201)) by @maralorn
+- Stylish Haskell: CPP parse issues
+([#3199](https://github.com/haskell/haskell-language-server/pull/3199)) by @andys8
+- Bump technote-space/get-diff-action from 4.0.1 to 6.1.0
+([#3198](https://github.com/haskell/haskell-language-server/pull/3198)) by @dependabot[bot]
+- Log plugin name and attribute errors to plugins
+([#3194](https://github.com/haskell/haskell-language-server/pull/3194)) by @pepeiborra
+- Support optional plugins
+([#3193](https://github.com/haskell/haskell-language-server/pull/3193)) by @pepeiborra
+- Add policy on plugin support tiers
+([#3189](https://github.com/haskell/haskell-language-server/pull/3189)) by @michaelpj
+- Fix broken call-hierarchy-plugin-tests for type signatures
+([#3188](https://github.com/haskell/haskell-language-server/pull/3188)) by @July541
+- Update supported GHC versions doc
+([#3186](https://github.com/haskell/haskell-language-server/pull/3186)) by @michaelpj
+- Docs: Fix checkParents documentation
+([#3184](https://github.com/haskell/haskell-language-server/pull/3184)) by @andys8
+- Configuration: more advanced Vim / Coc example (suggestion)
+([#3181](https://github.com/haskell/haskell-language-server/pull/3181)) by @andys8
+- Docs: List stan plugin
+([#3180](https://github.com/haskell/haskell-language-server/pull/3180)) by @andys8
+- Stan: Respect plugin configuration globalOn
+([#3179](https://github.com/haskell/haskell-language-server/pull/3179)) by @andys8
+- Solve formatting issues (stylish-haskell, pre-commit CI)
+([#3171](https://github.com/haskell/haskell-language-server/pull/3171)) by @andys8
+- remove manual heap profiling from ghcide
+([#3168](https://github.com/haskell/haskell-language-server/pull/3168)) by @pepeiborra
+- Refactor plugin: Prefer code action
+([#3167](https://github.com/haskell/haskell-language-server/pull/3167)) by @andys8
+- Fixes the flake deps to align with cabal bounds
+([#3163](https://github.com/haskell/haskell-language-server/pull/3163)) by @mjrussell
+- Remove unused build-depends and install warnings
+([#3155](https://github.com/haskell/haskell-language-server/pull/3155)) by @pepeiborra
+- Release script fixes
+([#3154](https://github.com/haskell/haskell-language-server/pull/3154)) by @wz1000
+- Allow hackage upload
+([#3153](https://github.com/haskell/haskell-language-server/pull/3153)) by @wz1000
+- support add-argument action
+([#3149](https://github.com/haskell/haskell-language-server/pull/3149)) by @santiweight
+- Only run the pre-commit hook on changed files
+([#3145](https://github.com/haskell/haskell-language-server/pull/3145)) by @drsooch
+- unescape printable characters
+([#3140](https://github.com/haskell/haskell-language-server/pull/3140)) by @kokobd
+- nix: fix nix environment for GHC 9.4
+([#3133](https://github.com/haskell/haskell-language-server/pull/3133)) by @guibou
+- Drop compatibility with GHC 8.6.5
+([#3101](https://github.com/haskell/haskell-language-server/pull/3101)) by @pepeiborra
+- Feat: basic record dot completions
+([#3080](https://github.com/haskell/haskell-language-server/pull/3080)) by @coltenwebb
+- Feat: Folding Ranges
+([#3058](https://github.com/haskell/haskell-language-server/pull/3058)) by @sloorush
+- Parse .cabal files; show error and warning diagnostics
+([#2954](https://github.com/haskell/haskell-language-server/pull/2954)) by @runeksvendsen
+- Make splice plugin compatible with GHC 9.2
+([#2816](https://github.com/haskell/haskell-language-server/pull/2816)) by @eddiejessup
+- Add formatting plugin for cabal files which uses cabal-fmt
+([#2047](https://github.com/haskell/haskell-language-server/pull/2047)) by @VeryMilkyJoe
+
 ## 1.8.0.0
 
 - Binaries for GHC 9.2.3 and GHC 9.2.4
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@
 
 - [Features](https://haskell-language-server.readthedocs.io/en/latest/features.html)
 - [Installation](https://haskell-language-server.readthedocs.io/en/latest/installation.html)
-- [Supported GHC Versions](https://haskell-language-server.readthedocs.io/en/latest/supported-versions.html)
+- [Supported GHC Versions](https://haskell-language-server.readthedocs.io/en/latest/support/ghc-version-support.html)
 - [Configuration](https://haskell-language-server.readthedocs.io/en/latest/configuration.html)
 - [Troubleshooting](https://haskell-language-server.readthedocs.io/en/latest/troubleshooting.html)
 - [Contributing](https://haskell-language-server.readthedocs.io/en/latest/contributing/index.html)
diff --git a/bench/Main.hs b/bench/Main.hs
--- a/bench/Main.hs
+++ b/bench/Main.hs
@@ -42,9 +42,9 @@
  -}
 {-# LANGUAGE DeriveAnyClass     #-}
 {-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE OverloadedStrings  #-}
 {-# LANGUAGE TypeFamilies       #-}
 {-# OPTIONS -Wno-orphans #-}
-{-# LANGUAGE PackageImports     #-}
 
 import           Control.Lens                (preview, (^.))
 import           Control.Monad.Extra
@@ -54,7 +54,7 @@
 import           Data.Foldable               (find)
 import qualified Data.Map.Strict             as Map
 import           Data.Maybe
-import           Data.Text                   (pack, unpack)
+import           Data.Text                   (unpack)
 import           Data.Yaml                   (FromJSON (..), ToJSON (toJSON),
                                               decodeFileThrow)
 import           Development.Benchmark.Rules hiding (parallelism)
@@ -75,7 +75,7 @@
 import           GHC.Generics                (Generic)
 import           HlsPlugins                  (idePlugins)
 import qualified Ide.Plugin.Config           as Plugin
-import           Ide.Types
+import           Ide.Types                   hiding (Config)
 import           Numeric.Natural             (Natural)
 import           System.Console.GetOpt
 import           System.Directory
@@ -176,13 +176,13 @@
 disableAllPluginsBut :: (PluginId -> Bool) -> Plugin.Config
 disableAllPluginsBut pred = def {Plugin.plugins = pluginsMap} where
     pluginsMap = Map.fromList
-        [ (p, def { Plugin.plcGlobalOn = globalOn})
-        | PluginDescriptor{pluginId = plugin@(PluginId p)} <- plugins
+        [ (plugin, def { Plugin.plcGlobalOn = globalOn})
+        | PluginDescriptor{pluginId = plugin} <- plugins
         , let globalOn =
                     -- ghcide-core is required, nothing works without it
-                   plugin == PluginId (pack "ghcide-core")
+                   plugin == "ghcide-core"
                     -- document symbols is required by the benchmark suite
-                || plugin == PluginId (pack "ghcide-hover-and-symbols")
+                || plugin == "ghcide-hover-and-symbols"
                 || pred plugin
         ]
     IdePlugins plugins = idePlugins mempty
diff --git a/bindist/wrapper.in b/bindist/wrapper.in
new file mode 100644
--- /dev/null
+++ b/bindist/wrapper.in
@@ -0,0 +1,186 @@
+#!/bin/sh
+
+exedir="@@EXE_DIR@@"
+executablename="@@EXE_NAME@@"
+GHC_VERSION="@@GHC_VERSION@@"
+
+# This space separated list contains the names and versions of the boot libraries used to compile hls.
+BOOT_PKGS="@@BOOT_PKGS@@"
+# This space separated list contains the ABI hashes of the pkgs in BOOT_PKGS at compiletime.
+ABI_HASHES="@@ABI_HASHES@@"
+
+debug_msg() {
+    if [ -n "$HLS_WRAPPER_DEBUG" ] ; then
+        (>&2 printf "\\033[0;34m%s\\033[0m\\n" "$1")
+    fi
+}
+
+err_msg() {
+    if [ -n "$HLS_WRAPPER_DEBUG" ] ; then
+        (>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
+	elif [ -n "$HLS_WRAPPER_VERBOSE" ] ; then
+        (>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
+    fi
+}
+
+instruction_msg() {
+	(>&2 printf "\\033[0;35m%s\\033[0m\\n" "$1")
+}
+
+err_exit() {
+	msg="Couldn't find a working/matching GHC installation. Consider installing ghc-${GHC_VERSION} via ghcup or build HLS from source."
+	# adjust Content-Length when changing json
+	json="{\"jsonrpc\":\"2.0\", \"method\":\"window/showMessage\", \"params\": {\"type\": 1, \"message\": \"${msg}\"}}"
+	printf "%s\r\n" "Content-Length: 203"
+	printf "%s\r\n"
+	printf "%s" "${json}"
+	unset msg json
+}
+
+err_ghc_pkg() {
+	err_msg "Could not find a ghc-pkg binary (found: $1)!"
+}
+
+err_abi() {
+	err_msg "GHC ABIs don't match!"
+	err_msg ""
+	err_msg "Expected: ${ABI_HASHES}"
+	err_msg "Got:      $1"
+}
+
+err_ver() {
+	err_msg "GHC versions don't match!"
+	err_msg ""
+	err_msg "Expected: ${GHC_VERSION}"
+	err_msg "Got:      $1"
+}
+
+# Check the version of GHC and the ABI.
+check_ghc() {
+	{ [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] ;} && debug_msg "internal error: not enough arguments to check_ghc: 1:$1,2:$2,3:$3" && return 4
+
+	check_ghc_libdir=$1
+	check_ghc_bin=$2
+	GHC_PKG=$3
+	check_ghc_ver="$("${check_ghc_bin}" --numeric-version 2>/dev/null)"
+
+	# check version
+	if [ "${check_ghc_ver}" = "${GHC_VERSION}" ] ; then
+		# check for all packages listed in BOOT_PKGS that they are present with the same ABI hash as at hls-compiletime to prevent linking issues.
+		if "${GHC_PKG}" --version >/dev/null ; then
+			:
+		elif "${GHC_PKG}-${GHC_VERSION}" --version >/dev/null ; then
+			GHC_PKG=${GHC_PKG}-${GHC_VERSION}
+		else
+			err_ghc_pkg "${GHC_PKG}"
+			unset GHC_LIBDIR
+			return 1
+		fi
+		PKGCONF="${check_ghc_libdir}/package.conf.d"
+		MY_ABI_HASHES="$(for dep in ${BOOT_PKGS} ; do printf "%s:" "${dep}" && "${GHC_PKG}" --global --global-package-db "$PKGCONF" field "${dep}" abi --simple-output ; done | tr '\n' ' ' | xargs)"
+		if [ "${ABI_HASHES}" != "${MY_ABI_HASHES}" ] ; then
+			err_abi "${MY_ABI_HASHES}"
+			return 3
+		fi
+		unset PKGCONF
+	else
+		err_ver "${check_ghc_ver}"
+		unset GHC_LIBDIR
+		return 2
+	fi
+
+	unset check_ghc_libdir check_ghc_bindir GHC_PKG check_ghc_ver
+}
+
+# Infer ghc-pkg from the given ghc path. Doesn't check for existence of any
+# components.
+infer_ghc_pkg() {
+	infer_ghc_path=$1
+	infer_ghc_bin=${infer_ghc_path##**/}
+	infer_ghc_ver_suffix=${infer_ghc_bin#ghc}
+	path_prefix="$(dirname "${infer_ghc_path}")"
+
+	if [ "${path_prefix}" = "." ] ; then
+		echo "ghc-pkg${infer_ghc_ver_suffix}"
+	elif [ "${path_prefix}" = "/" ] ; then
+		echo "${path_prefix}ghc-pkg${infer_ghc_ver_suffix}"
+	else
+		echo "${path_prefix}/ghc-pkg${infer_ghc_ver_suffix}"
+	fi
+	unset infer_ghc_path infer_ghc_bin infer_ghc_ver_suffix path_prefix
+}
+
+# try GHC_LIBDIR from the environment (e.g. user set it, or haskell-language-server-wrapper)
+if [ -n "${GHC_LIBDIR}" ] &&
+	[ -n "${GHC_BIN}" ] &&
+	{ debug_msg "Trying method: GHC_LIBDIR and GHC_BIN from env" ; HLS_WRAPPER_VERBOSE=1 ; check_ghc "${GHC_LIBDIR}" "${GHC_BIN}" "$(infer_ghc_pkg "${GHC_BIN}")" || { err_exit ; exit 1 ; } ; }
+then
+	:
+# try GHC_BIN from the environment (e.g. user set it)
+elif [ -n "${GHC_BIN}" ] &&
+	GHC_LIBDIR="$("${GHC_BIN}" --print-libdir)" &&
+	{ debug_msg "Trying method: GHC_BIN from env" ; HLS_WRAPPER_VERBOSE=1 ; check_ghc "${GHC_LIBDIR}" "${GHC_BIN}" "$(infer_ghc_pkg "${GHC_BIN}")" || { err_exit ; exit 2 ; } ; }
+then
+	:
+# try ghcup
+elif command -v ghcup >/dev/null &&
+	GHC_BIN="$(ghcup whereis ghc "${GHC_VERSION}")" &&
+	GHC_LIBDIR="$("${GHC_BIN}" --print-libdir)" &&
+	{ debug_msg "Trying method: ghcup" ; check_ghc "${GHC_LIBDIR}" "${GHC_BIN}" "$(infer_ghc_pkg "${GHC_BIN}")" ; }
+then
+	:
+# try ghc-${GHC_VERSION}
+elif command -v ghc-${GHC_VERSION} >/dev/null &&
+	GHC_LIBDIR="$("ghc-${GHC_VERSION}" --print-libdir)" &&
+	{ debug_msg "Trying method: ghc-${GHC_VERSION} in PATH" ; check_ghc "${GHC_LIBDIR}" "ghc-${GHC_VERSION}" "$(infer_ghc_pkg "ghc-${GHC_VERSION}")" ; }
+then
+	:
+# try ghc
+elif command -v ghc >/dev/null &&
+	GHC_LIBDIR="$(ghc --print-libdir)" &&
+	{ debug_msg "Trying method: ghc in PATH" ; check_ghc "${GHC_LIBDIR}" "ghc" "$(infer_ghc_pkg "ghc")" ; }
+then
+	:
+# try stack
+elif command -v stack >/dev/null &&
+	GHC_BIN="$(cd "$(mktemp -d)" && stack --no-system-ghc --no-install-ghc --resolver "ghc-${GHC_VERSION}" exec sh -- -c 'command -v ghc')" &&
+	GHC_LIBDIR="$("${GHC_BIN}" --print-libdir)" &&
+	{ debug_msg "Trying method: stack" ; check_ghc "${GHC_LIBDIR}" "${GHC_BIN}" "$(infer_ghc_pkg "${GHC_BIN}")" ; }
+then
+	:
+else
+	HLS_WRAPPER_VERBOSE=1
+	err_msg "All methods exhausted!"
+	err_exit
+	err_msg "exiting..."
+	exit 42
+fi
+
+debug_msg "Found GHC libdir at: ${GHC_LIBDIR}"
+
+case "$(uname -s)" in
+	"Darwin"|"darwin")
+		if [ -n "$DYLD_LIBRARY_PATH" ] ; then
+			DYLD_LIBRARY_PATH="$(for i in "${GHC_LIBDIR}"/* ; do [ -d "$i" ] && printf "%s" "$i:" ; done)$DYLD_LIBRARY_PATH"
+			debug_msg "Exporting DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}"
+			export DYLD_LIBRARY_PATH
+		else
+			DYLD_LIBRARY_PATH="$(for i in "${GHC_LIBDIR}"/* ; do [ -d "$i" ] && printf "%s" "$i:" ; done | sed 's/:$//')"
+			debug_msg "Exporting DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}"
+			export DYLD_LIBRARY_PATH
+		fi
+		;;
+	*)
+		if [ -n "$LD_LIBRARY_PATH" ] ; then
+			LD_LIBRARY_PATH="$(for i in "${GHC_LIBDIR}"/* ; do [ -d "$i" ] && printf "%s" "$i:" ; done)$LD_LIBRARY_PATH"
+			debug_msg "Exporting LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
+			export LD_LIBRARY_PATH
+		else
+			LD_LIBRARY_PATH="$(for i in "${GHC_LIBDIR}"/* ; do [ -d "$i" ] && printf "%s" "$i:" ; done | sed 's/:$//')"
+			debug_msg "Exporting LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
+			export LD_LIBRARY_PATH
+		fi
+		;;
+esac
+
+exec "${exedir}/${executablename}" ${1+"$@"}
diff --git a/exe/Wrapper.hs b/exe/Wrapper.hs
--- a/exe/Wrapper.hs
+++ b/exe/Wrapper.hs
@@ -12,11 +12,11 @@
 module Main where
 
 import           Control.Monad.Extra
-import           Data.Char                          (isSpace)
 import           Data.Default
 import           Data.Either.Extra                  (eitherToMaybe)
 import           Data.Foldable
 import           Data.List
+import           Data.List.Extra                    (trimEnd)
 import           Data.Void
 import qualified Development.IDE.Session            as Session
 import qualified HIE.Bios.Environment               as HieBios
@@ -54,6 +54,7 @@
                                                      makeDefaultStderrRecorder)
 import           GHC.Stack.Types                    (emptyCallStack)
 import           Ide.Plugin.Config                  (Config)
+import           Ide.Types                          (IdePlugins (IdePlugins))
 import           Language.LSP.Server                (LspM)
 import qualified Language.LSP.Server                as LSP
 import           Language.LSP.Types                 (MessageActionItem (MessageActionItem),
@@ -232,7 +233,7 @@
 trim :: String -> String
 trim s = case lines s of
   [] -> s
-  ls -> dropWhileEnd isSpace $ last ls
+  ls -> trimEnd $ last ls
 
 data WrapperSetupError
     = FailedToObtainGhcVersion (ActionName Void) CradleError
@@ -276,7 +277,7 @@
 
   let logger = Logger $ \p m -> logger_ recorder (WithPriority p emptyCallStack (pretty m))
 
-  let defaultArguments = Main.defaultArguments (cmapWithPrio pretty recorder) logger
+  let defaultArguments = Main.defaultArguments (cmapWithPrio pretty recorder) logger (IdePlugins [])
 
   inH <- Main.argsHandleIn defaultArguments
 
diff --git a/haskell-language-server.cabal b/haskell-language-server.cabal
--- a/haskell-language-server.cabal
+++ b/haskell-language-server.cabal
@@ -1,7 +1,7 @@
 cabal-version:      3.0
 category:           Development
 name:               haskell-language-server
-version:            1.8.0.0
+version:            1.9.0.0
 synopsis:           LSP server for GHC
 description:
   Please see the README on GitHub at <https://github.com/haskell/haskell-language-server#readme>
@@ -14,7 +14,7 @@
 license:            Apache-2.0
 license-file:       LICENSE
 build-type:         Simple
-tested-with:        GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.3 || == 9.2.4
+tested-with:        GHC == 8.10.7 || == 9.0.2 || ==9.2.5
 extra-source-files:
   README.md
   ChangeLog.md
@@ -22,6 +22,7 @@
   test/testdata/**/*.cabal
   test/testdata/**/*.yaml
   test/testdata/**/*.hs
+  bindist/wrapper.in
 
 flag pedantic
   description: Enable -Werror
@@ -62,6 +63,12 @@
   default:     False
   manual:      True
 
+
+flag cabal
+  description: Enable cabal plugin
+  default:     True
+  manual:      True
+
 flag class
   description: Enable class plugin
   default:     True
@@ -162,6 +169,11 @@
   default:     True
   manual:      True
 
+flag explicitFields
+  description: Enable explicitFields plugin
+  default:     True
+  manual:      True
+
 -- formatters
 
 flag floskell
@@ -199,8 +211,23 @@
   default:     True
   manual:      True
 
+flag cabalfmt
+  description: Enable cabal-fmt plugin
+  default:     True
+  manual:      True
+
+common cabalfmt
+  if flag(cabalfmt)
+    build-depends: hls-cabal-fmt-plugin ^>= 0.1.0.0
+    cpp-options: -Dhls_cabalfmt
+
+common cabal
+  if flag(cabal)
+    build-depends: hls-cabal-plugin ^>= 0.1
+    cpp-options: -Dhls_cabal
+
 common class
-  if flag(class) && (impl(ghc < 9.4.1) || flag(ignore-plugins-ghc-bounds))
+  if flag(class)
     build-depends: hls-class-plugin ^>= 1.1
     cpp-options: -Dhls_class
 
@@ -216,12 +243,12 @@
 
 common eval
   if flag(eval) && (impl(ghc < 9.4.1) || flag(ignore-plugins-ghc-bounds))
-    build-depends: hls-eval-plugin ^>= 1.3
+    build-depends: hls-eval-plugin ^>= 1.4
     cpp-options: -Dhls_eval
 
 common importLens
   if flag(importLens)
-    build-depends: hls-explicit-imports-plugin ^>= 1.1
+    build-depends: hls-explicit-imports-plugin ^>= 1.2
     cpp-options: -Dhls_importLens
 
 common refineImports
@@ -235,22 +262,22 @@
     cpp-options: -Dhls_rename
 
 common retrie
-  if flag(retrie) && (impl(ghc < 9.4.1) || flag(ignore-plugins-ghc-bounds))
+  if flag(retrie)
     build-depends: hls-retrie-plugin ^>= 1.0
     cpp-options: -Dhls_retrie
 
 common tactic
   if flag(tactic) && (impl(ghc < 9.2.1) || flag(ignore-plugins-ghc-bounds))
-    build-depends: hls-tactics-plugin ^>= 1.7
+    build-depends: hls-tactics-plugin ^>= 1.8
     cpp-options: -Dhls_tactic
 
 common hlint
-  if flag(hlint) && (impl(ghc < 9.4.1) || flag(ignore-plugins-ghc-bounds))
+  if flag(hlint)
     build-depends: hls-hlint-plugin ^>= 1.1
     cpp-options: -Dhls_hlint
 
 common stan
-  if flag(stan) && (impl(ghc >= 8.8) && impl(ghc < 9.0))
+  if flag(stan) && (impl(ghc >= 8.10) && impl(ghc < 9.0))
     build-depends: hls-stan-plugin ^>= 1.0
     cpp-options: -Dhls_stan
 
@@ -265,13 +292,13 @@
     cpp-options: -Dhls_pragmas
 
 common splice
-  if flag(splice) && (impl(ghc < 9.2.1) || flag(ignore-plugins-ghc-bounds))
+  if flag(splice)
     build-depends: hls-splice-plugin ^>=1.0.0.1
     cpp-options: -Dhls_splice
 
 common alternateNumberFormat
-  if flag(alternateNumberFormat) 
-    build-depends: hls-alternate-number-format-plugin ^>= 1.2
+  if flag(alternateNumberFormat)
+    build-depends: hls-alternate-number-format-plugin ^>= 1.3
     cpp-options: -Dhls_alternateNumberFormat
 
 common qualifyImportedNames
@@ -281,24 +308,29 @@
 
 common codeRange
   if flag(codeRange)
-    build-depends: hls-code-range-plugin ^>= 1.0
+    build-depends: hls-code-range-plugin ^>= 1.1
     cpp-options: -Dhls_codeRange
 
 common changeTypeSignature
   if flag(changeTypeSignature)
-    build-depends: hls-change-type-signature-plugin ^>= 1.0
+    build-depends: hls-change-type-signature-plugin ^>= 1.1
     cpp-options: -Dhls_changeTypeSignature
 
 common gadt
-  if flag(gadt) && (impl(ghc < 9.4.1) || flag(ignore-plugins-ghc-bounds))
+  if flag(gadt)
     build-depends: hls-gadt-plugin ^>= 1.0
     cpp-options: -Dhls_gadt
 
 common explicitFixity
   if flag(explicitFixity)
-    build-depends: hls-explicit-fixity-plugin ^>= 1.0
+    build-depends: hls-explicit-fixity-plugin ^>= 1.1
     cpp-options: -DexplicitFixity
 
+common explicitFields
+  if flag(explicitFields)
+    build-depends: hls-explicit-record-fields-plugin ^>= 1.0
+    cpp-options: -DexplicitFields
+
 -- formatters
 
 common floskell
@@ -307,7 +339,7 @@
     cpp-options: -Dhls_floskell
 
 common fourmolu
-  if flag(fourmolu) && (impl(ghc < 9.4.1) || flag(ignore-plugins-ghc-bounds))
+  if flag(fourmolu)
     build-depends: hls-fourmolu-plugin ^>= 1.1
     cpp-options: -Dhls_fourmolu
 
@@ -323,12 +355,12 @@
 
 common brittany
   if flag(brittany) && (impl(ghc < 9.0.2) || flag(ignore-plugins-ghc-bounds))
-    build-depends: hls-brittany-plugin ^>= 1.0
+    build-depends: hls-brittany-plugin ^>= 1.1
     cpp-options: -Dhls_brittany
 
 common refactor
-  if flag(refactor) && (impl(ghc < 9.4.1) || flag(ignore-plugins-ghc-bounds))
-    build-depends: hls-refactor-plugin ^>= 1.0
+  if flag(refactor)
+    build-depends: hls-refactor-plugin ^>= 1.1
     cpp-options: -Dhls_refactor
 
 library
@@ -337,7 +369,9 @@
                   , warnings
                   , pedantic
                   -- plugins
+                  , cabal
                   , callHierarchy
+                  , cabalfmt
                   , changeTypeSignature
                   , class
                   , haddockComments
@@ -357,6 +391,7 @@
                   , codeRange
                   , gadt
                   , explicitFixity
+                  , explicitFields
                   , floskell
                   , fourmolu
                   , ormolu
@@ -381,12 +416,12 @@
     , cryptohash-sha1
     , data-default
     , ghc
-    , ghcide                ^>=1.8
+    , ghcide                ^>=1.9
     , githash               >=0.1.6.1
     , lsp
     , hie-bios
     , hiedb
-    , hls-plugin-api        ^>=1.5
+    , hls-plugin-api        ^>=1.6
     , optparse-applicative
     , optparse-simple
     , process
@@ -519,11 +554,14 @@
   build-depends:
     , bytestring
     , data-default
+    , deepseq
+    , hashable
     , hspec-expectations
     , lens
     , lens-aeson
     , ghcide
-    , hls-test-utils ^>=1.4
+    , ghcide-test-utils
+    , hls-test-utils ^>=1.5
     , lsp-types
     , aeson
     , hls-plugin-api
@@ -625,6 +663,6 @@
         lens-aeson,
         optparse-applicative,
         shake,
-        shake-bench == 0.1.*,
+        shake-bench == 0.2.*,
         text,
         yaml
diff --git a/src/HlsPlugins.hs b/src/HlsPlugins.hs
--- a/src/HlsPlugins.hs
+++ b/src/HlsPlugins.hs
@@ -6,7 +6,8 @@
 import           Development.IDE.Types.Logger      (Pretty (pretty), Recorder,
                                                     WithPriority, cmapWithPrio)
 import           Ide.PluginUtils                   (pluginDescToIdePlugins)
-import           Ide.Types                         (IdePlugins)
+import           Ide.Types                         (IdePlugins,
+                                                    PluginId (PluginId))
 
 -- fixed plugins
 import           Development.IDE                   (IdeState)
@@ -20,7 +21,9 @@
 #if hls_callHierarchy
 import qualified Ide.Plugin.CallHierarchy          as CallHierarchy
 #endif
-
+#if hls_cabal
+import qualified Ide.Plugin.Cabal                  as Cabal
+#endif
 #if hls_class
 import qualified Ide.Plugin.Class                  as Class
 #endif
@@ -82,17 +85,21 @@
 #endif
 
 #if hls_changeTypeSignature
-import           Ide.Plugin.ChangeTypeSignature    as ChangeTypeSignature
+import qualified Ide.Plugin.ChangeTypeSignature    as ChangeTypeSignature
 #endif
 
 #if hls_gadt
-import           Ide.Plugin.GADT                   as GADT
+import qualified Ide.Plugin.GADT                   as GADT
 #endif
 
 #if explicitFixity
-import           Ide.Plugin.ExplicitFixity         as ExplicitFixity
+import qualified Ide.Plugin.ExplicitFixity         as ExplicitFixity
 #endif
 
+#if explicitFields
+import qualified Ide.Plugin.ExplicitFields         as ExplicitFields
+#endif
+
 -- formatters
 
 #if hls_floskell
@@ -103,6 +110,10 @@
 import qualified Ide.Plugin.Fourmolu               as Fourmolu
 #endif
 
+#if hls_cabalfmt
+import qualified Ide.Plugin.CabalFmt               as CabalFmt
+#endif
+
 #if hls_ormolu
 import qualified Ide.Plugin.Ormolu                 as Ormolu
 #endif
@@ -119,10 +130,10 @@
 import qualified Development.IDE.Plugin.CodeAction as Refactor
 #endif
 
-data Log = forall a. (Pretty a) => Log a
+data Log = forall a. (Pretty a) => Log PluginId a
 
 instance Pretty Log where
-  pretty (Log a) = pretty a
+  pretty (Log (PluginId pId) a) = pretty pId <> ": " <> pretty a
 
 -- ---------------------------------------------------------------------
 
@@ -134,9 +145,12 @@
 idePlugins :: Recorder (WithPriority Log) -> IdePlugins IdeState
 idePlugins recorder = pluginDescToIdePlugins allPlugins
   where
-    pluginRecorder :: forall log. (Pretty log) => Recorder (WithPriority log)
-    pluginRecorder = cmapWithPrio Log recorder
+    pluginRecorder :: forall log. (Pretty log) => PluginId -> Recorder (WithPriority log)
+    pluginRecorder pluginId = cmapWithPrio (Log pluginId) recorder
     allPlugins =
+#if hls_cabal
+      let pId = "cabal" in Cabal.descriptor (pluginRecorder pId) pId :
+#endif
 #if hls_pragmas
       Pragmas.descriptor  "pragmas" :
 #endif
@@ -144,10 +158,13 @@
       Floskell.descriptor "floskell" :
 #endif
 #if hls_fourmolu
-      Fourmolu.descriptor pluginRecorder "fourmolu" :
+      let pId = "fourmolu" in Fourmolu.descriptor (pluginRecorder pId) pId:
 #endif
+#if hls_cabalfmt
+      let pId = "cabalfmt" in CabalFmt.descriptor (pluginRecorder pId) pId:
+#endif
 #if hls_tactic
-      Tactic.descriptor pluginRecorder "tactics" :
+      let pId = "tactics" in Tactic.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_ormolu
       Ormolu.descriptor   "ormolu" :
@@ -156,7 +173,7 @@
       StylishHaskell.descriptor "stylish-haskell" :
 #endif
 #if hls_rename
-      Rename.descriptor pluginRecorder "rename" :
+      let pId = "rename" in Rename.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_retrie
       Retrie.descriptor "retrie" :
@@ -165,59 +182,62 @@
       Brittany.descriptor "brittany" :
 #endif
 #if hls_callHierarchy
-      CallHierarchy.descriptor :
+      CallHierarchy.descriptor "callHierarchy" :
 #endif
 #if hls_class
-      Class.descriptor pluginRecorder "class" :
+      let pId = "class" in Class.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_haddockComments
-      HaddockComments.descriptor pluginRecorder "haddockComments" :
+      let pId = "haddockComments" in HaddockComments.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_eval
-      Eval.descriptor pluginRecorder "eval" :
+      let pId = "eval" in Eval.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_importLens
-      ExplicitImports.descriptor pluginRecorder "importLens" :
+      let pId = "importLens" in ExplicitImports.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_qualifyImportedNames
       QualifyImportedNames.descriptor "qualifyImportedNames" :
 #endif
 #if hls_refineImports
-      RefineImports.descriptor pluginRecorder "refineImports" :
+      let pId = "refineImports" in RefineImports.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_moduleName
-      ModuleName.descriptor pluginRecorder "moduleName" :
+      let pId = "moduleName" in ModuleName.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_hlint
-      Hlint.descriptor pluginRecorder "hlint" :
+      let pId = "hlint" in Hlint.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_stan
-      Stan.descriptor pluginRecorder "stan" :
+      let pId = "stan" in Stan.descriptor (pluginRecorder pId) pId :
 #endif
 #if hls_splice
       Splice.descriptor "splice" :
 #endif
 #if hls_alternateNumberFormat
-      AlternateNumberFormat.descriptor pluginRecorder :
+      let pId = "alternateNumberFormat" in AlternateNumberFormat.descriptor (pluginRecorder pId) pId :
 #endif
 #if hls_codeRange
-      CodeRange.descriptor pluginRecorder "codeRange" :
+      let pId = "codeRange" in CodeRange.descriptor (pluginRecorder pId) pId:
 #endif
 #if hls_changeTypeSignature
-      ChangeTypeSignature.descriptor :
+      ChangeTypeSignature.descriptor "changeTypeSignature" :
 #endif
 #if hls_gadt
       GADT.descriptor "gadt" :
 #endif
 #if hls_refactor
-      Refactor.iePluginDescriptor pluginRecorder "ghcide-code-actions-imports-exports" :
-      Refactor.typeSigsPluginDescriptor pluginRecorder "ghcide-code-actions-type-signatures" :
-      Refactor.bindingsPluginDescriptor pluginRecorder "ghcide-code-actions-bindings" :
-      Refactor.fillHolePluginDescriptor pluginRecorder "ghcide-code-actions-fill-holes" :
-      Refactor.extendImportPluginDescriptor pluginRecorder "ghcide-extend-import-action" :
+      let pId = "ghcide-code-actions-imports-exports" in Refactor.iePluginDescriptor (pluginRecorder pId) pId :
+      let pId = "ghcide-code-actions-type-signatures" in Refactor.typeSigsPluginDescriptor (pluginRecorder     pId) pId :
+      let pId = "ghcide-code-actions-bindings" in Refactor.bindingsPluginDescriptor (pluginRecorder pId) pId :
+      let pId = "ghcide-code-actions-fill-holes" in Refactor.fillHolePluginDescriptor (pluginRecorder pId) pId :
+      let pId = "ghcide-extend-import-action" in Refactor.extendImportPluginDescriptor (pluginRecorder pId) pId :
 #endif
-      GhcIde.descriptors pluginRecorder
+      GhcIde.descriptors (pluginRecorder "ghcide")
 #if explicitFixity
-      ++ [ExplicitFixity.descriptor pluginRecorder]
+      ++ [let pId = "explicit-fixity" in ExplicitFixity.descriptor (pluginRecorder pId) pId]
+#endif
+#if explicitFields
+      ++ [let pId = "explicit-fields" in ExplicitFields.descriptor (pluginRecorder pId) pId]
 #endif
 
diff --git a/src/Ide/Arguments.hs b/src/Ide/Arguments.hs
--- a/src/Ide/Arguments.hs
+++ b/src/Ide/Arguments.hs
@@ -66,6 +66,10 @@
     opts = info ((
       VersionMode <$> printVersionParser exeName
       <|> probeToolsParser exeName
+      <|> hsubparser
+        (  command "vscode-extension-schema" extensionSchemaCommand
+        <> command "generate-default-config" generateDefaultConfigCommand
+        )
       <|> listPluginsParser
       <|> BiosMode <$> biosParser
       <|> Ghcide <$> arguments plugins
@@ -75,6 +79,13 @@
       ( fullDesc
      <> progDesc "Used as a test bed to check your IDE Client will work"
      <> header (exeName ++ " - GHC Haskell LSP server"))
+
+    extensionSchemaCommand =
+        info (pure VSCodeExtensionSchemaMode)
+             (fullDesc <> progDesc "Print generic config schema for plugins (used in the package.json of haskell vscode extension)")
+    generateDefaultConfigCommand =
+        info (pure DefaultConfigurationMode)
+             (fullDesc <> progDesc "Print config supported by the server with default values")
 
 printVersionParser :: String -> Parser PrintVersion
 printVersionParser exeName =
diff --git a/src/Ide/Main.hs b/src/Ide/Main.hs
--- a/src/Ide/Main.hs
+++ b/src/Ide/Main.hs
@@ -12,12 +12,13 @@
 
 import           Control.Monad.Extra
 import qualified Data.Aeson.Encode.Pretty      as A
-import qualified Data.ByteString.Lazy.Char8    as LBS
 import           Data.Coerce                   (coerce)
 import           Data.Default
 import           Data.List                     (sort)
 import           Data.Text                     (Text)
 import qualified Data.Text                     as T
+import           Data.Text.Lazy.Encoding       (decodeUtf8)
+import qualified Data.Text.Lazy.IO             as LT
 import           Development.IDE.Core.Rules    hiding (Log, logToPriority)
 import           Development.IDE.Core.Tracing  (withTelemetryLogger)
 import           Development.IDE.Main          (isLSP)
@@ -96,10 +97,9 @@
             runLspMode recorder ghcideArgs idePlugins
 
         VSCodeExtensionSchemaMode -> do
-          LBS.putStrLn $ A.encodePretty $ pluginsToVSCodeExtensionSchema idePlugins
-
+          LT.putStrLn $ decodeUtf8 $ encodePrettySorted $ pluginsToVSCodeExtensionSchema idePlugins
         DefaultConfigurationMode -> do
-          LBS.putStrLn $ A.encodePretty $ pluginsToDefaultConfig idePlugins
+          LT.putStrLn $ decodeUtf8 $ encodePrettySorted $ pluginsToDefaultConfig idePlugins
         PrintLibDir -> do
           d <- getCurrentDirectory
           let initialFp = d </> "a"
@@ -107,6 +107,10 @@
           cradle <- Session.loadCradle def hieYaml d
           (CradleSuccess libdir) <- HieBios.getRuntimeGhcLibDir cradle
           putStr libdir
+  where
+    encodePrettySorted = A.encodePretty' A.defConfig
+      { A.confCompare = compare
+      }
 
 -- ---------------------------------------------------------------------
 
@@ -123,11 +127,10 @@
     -- exists so old-style logging works. intended to be phased out
     let logger = Logger $ \p m -> logger_ recorder (WithPriority p emptyCallStack $ LogOther m)
         args = (if argsTesting then IDEMain.testing else IDEMain.defaultArguments)
-                    (cmapWithPrio LogIDEMain recorder) logger
+                    (cmapWithPrio LogIDEMain recorder) logger idePlugins
 
     IDEMain.defaultMain (cmapWithPrio LogIDEMain recorder) args
       { IDEMain.argCommand = argsCommand
-      , IDEMain.argsHlsPlugins = IDEMain.argsHlsPlugins args <> idePlugins
       , IDEMain.argsLogger = pure logger <> pure telemetryLogger
       , IDEMain.argsThreads = if argsThreads == 0 then Nothing else Just $ fromIntegral argsThreads
       , IDEMain.argsIdeOptions = \config sessionLoader ->
diff --git a/test/functional/Completion.hs b/test/functional/Completion.hs
--- a/test/functional/Completion.hs
+++ b/test/functional/Completion.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 module Completion(tests) where
 
+import           Control.Monad
 import           Control.Lens            hiding ((.=))
 import           Data.Aeson              (object, (.=))
 import           Data.Foldable           (find)
@@ -11,6 +12,15 @@
 import           Test.Hls
 import           Test.Hls.Command
 
+getResolvedCompletions :: TextDocumentIdentifier -> Position -> Session [CompletionItem]
+getResolvedCompletions doc pos = do
+  xs <- getCompletions doc pos
+  forM xs $ \item -> do
+    rsp <- request SCompletionItemResolve item
+    case rsp ^. result of
+      Left err -> liftIO $ assertFailure ("completionItem/resolve failed with: " <> show err)
+      Right x -> pure x
+
 tests :: TestTree
 tests = testGroup "completions" [
      testCase "works" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
@@ -19,34 +29,29 @@
          let te = TextEdit (Range (Position 5 7) (Position 5 24)) "put"
          _ <- applyEdit doc te
 
-         compls <- getCompletions doc (Position 5 9)
+         compls <- getResolvedCompletions doc (Position 5 9)
          item <- getCompletionByLabel "putStrLn" compls
          liftIO $ do
              item ^. label @?= "putStrLn"
              item ^. kind @?= Just CiFunction
-             item ^. detail @?= Just ":: String -> IO ()"
+             item ^. detail @?= Just ":: String -> IO ()\nfrom Prelude"
              item ^. insertTextFormat @?= Just Snippet
-             item ^. insertText @?= Just "putStrLn ${1:String}"
+             item ^. insertText @?= Just "putStrLn"
 
-     , ignoreTestBecause "no support for itemCompletion/resolve requests"
-       $ testCase "itemCompletion/resolve works" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
+     , testCase "itemCompletion/resolve works" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
          doc <- openDoc "Completion.hs" "haskell"
 
          let te = TextEdit (Range (Position 5 7) (Position 5 24)) "put"
          _ <- applyEdit doc te
 
-         compls <- getCompletions doc (Position 5 9)
+         compls <- getResolvedCompletions doc (Position 5 9)
          item <- getCompletionByLabel "putStrLn" compls
-         resolvedRes <- request SCompletionItemResolve item
-         let eResolved = resolvedRes ^. result
-         case eResolved of
-             Right resolved -> liftIO $ do
-                 resolved ^. label @?= "putStrLn"
-                 resolved ^. kind @?= Just CiFunction
-                 resolved ^. detail @?= Just "String -> IO ()\nPrelude"
-                 resolved ^. insertTextFormat @?= Just Snippet
-                 resolved ^. insertText @?= Just "putStrLn ${1:String}"
-             _ -> error $ "Unexpected resolved value: " ++ show eResolved
+         liftIO $ do
+                 item ^. label @?= "putStrLn"
+                 item ^. kind @?= Just CiFunction
+                 item ^. detail @?= Just ":: String -> IO ()\nfrom Prelude"
+                 item ^. insertTextFormat @?= Just Snippet
+                 item ^. insertText @?= Just "putStrLn"
 
      , testCase "completes imports" $ runSession (hlsCommand <> " --test") fullCaps "test/testdata/completion" $ do
          doc <- openDoc "Completion.hs" "haskell"
@@ -56,7 +61,7 @@
          let te = TextEdit (Range (Position 1 17) (Position 1 26)) "Data.M"
          _ <- applyEdit doc te
 
-         compls <- getCompletions doc (Position 1 23)
+         compls <- getResolvedCompletions doc (Position 1 23)
          item <- getCompletionByLabel "Maybe" compls
          liftIO $ do
              item ^. label @?= "Maybe"
@@ -71,7 +76,7 @@
          let te = TextEdit (Range (Position 2 17) (Position 2 25)) "Data.L"
          _ <- applyEdit doc te
 
-         compls <- getCompletions doc (Position 2 24)
+         compls <- getResolvedCompletions doc (Position 2 24)
          item <- getCompletionByLabel "List" compls
          liftIO $ do
              item ^. label @?= "List"
@@ -81,9 +86,35 @@
      , testCase "completes with no prefix" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
          doc <- openDoc "Completion.hs" "haskell"
 
-         compls <- getCompletions doc (Position 5 7)
+         compls <- getResolvedCompletions doc (Position 5 7)
          liftIO $ assertBool "Expected completions" $ not $ null compls
 
+     , expectFailIfBeforeGhc92 "record dot syntax is introduced in GHC 9.2"
+       $ testGroup "recorddotsyntax"
+        [ testCase "shows field selectors" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
+            doc <- openDoc "RecordDotSyntax.hs" "haskell"
+
+            let te = TextEdit (Range (Position 25 0) (Position 25 5)) "z = x.a"
+            _ <- applyEdit doc te
+
+            compls <- getResolvedCompletions doc (Position 25 6)
+            item <- getCompletionByLabel "a" compls
+
+            liftIO $ do
+                item ^. label @?= "a"
+        , testCase "shows field selectors for nested field" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
+            doc <- openDoc "RecordDotSyntax.hs" "haskell"
+
+            let te = TextEdit (Range (Position 27 0) (Position 27 8)) "z2 = x.c.z"
+            _ <- applyEdit doc te
+
+            compls <- getResolvedCompletions doc (Position 27 9)
+            item <- getCompletionByLabel "z" compls
+
+            liftIO $ do
+                item ^. label @?= "z"
+        ]
+
      -- See https://github.com/haskell/haskell-ide-engine/issues/903
      , testCase "strips compiler generated stuff from completions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
          doc <- openDoc "DupRecFields.hs" "haskell"
@@ -91,7 +122,7 @@
          let te = TextEdit (Range (Position 5 0) (Position 5 2)) "acc"
          _ <- applyEdit doc te
 
-         compls <- getCompletions doc (Position 5 4)
+         compls <- getResolvedCompletions doc (Position 5 4)
          item <- getCompletionByLabel "accessor" compls
          liftIO $ do
              item ^. label @?= "accessor"
@@ -101,25 +132,25 @@
 
          let te = TextEdit (Range (Position 5 7) (Position 5 9)) "id"
          _ <- applyEdit doc te
-         compls <- getCompletions doc (Position 5 9)
+         compls <- getResolvedCompletions doc (Position 5 9)
          item <- getCompletionByLabel "id" compls
          liftIO $ do
-             item ^. detail @?= Just ":: a -> a"
+             item ^. detail @?= Just ":: a -> a\nfrom Prelude"
 
      , testCase "have implicit foralls with multiple type variables" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
          doc <- openDoc "Completion.hs" "haskell"
 
          let te = TextEdit (Range (Position 5 7) (Position 5 24)) "flip"
          _ <- applyEdit doc te
-         compls <- getCompletions doc (Position 5 11)
+         compls <- getResolvedCompletions doc (Position 5 11)
          item <- getCompletionByLabel "flip" compls
          liftIO $
-             item ^. detail @?= Just ":: (a -> b -> c) -> b -> a -> c"
+             item ^. detail @?= Just ":: (a -> b -> c) -> b -> a -> c\nfrom Prelude"
 
      , testCase "maxCompletions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
          doc <- openDoc "Completion.hs" "haskell"
 
-         compls <- getCompletions doc (Position 5 7)
+         compls <- getResolvedCompletions doc (Position 5 7)
          liftIO $ length compls @?= maxCompletions def
 
      , testCase "import function completions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
@@ -128,7 +159,7 @@
          let te = TextEdit (Range (Position 0 30) (Position 0 41)) "A"
          _ <- applyEdit doc te
 
-         compls <- getCompletions doc (Position 0 31)
+         compls <- getResolvedCompletions doc (Position 0 31)
          item <- getCompletionByLabel "Alternative" compls
          liftIO $ do
              item ^. label @?= "Alternative"
@@ -141,7 +172,7 @@
          let te = TextEdit (Range (Position 0 39) (Position 0 39)) ", l"
          _ <- applyEdit doc te
 
-         compls <- getCompletions doc (Position 0 42)
+         compls <- getResolvedCompletions doc (Position 0 42)
          item <- getCompletionByLabel "liftA" compls
          liftIO $ do
              item ^. label @?= "liftA"
@@ -151,7 +182,7 @@
      , testCase "completes locally defined associated type family" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
          doc <- openDoc "AssociatedTypeFamily.hs" "haskell"
 
-         compls <- getCompletions doc (Position 5 20)
+         compls <- getResolvedCompletions doc (Position 5 20)
          item <- getCompletionByLabel "Fam" compls
          liftIO $ do
              item ^. label @?= "Fam"
@@ -169,7 +200,7 @@
       let te = TextEdit (Range (Position 5 7) (Position 5 24)) "Nothing"
       _ <- applyEdit doc te
 
-      compls <- getCompletions doc (Position 5 14)
+      compls <- getResolvedCompletions doc (Position 5 14)
       item <- getCompletionByLabel "Nothing" compls
       liftIO $ do
           item ^. insertTextFormat @?= Just Snippet
@@ -181,13 +212,13 @@
         let te = TextEdit (Range (Position 5 7) (Position 5 24)) "fold"
         _ <- applyEdit doc te
 
-        compls <- getCompletions doc (Position 5 11)
+        compls <- getResolvedCompletions doc (Position 5 11)
         item <- getCompletionByLabel "foldl" compls
         liftIO $ do
             item ^. label @?= "foldl"
             item ^. kind @?= Just CiFunction
             item ^. insertTextFormat @?= Just Snippet
-            item ^. insertText @?= Just "foldl ${1:(b -> a -> b)} ${2:b} ${3:(t a)}"
+            item ^. insertText @?= Just "foldl"
 
     , testCase "work for complex types" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
         doc <- openDoc "Completion.hs" "haskell"
@@ -195,13 +226,13 @@
         let te = TextEdit (Range (Position 5 7) (Position 5 24)) "mapM"
         _ <- applyEdit doc te
 
-        compls <- getCompletions doc (Position 5 11)
+        compls <- getResolvedCompletions doc (Position 5 11)
         item <- getCompletionByLabel "mapM" compls
         liftIO $ do
             item ^. label @?= "mapM"
             item ^. kind @?= Just CiFunction
             item ^. insertTextFormat @?= Just Snippet
-            item ^. insertText @?= Just "mapM ${1:(a -> m b)} ${2:(t a)}"
+            item ^. insertText @?= Just "mapM"
 
     , testCase "work for infix functions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
         doc <- openDoc "Completion.hs" "haskell"
@@ -209,7 +240,7 @@
         let te = TextEdit (Range (Position 5 7) (Position 5 24)) "even `filte"
         _ <- applyEdit doc te
 
-        compls <- getCompletions doc (Position 5 18)
+        compls <- getResolvedCompletions doc (Position 5 18)
         item <- getCompletionByLabel "filter" compls
         liftIO $ do
             item ^. label @?= "filter"
@@ -223,7 +254,7 @@
         let te = TextEdit (Range (Position 5 7) (Position 5 24)) "even `filte`"
         _ <- applyEdit doc te
 
-        compls <- getCompletions doc (Position 5 18)
+        compls <- getResolvedCompletions doc (Position 5 18)
         item <- getCompletionByLabel "filter" compls
         liftIO $ do
             item ^. label @?= "filter"
@@ -237,7 +268,7 @@
         let te = TextEdit (Range (Position 5 7) (Position 5 24)) "\"\" `Data.List.interspe"
         _ <- applyEdit doc te
 
-        compls <- getCompletions doc (Position 5 29)
+        compls <- getResolvedCompletions doc (Position 5 29)
         item <- getCompletionByLabel "intersperse" compls
         liftIO $ do
             item ^. label @?= "intersperse"
@@ -251,7 +282,7 @@
         let te = TextEdit (Range (Position 5 7) (Position 5 24)) "\"\" `Data.List.interspe`"
         _ <- applyEdit doc te
 
-        compls <- getCompletions doc (Position 5 29)
+        compls <- getResolvedCompletions doc (Position 5 29)
         item <- getCompletionByLabel "intersperse" compls
         liftIO $ do
             item ^. label @?= "intersperse"
@@ -278,7 +309,7 @@
          let te = TextEdit (Range (Position 1 0) (Position 1 2)) "MkF"
          _ <- applyEdit doc te
 
-         compls <- getCompletions doc (Position 1 6)
+         compls <- getResolvedCompletions doc (Position 1 6)
          item <- case find (\c -> (c ^. label == "MkFoo") && maybe False ("MkFoo {" `T.isPrefixOf`) (c ^. insertText)) compls of
             Just c -> pure c
             Nothing -> liftIO . assertFailure $ "Completion with label 'MkFoo' and insertText starting with 'MkFoo {' not found among " <> show compls
@@ -291,7 +322,7 @@
             let te = TextEdit (Range (Position 5 7) (Position 5 24)) "fold"
             _      <- applyEdit doc te
 
-            compls <- getCompletions doc (Position 5 11)
+            compls <- getResolvedCompletions doc (Position 5 11)
             item <- getCompletionByLabel "foldl" compls
             liftIO $ do
                 item ^. label @?= "foldl"
@@ -316,7 +347,7 @@
     testCase "only provides type suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
       doc <- openDoc "Context.hs" "haskell"
 
-      compls <- getCompletions doc (Position 2 17)
+      compls <- getResolvedCompletions doc (Position 2 17)
       liftIO $ do
         compls `shouldContainCompl` "Integer"
         compls `shouldNotContainCompl` "interact"
@@ -324,7 +355,7 @@
     , testCase "only provides value suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
       doc <- openDoc "Context.hs" "haskell"
 
-      compls <- getCompletions doc (Position 3 10)
+      compls <- getResolvedCompletions doc (Position 3 10)
       liftIO $ do
         compls `shouldContainCompl` "abs"
         compls `shouldNotContainCompl` "Applicative"
@@ -332,7 +363,7 @@
     , testCase "completes qualified type suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
         doc <- openDoc "Context.hs" "haskell"
 
-        compls <- getCompletions doc (Position 2 26)
+        compls <- getResolvedCompletions doc (Position 2 26)
         liftIO $ do
             compls `shouldNotContainCompl` "forkOn"
             compls `shouldContainCompl` "MVar"
@@ -348,3 +379,6 @@
 compls `shouldNotContainCompl` lbl =
     all ((/= lbl) . (^. label)) compls
     @? "Should not contain completion: " ++ show lbl
+
+expectFailIfBeforeGhc92 :: String -> TestTree -> TestTree
+expectFailIfBeforeGhc92 = knownBrokenForGhcVersions [GHC810, GHC90]
diff --git a/test/functional/Config.hs b/test/functional/Config.hs
--- a/test/functional/Config.hs
+++ b/test/functional/Config.hs
@@ -1,11 +1,27 @@
+{-# LANGUAGE DeriveGeneric     #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeApplications  #-}
+{-# LANGUAGE TypeFamilies      #-}
 
 module Config (tests) where
 
+import           Control.DeepSeq
 import           Control.Lens            hiding (List, (.=))
 import           Control.Monad
 import           Data.Aeson
+import           Data.Hashable
+import qualified Data.HashMap.Strict     as HM
+import qualified Data.Map                as Map
 import qualified Data.Text               as T
+import           Data.Typeable           (Typeable)
+import           Development.IDE         (RuleResult, action, define,
+                                          getFilesOfInterestUntracked,
+                                          getPluginConfigAction, ideErrorText,
+                                          uses_)
+import           Development.IDE.Test    (expectDiagnostics)
+import           GHC.Generics
+import           Ide.Plugin.Config
+import           Ide.Types
 import           Language.LSP.Test       as Test
 import qualified Language.LSP.Types.Lens as L
 import           System.FilePath         ((</>))
@@ -18,12 +34,12 @@
 tests = testGroup "plugin config" [
       -- Note: there are more comprehensive tests over config in hls-hlint-plugin
       -- TODO: Add generic tests over some example plugin
-      configTests
+      configParsingTests, genericConfigTests
     ]
 
-configTests :: TestTree
-configTests = testGroup "config parsing" [
-      testCase "empty object as user configuration should not send error logMessage" $ runConfigSession "" $ do
+configParsingTests :: TestTree
+configParsingTests = testGroup "config parsing"
+    [ testCase "empty object as user configuration should not send error logMessage" $ runConfigSession "" $ do
         let config = object []
         sendConfigurationChanged (toJSON config)
 
@@ -36,7 +52,78 @@
                  || "non-existent-method" `T.isInfixOf` (logNot ^. L.params . L.message)
                     @? "Server sends logMessage with MessageType = Error"
     ]
+
     where
         runConfigSession :: FilePath -> Session a -> IO a
         runConfigSession subdir  =
             failIfSessionTimeout . runSession hlsCommand fullCaps ("test/testdata" </> subdir)
+
+genericConfigTests :: TestTree
+genericConfigTests = testGroup "generic plugin config"
+    [
+        testCase "custom defaults" $ runConfigSession "diagnostics" $ do
+            _doc <- createDoc "Foo.hs" "haskell" "module Foo where\nfoo = False"
+            -- getting only the standard diagnostics means the plugin wasn't enabled
+            expectDiagnostics standardDiagnostics
+   ,    testCase "custom defaults and user config on some other plugin" $ runConfigSession "diagnostics" $ do
+            _doc <- createDoc "Foo.hs" "haskell" "module Foo where\nfoo = False"
+            -- test that the user config doesn't accidentally override the initial config
+            sendConfigurationChanged $ toJSON (changeConfig "someplugin" def{plcHoverOn = False})
+            -- getting only the expected diagnostics means the plugin wasn't enabled
+            expectDiagnostics standardDiagnostics
+    ,   expectFailBecause "partial config is not supported" $
+        testCase "custom defaults and non overlapping user config" $ runConfigSession "diagnostics" $ do
+            _doc <- createDoc "Foo.hs" "haskell" "module Foo where\nfoo = False"
+            -- test that the user config doesn't accidentally override the initial config
+            sendConfigurationChanged $ toJSON (changeConfig testPluginId def{plcHoverOn = False})
+            -- getting only the expected diagnostics means the plugin wasn't enabled
+            expectDiagnostics standardDiagnostics
+    ,   testCase "custom defaults and overlapping user plugin config" $ runConfigSession "diagnostics" $ do
+            _doc <- createDoc "Foo.hs" "haskell" "module Foo where\nfoo = False"
+            -- test that the user config overrides the default initial config
+            sendConfigurationChanged $ toJSON (changeConfig testPluginId def{plcGlobalOn = True})
+            -- getting only the expected diagnostics means the plugin wasn't enabled
+            expectDiagnostics testPluginDiagnostics
+    ,   testCase "custom defaults and non plugin user config" $ runConfigSession "diagnostics" $ do
+            _doc <- createDoc "Foo.hs" "haskell" "module Foo where\nfoo = False"
+            -- test that the user config doesn't accidentally override the initial config
+            sendConfigurationChanged $ toJSON (def {formattingProvider = "foo"})
+            -- getting only the expected diagnostics means the plugin wasn't enabled
+            expectDiagnostics standardDiagnostics
+    ]
+    where
+        standardDiagnostics = [("Foo.hs", [(DsWarning, (1,0), "Top-level binding")])]
+        testPluginDiagnostics = [("Foo.hs", [(DsError, (0,0), "testplugin")])]
+
+        runConfigSession subdir =
+            failIfSessionTimeout . runSessionWithServer @() (const plugin) ("test/testdata" </> subdir)
+
+        testPluginId = "testplugin"
+        -- A disabled-by-default plugin that creates diagnostics
+        plugin = (defaultPluginDescriptor testPluginId)
+          {
+            pluginConfigDescriptor = configDisabled
+          , pluginRules = do
+              action $ do
+                plc <- getPluginConfigAction testPluginId
+                when (plcGlobalOn plc && plcDiagnosticsOn plc) $ do
+                    files <- getFilesOfInterestUntracked
+                    void $ uses_ GetTestDiagnostics $ HM.keys files
+              define mempty $ \GetTestDiagnostics file -> do
+                let diags = [ideErrorText file "testplugin"]
+                return (diags,Nothing)
+          }
+        -- A config that disables the plugin initially
+        configDisabled = defaultConfigDescriptor{
+            configInitialGenericConfig = def{plcGlobalOn = False, plcDiagnosticsOn = False}
+        }
+        changeConfig :: PluginId -> PluginConfig -> Config
+        changeConfig plugin conf =
+            def{plugins = Map.fromList [(plugin, conf)]}
+
+
+data GetTestDiagnostics = GetTestDiagnostics
+    deriving (Eq, Show, Typeable, Generic)
+instance Hashable GetTestDiagnostics
+instance NFData   GetTestDiagnostics
+type instance RuleResult GetTestDiagnostics = ()
diff --git a/test/functional/Format.hs b/test/functional/Format.hs
--- a/test/functional/Format.hs
+++ b/test/functional/Format.hs
@@ -6,9 +6,9 @@
 import           Control.Monad.IO.Class
 import           Data.Aeson
 import qualified Data.ByteString.Lazy    as BS
+import qualified Data.Text               as T
 import qualified Data.Text.Encoding      as T
 import qualified Data.Text.IO            as T
-import qualified Data.Text               as T
 import           Language.LSP.Test
 import           Language.LSP.Types
 import qualified Language.LSP.Types.Lens as LSP
@@ -54,7 +54,6 @@
             InvalidRequest | "No plugin enabled for STextDocumentFormatting" `T.isPrefixOf` message -> pure ()
             _ -> assertFailure $ "strange response from formatting provider:" ++ show result
           result -> assertFailure $ "strange response from formatting provider:" ++ show result
-
 
     , requiresOrmoluPlugin . requiresFloskellPlugin $ testCase "can change on the fly" $ runSession hlsCommand fullCaps "test/testdata/format" $ do
         formattedOrmolu <- liftIO $ T.readFile "test/testdata/format/Format.ormolu.formatted.hs"
diff --git a/test/functional/FunctionalCodeAction.hs b/test/functional/FunctionalCodeAction.hs
--- a/test/functional/FunctionalCodeAction.hs
+++ b/test/functional/FunctionalCodeAction.hs
@@ -18,6 +18,7 @@
 import           Test.Hls
 import           Test.Hspec.Expectations
 
+import           Development.IDE.Test    (configureCheckProject)
 import           Test.Hls.Command
 
 {-# ANN module ("HLint: ignore Reduce duplication"::String) #-}
@@ -52,6 +53,7 @@
 
     , testCase "doesn't give both documentChanges and changes"
         $ runSession hlsCommand noLiteralCaps "test/testdata" $ do
+            configureCheckProject False
             doc <- openDoc "CodeActionRename.hs" "haskell"
 
             _ <- waitForDiagnosticsFromSource doc "typecheck"
@@ -104,7 +106,6 @@
 packageTests :: TestTree
 packageTests = testGroup "add package suggestions" [
     ignoreTestBecause "no support for adding dependent packages via code action" $ testCase "adds to .cabal files" $ do
-        flushStackEnvironment
         runSession hlsCommand fullCaps "test/testdata/addPackageTest/cabal-exe" $ do
             doc <- openDoc "AddPackage.hs" "haskell"
 
@@ -175,16 +176,21 @@
             doc <- openDoc "src/CodeActionRedundant.hs" "haskell"
 
             diags <- waitForDiagnosticsFromSource doc "typecheck"
-            liftIO $ expectDiagnostic diags ["The import of", "Data.List", "is redundant"]
+            liftIO $ expectDiagnostic diags [ "The import of", "Data.List", "is redundant" ]
+            liftIO $ expectDiagnostic diags [ "Empty", "from module", "Data.Sequence" ]
 
             mActions <- getAllCodeActions doc
 
             let allActions = map fromAction mActions
                 actionTitles = map (view L.title) allActions
 
-            liftIO $ actionTitles `shouldContain` ["Remove import", "Remove all redundant imports"]
+            liftIO $ actionTitles `shouldContain`
+              [ "Remove import"
+              , "Remove Empty from import"
+              , "Remove all redundant imports"
+              ]
 
-            let mbRemoveAction = find (\x -> x ^. L.title == "Remove import") allActions
+            let mbRemoveAction = find (\x -> x ^. L.title == "Remove all redundant imports") allActions
 
             case mbRemoveAction of
                 Just removeAction -> do
@@ -201,7 +207,17 @@
             -- provides workspace edit property which skips round trip to
             -- the server
             contents <- documentContents doc
-            liftIO $ contents @?= "{-# OPTIONS_GHC -Wunused-imports #-}\nmodule CodeActionRedundant where\nmain :: IO ()\nmain = putStrLn \"hello\"\n"
+            liftIO $ contents @?= T.unlines
+              [ "{-# OPTIONS_GHC -Wunused-imports #-}"
+              , "{-# LANGUAGE PatternSynonyms #-}"
+              , "module CodeActionRedundant where"
+              , "-- We need a non-reduntant import in the import list"
+              , "-- to properly test the removal of the singular redundant item"
+              , "import Data.Sequence (singleton)"
+              , "main :: IO ()"
+              , "main = putStrLn \"hello\""
+              , "  where unused = Data.Sequence.singleton 42"
+              ]
 
     , testCase "doesn't touch other imports" $ runSession hlsCommand noLiteralCaps "test/testdata/redundantImportTest/" $ do
         doc <- openDoc "src/MultipleImports.hs" "haskell"
@@ -244,15 +260,15 @@
                     , "foo x = maxBound"
                     ]
 
-      , expectFailIfGhc92 "The wingman plugin doesn't yet compile in GHC92" $
-        testCase "doesn't work when wingman is active" $
-        runSession hlsCommand fullCaps "test/testdata" $ do
-            doc <- openDoc "TypedHoles.hs" "haskell"
-            _ <- waitForDiagnosticsFromSource doc "typecheck"
-            cas <- getAllCodeActions doc
-            liftIO $ do
-                dontExpectCodeAction cas ["replace _ with minBound"]
-                dontExpectCodeAction cas ["replace _ with foo _"]
+      , knownBrokenForGhcVersions [GHC92, GHC94] "The wingman plugin doesn't yet compile in GHC92/GHC94" $
+          testCase "doesn't work when wingman is active" $
+          runSession hlsCommand fullCaps "test/testdata" $ do
+              doc <- openDoc "TypedHoles.hs" "haskell"
+              _ <- waitForDiagnosticsFromSource doc "typecheck"
+              cas <- getAllCodeActions doc
+              liftIO $ do
+                  dontExpectCodeAction cas ["replace _ with minBound"]
+                  dontExpectCodeAction cas ["replace _ with foo _"]
 
       , testCase "shows more suggestions" $
             runSession hlsCommand fullCaps "test/testdata" $ do
@@ -279,7 +295,7 @@
                         , "    stuff (A a) = A (a + 1)"
                         ]
 
-      , expectFailIfGhc92 "The wingman plugin doesn't yet compile in GHC92" $
+      , knownBrokenForGhcVersions [GHC92, GHC94] "The wingman plugin doesn't yet compile in GHC92/GHC94" $
           testCase "doesnt show more suggestions when wingman is active" $
             runSession hlsCommand fullCaps "test/testdata" $ do
                 doc <- openDoc "TypedHoles2.hs" "haskell"
@@ -367,9 +383,6 @@
             assertBool "Quick fixes should have been filtered out"
               $ Just CodeActionQuickFix `notElem` kinds
     ]
-
-expectFailIfGhc92 :: String -> TestTree -> TestTree
-expectFailIfGhc92 = knownBrokenForGhcVersions [GHC92]
 
 disableWingman :: Session ()
 disableWingman =
diff --git a/test/functional/TypeDefinition.hs b/test/functional/TypeDefinition.hs
--- a/test/functional/TypeDefinition.hs
+++ b/test/functional/TypeDefinition.hs
@@ -13,8 +13,7 @@
         $ getTypeDefinitionTest' 15 21 12 0
     , testCase "finds local definition of sum type variable"
         $ getTypeDefinitionTest' 20 13 17 0
-    , knownBrokenForGhcVersions [GHC88] "Definition of sum type not found from data constructor in GHC 8.8.x" $
-      testCase "finds local definition of sum type constructor"
+    , testCase "finds local definition of sum type constructor"
         $ getTypeDefinitionTest' 23 7 17 0
     , testCase "finds non-local definition of type def"
         $ getTypeDefinitionTest' 29 19 26 0
diff --git a/test/testdata/completion/RecordDotSyntax.hs b/test/testdata/completion/RecordDotSyntax.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/completion/RecordDotSyntax.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE OverloadedRecordDot #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE NoFieldSelectors #-}
+
+module Test where
+
+import qualified Data.Maybe as M
+
+data MyRecord = MyRecord1
+  { a :: String
+  , b :: Integer
+  , c :: MyChild
+  }
+  | MyRecord2 { a2 :: String
+  , b2 :: Integer
+  , c2 :: MyChild
+  } deriving (Eq, Show)
+
+newtype MyChild = MyChild
+  { z :: String
+  } deriving (Eq, Show)
+
+x = MyRecord1 { a = "Hello", b = 12, c = MyChild { z = "there" } }
+
+y = x.a ++ show x.b 
+
+y2 = x.c.z 
+
diff --git a/test/testdata/hieBiosError/hie.yaml b/test/testdata/hieBiosError/hie.yaml
deleted file mode 100644
--- a/test/testdata/hieBiosError/hie.yaml
+++ /dev/null
diff --git a/test/testdata/redundantImportTest/src/CodeActionRedundant.hs b/test/testdata/redundantImportTest/src/CodeActionRedundant.hs
--- a/test/testdata/redundantImportTest/src/CodeActionRedundant.hs
+++ b/test/testdata/redundantImportTest/src/CodeActionRedundant.hs
@@ -1,5 +1,10 @@
 {-# OPTIONS_GHC -Wunused-imports #-}
+{-# LANGUAGE PatternSynonyms #-}
 module CodeActionRedundant where
 import Data.List
+-- We need a non-reduntant import in the import list
+-- to properly test the removal of the singular redundant item
+import Data.Sequence (pattern Empty, singleton)
 main :: IO ()
 main = putStrLn "hello"
+  where unused = Data.Sequence.singleton 42
diff --git a/test/testdata/wErrorTest/dist-newstyle/build/x86_64-linux/ghc-8.10.3/test-0.1.0.0/build/autogen/Paths_test.hs b/test/testdata/wErrorTest/dist-newstyle/build/x86_64-linux/ghc-8.10.3/test-0.1.0.0/build/autogen/Paths_test.hs
deleted file mode 100644
--- a/test/testdata/wErrorTest/dist-newstyle/build/x86_64-linux/ghc-8.10.3/test-0.1.0.0/build/autogen/Paths_test.hs
+++ /dev/null
@@ -1,50 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE NoRebindableSyntax #-}
-{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}
-module Paths_test (
-    version,
-    getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir,
-    getDataFileName, getSysconfDir
-  ) where
-
-import qualified Control.Exception as Exception
-import Data.Version (Version(..))
-import System.Environment (getEnv)
-import Prelude
-
-#if defined(VERSION_base)
-
-#if MIN_VERSION_base(4,0,0)
-catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
-#else
-catchIO :: IO a -> (Exception.Exception -> IO a) -> IO a
-#endif
-
-#else
-catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
-#endif
-catchIO = Exception.catch
-
-version :: Version
-version = Version [0,1,0,0] []
-bindir, libdir, dynlibdir, datadir, libexecdir, sysconfdir :: FilePath
-
-bindir     = "/home/zubin/.cabal/bin"
-libdir     = "/home/zubin/.cabal/lib/x86_64-linux-ghc-8.10.3/test-0.1.0.0-inplace"
-dynlibdir  = "/home/zubin/.cabal/lib/x86_64-linux-ghc-8.10.3"
-datadir    = "/home/zubin/.cabal/share/x86_64-linux-ghc-8.10.3/test-0.1.0.0"
-libexecdir = "/home/zubin/.cabal/libexec/x86_64-linux-ghc-8.10.3/test-0.1.0.0"
-sysconfdir = "/home/zubin/.cabal/etc"
-
-getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir, getSysconfDir :: IO FilePath
-getBinDir = catchIO (getEnv "test_bindir") (\_ -> return bindir)
-getLibDir = catchIO (getEnv "test_libdir") (\_ -> return libdir)
-getDynLibDir = catchIO (getEnv "test_dynlibdir") (\_ -> return dynlibdir)
-getDataDir = catchIO (getEnv "test_datadir") (\_ -> return datadir)
-getLibexecDir = catchIO (getEnv "test_libexecdir") (\_ -> return libexecdir)
-getSysconfDir = catchIO (getEnv "test_sysconfdir") (\_ -> return sysconfdir)
-
-getDataFileName :: FilePath -> IO FilePath
-getDataFileName name = do
-  dir <- getDataDir
-  return (dir ++ "/" ++ name)
diff --git a/test/wrapper/Main.hs b/test/wrapper/Main.hs
--- a/test/wrapper/Main.hs
+++ b/test/wrapper/Main.hs
@@ -5,14 +5,11 @@
 import           Test.Hls
 
 main :: IO ()
-main = do
-  flushStackEnvironment
-  defaultTestRunner $ testGroup "haskell-language-server-wrapper" [projectGhcVersionTests]
+main = defaultTestRunner $ testGroup "haskell-language-server-wrapper" [projectGhcVersionTests]
 
 projectGhcVersionTests :: TestTree
 projectGhcVersionTests = testGroup "--project-ghc-version"
   [ stackTest "8.10.7"
-  , stackTest "8.8.4"
   , testCase "cabal with global ghc" $ do
       ghcVer <- trimEnd <$> readProcess "ghc" ["--numeric-version"] ""
       testDir "test/wrapper/testdata/cabal-cur-ver" ghcVer
