1
1
{-# LANGUAGE CPP #-}
2
2
{-# LANGUAGE DataKinds #-}
3
3
{-# LANGUAGE DuplicateRecordFields #-}
4
+ {-# LANGUAGE LambdaCase #-}
4
5
{-# LANGUAGE MultiWayIf #-}
5
6
{-# LANGUAGE OverloadedStrings #-}
6
7
{-# LANGUAGE ViewPatterns #-}
@@ -20,19 +21,21 @@ import Control.Monad.IO.Class (MonadIO (liftIO))
20
21
import qualified Data.Aeson as JSON
21
22
import Data.Char (isAlphaNum )
22
23
import qualified Data.Foldable as Foldable
23
- import Data.List.Extra (nubOrdOn )
24
24
import qualified Data.Map as M
25
25
import Data.Maybe (mapMaybe )
26
26
import qualified Data.Text as T
27
27
import Development.IDE hiding (line )
28
- import Development.IDE.Core.Compile (sourceParser ,
29
- sourceTypecheck )
28
+ import Development.IDE.Core.FileStore (getVersionedTextDoc )
30
29
import Development.IDE.Core.PluginUtils
31
30
import Development.IDE.GHC.Compat
31
+ import Development.IDE.GHC.Compat.Error (msgEnvelopeErrorL )
32
32
import Development.IDE.Plugin.Completions (ghcideCompletionsPluginPriority )
33
33
import Development.IDE.Plugin.Completions.Logic (getCompletionPrefixFromRope )
34
34
import Development.IDE.Plugin.Completions.Types (PosPrefixInfo (.. ))
35
35
import qualified Development.IDE.Spans.Pragmas as Pragmas
36
+ import GHC.Types.Error (GhcHint (SuggestExtension ),
37
+ LanguageExtensionHint (.. ),
38
+ diagnosticHints )
36
39
import Ide.Plugin.Error
37
40
import Ide.Types
38
41
import qualified Language.LSP.Protocol.Lens as L
@@ -74,19 +77,27 @@ suggestPragmaProvider = mkCodeActionProvider suggest
74
77
suggestDisableWarningProvider :: PluginMethodHandler IdeState 'LSP.Method_TextDocumentCodeAction
75
78
suggestDisableWarningProvider = mkCodeActionProvider $ const suggestDisableWarning
76
79
77
- mkCodeActionProvider :: (Maybe DynFlags -> Diagnostic -> [PragmaEdit ]) -> PluginMethodHandler IdeState 'LSP.Method_TextDocumentCodeAction
80
+ mkCodeActionProvider :: (Maybe DynFlags -> FileDiagnostic -> [PragmaEdit ]) -> PluginMethodHandler IdeState 'LSP.Method_TextDocumentCodeAction
78
81
mkCodeActionProvider mkSuggest state _plId
79
- (LSP. CodeActionParams _ _ LSP. TextDocumentIdentifier { _uri = uri } _ (LSP. CodeActionContext diags _monly _)) = do
80
- normalizedFilePath <- getNormalizedFilePathE uri
82
+ (LSP. CodeActionParams _ _ docId@ LSP. TextDocumentIdentifier { _uri = uri } caRange _) = do
83
+ verTxtDocId <- liftIO $ runAction " classplugin.codeAction.getVersionedTextDoc" state $ getVersionedTextDoc docId
84
+ normalizedFilePath <- getNormalizedFilePathE (verTxtDocId ^. L. uri)
81
85
-- ghc session to get some dynflags even if module isn't parsed
82
86
(hscEnv -> hsc_dflags -> sessionDynFlags, _) <-
83
87
runActionE " Pragmas.GhcSession" state $ useWithStaleE GhcSession normalizedFilePath
84
88
fileContents <- liftIO $ runAction " Pragmas.GetFileContents" state $ getFileContents normalizedFilePath
85
89
parsedModule <- liftIO $ runAction " Pragmas.GetParsedModule" state $ getParsedModule normalizedFilePath
90
+
91
+
86
92
let parsedModuleDynFlags = ms_hspp_opts . pm_mod_summary <$> parsedModule
87
93
nextPragmaInfo = Pragmas. getNextPragmaInfo sessionDynFlags fileContents
88
- pedits = nubOrdOn snd $ concatMap (mkSuggest parsedModuleDynFlags) diags
89
- pure $ LSP. InL $ pragmaEditToAction uri nextPragmaInfo <$> pedits
94
+ activeDiagnosticsInRange (shakeExtras state) normalizedFilePath caRange >>= \ case
95
+ Nothing -> pure $ LSP. InL []
96
+ Just fileDiags -> do
97
+ let actions = concatMap (mkSuggest parsedModuleDynFlags) fileDiags
98
+ pure $ LSP. InL $ pragmaEditToAction uri nextPragmaInfo <$> actions
99
+ -- pedits = nubOrdOn snd $ concatMap (mkSuggest parsedModuleDynFlags) diags
100
+ -- pure $ LSP.InL $ pragmaEditToAction uri nextPragmaInfo <$> pedits
90
101
91
102
92
103
@@ -115,15 +126,15 @@ pragmaEditToAction uri Pragmas.NextPragmaInfo{ nextPragmaLine, lineSplitTextEdit
115
126
Nothing
116
127
Nothing
117
128
118
- suggest :: Maybe DynFlags -> Diagnostic -> [PragmaEdit ]
129
+ suggest :: Maybe DynFlags -> FileDiagnostic -> [PragmaEdit ]
119
130
suggest dflags diag =
120
131
suggestAddPragma dflags diag
121
132
122
133
-- ---------------------------------------------------------------------
123
134
124
- suggestDisableWarning :: Diagnostic -> [PragmaEdit ]
135
+ suggestDisableWarning :: FileDiagnostic -> [PragmaEdit ]
125
136
suggestDisableWarning diagnostic
126
- | Just (Just (JSON. Array attachedReasons)) <- diagnostic ^? attachedReason
137
+ | Just (Just (JSON. Array attachedReasons)) <- diagnostic ^? fdLspDiagnosticL . attachedReason
127
138
=
128
139
[ (" Disable \" " <> w <> " \" warnings" , OptGHC w)
129
140
| JSON. String attachedReason <- Foldable. toList attachedReasons
@@ -143,13 +154,12 @@ warningBlacklist =
143
154
-- ---------------------------------------------------------------------
144
155
145
156
-- | Offer to add a missing Language Pragma to the top of a file.
146
- -- Pragmas are defined by a curated list of known pragmas, see 'possiblePragmas'.
147
- suggestAddPragma :: Maybe DynFlags -> Diagnostic -> [PragmaEdit ]
148
- suggestAddPragma mDynflags Diagnostic {_message, _source}
149
- | _source == Just sourceTypecheck || _source == Just sourceParser = genPragma _message
157
+ -- Pragmas are defined by a cuNewrated list of known pragmas, see 'possiblePragmas'.
158
+ suggestAddPragma :: Maybe DynFlags -> FileDiagnostic -> [PragmaEdit ]
159
+ suggestAddPragma mDynflags fd= filterPragma fd
150
160
where
151
- genPragma target =
152
- [(" Add \" " <> r <> " \" " , LangExt r) | r <- findPragma target , r `notElem` disabled]
161
+ filterPragma fd =
162
+ [(" Add \" " <> r <> " \" " , LangExt r) | r <- map ( T. pack . show ) $ suggestsExtension fd , r `notElem` disabled] -- NOCOMMIT
153
163
disabled
154
164
| Just dynFlags <- mDynflags =
155
165
-- GHC does not export 'OnOff', so we have to view it as string
@@ -158,25 +168,22 @@ suggestAddPragma mDynflags Diagnostic {_message, _source}
158
168
-- When the module failed to parse, we don't have access to its
159
169
-- dynFlags. In that case, simply don't disable any pragmas.
160
170
[]
161
- suggestAddPragma _ _ = []
162
171
163
- -- | Find all Pragmas are an infix of the search term.
164
- findPragma :: T. Text -> [T. Text ]
165
- findPragma str = concatMap check possiblePragmas
166
- where
167
- check p = [p | T. isInfixOf p str]
168
-
169
- -- We exclude the Strict extension as it causes many false positives, see
170
- -- the discussion at https://github.com/haskell/ghcide/pull/638
171
- --
172
- -- We don't include the No- variants, as GHC never suggests disabling an
173
- -- extension in an error message.
174
- possiblePragmas :: [T. Text ]
175
- possiblePragmas =
176
- [ name
177
- | FlagSpec {flagSpecName = T. pack -> name} <- xFlags
178
- , " Strict" /= name
179
- ]
172
+ suggestsExtension :: FileDiagnostic -> [Extension ]
173
+ suggestsExtension message = case message ^? fdStructuredMessageL . _SomeStructuredMessage . msgEnvelopeErrorL of
174
+ Just s -> concat $ mapMaybe (\ case
175
+ SuggestExtension s -> Just $ ghcHintSuggestsExtension s
176
+ _ -> Nothing ) (diagnosticHints s)
177
+ _ -> []
178
+
179
+ ghcHintSuggestsExtension :: LanguageExtensionHint -> [Extension ]
180
+ ghcHintSuggestsExtension (SuggestSingleExtension _ ext) = [ext]
181
+ ghcHintSuggestsExtension (SuggestAnyExtension _ (ext: _)) = [ext] -- ghc suggests any of those, we pick first
182
+ ghcHintSuggestsExtension (SuggestAnyExtension _ [] ) = []
183
+ ghcHintSuggestsExtension (SuggestExtensions _ ext) = ext
184
+ ghcHintSuggestsExtension (SuggestExtensionInOrderTo _ ext) = [ext]
185
+
186
+
180
187
181
188
-- | All language pragmas, including the No- variants
182
189
allPragmas :: [T. Text ]
0 commit comments