Skip to content

Commit 9207050

Browse files
isovectorjneira
andauthored
Disable hole fit suggestions when running Wingman (#1873)
* Disable hole fit suggestions for EXTREME SPEED * Note the new behavior in the README * Disable the tests * Update documentation * Fix tests properly * Tests that code actions don't appear when Wingman is enabled * Unset dynflags rather than change their values * Fix error message * Revert "Unset dynflags rather than change their values" This reverts commit 940c535. * Maybe try unsetting it too? * Maybe this will elucidate the error * Disable tests on GHC9 because tactics doesn't build on GHC9 * Revert "Maybe this will elucidate the error" This reverts commit 6c5b835. Co-authored-by: Javier Neira <[email protected]>
1 parent f9042bf commit 9207050

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

Diff for: hls-test-utils/src/Test/Hls/Util.hs

+14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Test.Hls.Util
1010
(
1111
codeActionSupportCaps
1212
, expectCodeAction
13+
, dontExpectCodeAction
1314
, expectDiagnostic
1415
, expectNoMoreDiagnostics
1516
, expectSameLocations
@@ -45,6 +46,7 @@ import Control.Lens ((^.))
4546
import Control.Monad
4647
import Control.Monad.IO.Class
4748
import qualified Data.Aeson as A
49+
import Data.Bool (bool)
4850
import Data.Default
4951
import Data.List (intercalate)
5052
import Data.List.Extra (find)
@@ -315,6 +317,10 @@ fromCommand _ = error "Not a command"
315317
onMatch :: [a] -> (a -> Bool) -> String -> IO a
316318
onMatch as predicate err = maybe (fail err) return (find predicate as)
317319

320+
noMatch :: [a] -> (a -> Bool) -> String -> IO ()
321+
noMatch [] _ _ = pure ()
322+
noMatch as predicate err = bool (pure ()) (fail err) (any predicate as)
323+
318324
inspectDiagnostic :: [Diagnostic] -> [T.Text] -> IO Diagnostic
319325
inspectDiagnostic diags s = onMatch diags (\ca -> all (`T.isInfixOf` (ca ^. L.message)) s) err
320326
where err = "expected diagnostic matching '" ++ show s ++ "' but did not find one"
@@ -331,6 +337,14 @@ inspectCodeAction cars s = fromAction <$> onMatch cars predicate err
331337
expectCodeAction :: [Command |? CodeAction] -> [T.Text] -> IO ()
332338
expectCodeAction cars s = void $ inspectCodeAction cars s
333339

340+
dontExpectCodeAction :: [Command |? CodeAction] -> [T.Text] -> IO ()
341+
dontExpectCodeAction cars s =
342+
noMatch cars predicate err
343+
where predicate (InR ca) = all (`T.isInfixOf` (ca ^. L.title)) s
344+
predicate _ = False
345+
err = "didn't expected code action matching '" ++ show s ++ "' but found one anyway"
346+
347+
334348
inspectCommand :: [Command |? CodeAction] -> [T.Text] -> IO Command
335349
inspectCommand cars s = fromCommand <$> onMatch cars predicate err
336350
where predicate (InL command) = all (`T.isInfixOf` (command ^. L.title)) s

Diff for: plugins/hls-tactics-plugin/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ fill hole" code action, *et voila!*
3434
[hls]: https://github.com/haskell/haskell-language-server/releases
3535

3636

37+
## Usage
38+
39+
When enabled, Wingman for Haskell will remove HLS support for hole-fit code
40+
actions. These code actions are provided by GHC and make typechecking extremely
41+
slow in the presence of typed holes. Because Wingman relies so heavily on typed
42+
holes, these features are in great tension.
43+
44+
The solution: we just remove the hole-fit actions. If you'd prefer to use these
45+
actions, you can get them back by compiling HLS without the Wingman plugin.
46+
47+
3748
## Editor Configuration
3849

3950
### Enabling Jump to Hole

Diff for: plugins/hls-tactics-plugin/src/Wingman/StaticPlugin.hs

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,17 @@ staticPlugin :: DynFlagsModifications
1919
staticPlugin = mempty
2020
{ dynFlagsModifyGlobal =
2121
\df -> allowEmptyCaseButWithWarning
22+
$ flip gopt_unset Opt_SortBySubsumHoleFits
23+
$ flip gopt_unset Opt_ShowValidHoleFits
2224
$ df
25+
{ refLevelHoleFits = Just 0
26+
, maxRefHoleFits = Just 0
27+
, maxValidHoleFits = Just 0
28+
#if __GLASGOW_HASKELL__ >= 808
29+
, staticPlugins = staticPlugins df <> [metaprogrammingPlugin]
30+
#endif
31+
}
2332
#if __GLASGOW_HASKELL__ >= 808
24-
{ staticPlugins = staticPlugins df <> [metaprogrammingPlugin] }
2533
, dynFlagsModifyParser = enableQuasiQuotes
2634
#endif
2735
}

Diff for: test/functional/FunctionalCodeAction.hs

+42
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Control.Monad
99
import Data.Aeson
1010
import qualified Data.HashMap.Strict as HM
1111
import Data.List
12+
import qualified Data.Map as M
1213
import Data.Maybe
1314
import qualified Data.Text as T
1415
import Ide.Plugin.Config
@@ -397,10 +398,12 @@ redundantImportTests = testGroup "redundant import code actions" [
397398
]
398399
]
399400

401+
400402
typedHoleTests :: TestTree
401403
typedHoleTests = testGroup "typed hole code actions" [
402404
testCase "works" $
403405
runSession hlsCommand fullCaps "test/testdata" $ do
406+
disableWingman
404407
doc <- openDoc "TypedHoles.hs" "haskell"
405408
_ <- waitForDiagnosticsFromSource doc "typecheck"
406409
cas <- getAllCodeActions doc
@@ -419,8 +422,19 @@ typedHoleTests = testGroup "typed hole code actions" [
419422
, "foo x = maxBound"
420423
]
421424

425+
, expectFailIfGhc9 "The wingman plugin doesn't yet compile in GHC9" $
426+
testCase "doesn't work when wingman is active" $
427+
runSession hlsCommand fullCaps "test/testdata" $ do
428+
doc <- openDoc "TypedHoles.hs" "haskell"
429+
_ <- waitForDiagnosticsFromSource doc "typecheck"
430+
cas <- getAllCodeActions doc
431+
liftIO $ do
432+
dontExpectCodeAction cas ["replace _ with minBound"]
433+
dontExpectCodeAction cas ["replace _ with foo _"]
434+
422435
, testCase "shows more suggestions" $
423436
runSession hlsCommand fullCaps "test/testdata" $ do
437+
disableWingman
424438
doc <- openDoc "TypedHoles2.hs" "haskell"
425439
_ <- waitForDiagnosticsFromSource doc "typecheck"
426440
cas <- getAllCodeActions doc
@@ -442,6 +456,17 @@ typedHoleTests = testGroup "typed hole code actions" [
442456
, " where"
443457
, " stuff (A a) = A (a + 1)"
444458
]
459+
460+
, expectFailIfGhc9 "The wingman plugin doesn't yet compile in GHC9" $
461+
testCase "doesnt show more suggestions when wingman is active" $
462+
runSession hlsCommand fullCaps "test/testdata" $ do
463+
doc <- openDoc "TypedHoles2.hs" "haskell"
464+
_ <- waitForDiagnosticsFromSource doc "typecheck"
465+
cas <- getAllCodeActions doc
466+
467+
liftIO $ do
468+
dontExpectCodeAction cas ["replace _ with foo2 _"]
469+
dontExpectCodeAction cas ["replace _ with A _"]
445470
]
446471

447472
signatureTests :: TestTree
@@ -522,6 +547,23 @@ unusedTermTests = testGroup "unused term code actions" [
522547
all (Just CodeActionRefactorInline ==) kinds @? "All CodeActionRefactorInline"
523548
]
524549

550+
expectFailIfGhc9 :: String -> TestTree -> TestTree
551+
expectFailIfGhc9 reason =
552+
case ghcVersion of
553+
GHC90 -> expectFailBecause reason
554+
_ -> id
555+
556+
disableWingman :: Session ()
557+
disableWingman =
558+
sendConfigurationChanged $ def
559+
{ plugins = M.fromList [ ("tactics", def { plcGlobalOn = False }) ]
560+
}
561+
562+
563+
sendConfigurationChanged :: Config -> Session ()
564+
sendConfigurationChanged config =
565+
sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))
566+
525567
noLiteralCaps :: C.ClientCapabilities
526568
noLiteralCaps = def { C._textDocument = Just textDocumentCaps }
527569
where

0 commit comments

Comments
 (0)