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,23 @@ 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 (_TcRnMessage ,
32
+ msgEnvelopeErrorL ,
33
+ stripTcRnMessageContext )
32
34
import Development.IDE.Plugin.Completions (ghcideCompletionsPluginPriority )
33
35
import Development.IDE.Plugin.Completions.Logic (getCompletionPrefixFromRope )
34
36
import Development.IDE.Plugin.Completions.Types (PosPrefixInfo (.. ))
35
37
import qualified Development.IDE.Spans.Pragmas as Pragmas
38
+ import GHC.Types.Error (GhcHint (SuggestExtension ),
39
+ LanguageExtensionHint (.. ),
40
+ diagnosticHints )
36
41
import Ide.Plugin.Error
37
42
import Ide.Types
38
43
import qualified Language.LSP.Protocol.Lens as L
@@ -74,19 +79,27 @@ suggestPragmaProvider = mkCodeActionProvider suggest
74
79
suggestDisableWarningProvider :: PluginMethodHandler IdeState 'LSP.Method_TextDocumentCodeAction
75
80
suggestDisableWarningProvider = mkCodeActionProvider $ const suggestDisableWarning
76
81
77
- mkCodeActionProvider :: (Maybe DynFlags -> Diagnostic -> [PragmaEdit ]) -> PluginMethodHandler IdeState 'LSP.Method_TextDocumentCodeAction
82
+ mkCodeActionProvider :: (Maybe DynFlags -> FileDiagnostic -> [PragmaEdit ]) -> PluginMethodHandler IdeState 'LSP.Method_TextDocumentCodeAction
78
83
mkCodeActionProvider mkSuggest state _plId
79
- (LSP. CodeActionParams _ _ LSP. TextDocumentIdentifier { _uri = uri } _ (LSP. CodeActionContext diags _monly _)) = do
84
+ (LSP. CodeActionParams _ _ docId@ LSP. TextDocumentIdentifier { _uri = uri } caRange _) = do
85
+ verTxtDocId <- liftIO $ runAction " classplugin.codeAction.getVersionedTextDoc" state $ getVersionedTextDoc docId
80
86
normalizedFilePath <- getNormalizedFilePathE uri
81
87
-- ghc session to get some dynflags even if module isn't parsed
82
88
(hscEnv -> hsc_dflags -> sessionDynFlags, _) <-
83
89
runActionE " Pragmas.GhcSession" state $ useWithStaleE GhcSession normalizedFilePath
84
90
fileContents <- liftIO $ runAction " Pragmas.GetFileContents" state $ getFileContents normalizedFilePath
85
91
parsedModule <- liftIO $ runAction " Pragmas.GetParsedModule" state $ getParsedModule normalizedFilePath
92
+
93
+
86
94
let parsedModuleDynFlags = ms_hspp_opts . pm_mod_summary <$> parsedModule
87
95
nextPragmaInfo = Pragmas. getNextPragmaInfo sessionDynFlags fileContents
88
- pedits = nubOrdOn snd $ concatMap (mkSuggest parsedModuleDynFlags) diags
89
- pure $ LSP. InL $ pragmaEditToAction uri nextPragmaInfo <$> pedits
96
+ activeDiagnosticsInRange (shakeExtras state) normalizedFilePath caRange >>= \ case
97
+ Nothing -> pure $ LSP. InL []
98
+ Just fileDiags -> do
99
+ let actions = concatMap (mkSuggest parsedModuleDynFlags) fileDiags
100
+ pure $ LSP. InL $ pragmaEditToAction uri nextPragmaInfo <$> actions
101
+ -- pedits = nubOrdOn snd $ concatMap (mkSuggest parsedModuleDynFlags) diags
102
+ -- pure $ LSP.InL $ pragmaEditToAction uri nextPragmaInfo <$> pedits
90
103
91
104
92
105
@@ -115,22 +128,23 @@ pragmaEditToAction uri Pragmas.NextPragmaInfo{ nextPragmaLine, lineSplitTextEdit
115
128
Nothing
116
129
Nothing
117
130
118
- suggest :: Maybe DynFlags -> Diagnostic -> [PragmaEdit ]
131
+ suggest :: Maybe DynFlags -> FileDiagnostic -> [PragmaEdit ]
119
132
suggest dflags diag =
120
133
suggestAddPragma dflags diag
121
134
122
135
-- ---------------------------------------------------------------------
123
136
124
- suggestDisableWarning :: Diagnostic -> [PragmaEdit ]
125
- suggestDisableWarning diagnostic
126
- | Just (Just (JSON. Array attachedReasons)) <- diagnostic ^? attachedReason
127
- =
128
- [ (" Disable \" " <> w <> " \" warnings" , OptGHC w)
129
- | JSON. String attachedReason <- Foldable. toList attachedReasons
130
- , Just w <- [T. stripPrefix " -W" attachedReason]
131
- , w `notElem` warningBlacklist
132
- ]
133
- | otherwise = []
137
+ suggestDisableWarning :: FileDiagnostic -> [PragmaEdit ]
138
+ suggestDisableWarning _ = []
139
+ -- suggestDisableWarning diagnostic
140
+ -- | Just (Just (JSON.Array attachedReasons)) <- diagnostic ^? attachedReason
141
+ -- =
142
+ -- [ ("Disable \"" <> w <> "\" warnings", OptGHC w)
143
+ -- | JSON.String attachedReason <- Foldable.toList attachedReasons
144
+ -- , Just w <- [T.stripPrefix "-W" attachedReason]
145
+ -- , w `notElem` warningBlacklist
146
+ -- ]
147
+ -- | otherwise = []
134
148
135
149
warningBlacklist :: [T. Text ]
136
150
warningBlacklist =
@@ -144,12 +158,11 @@ warningBlacklist =
144
158
145
159
-- | Offer to add a missing Language Pragma to the top of a file.
146
160
-- 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
161
+ suggestAddPragma :: Maybe DynFlags -> FileDiagnostic -> [PragmaEdit ]
162
+ suggestAddPragma mDynflags fd= filterPragma fd
150
163
where
151
- genPragma target =
152
- [(" Add \" " <> r <> " \" " , LangExt r) | r <- findPragma target , r `notElem` disabled]
164
+ filterPragma fd =
165
+ [(" Add \" " <> r <> " \" " , LangExt r) | r <- map ( T. pack . show ) $ suggestsExtension fd , r `notElem` disabled]
153
166
disabled
154
167
| Just dynFlags <- mDynflags =
155
168
-- GHC does not export 'OnOff', so we have to view it as string
@@ -158,7 +171,20 @@ suggestAddPragma mDynflags Diagnostic {_message, _source}
158
171
-- When the module failed to parse, we don't have access to its
159
172
-- dynFlags. In that case, simply don't disable any pragmas.
160
173
[]
161
- suggestAddPragma _ _ = []
174
+
175
+ suggestsExtension :: FileDiagnostic -> [Extension ]
176
+ suggestsExtension message = case stripTcRnMessageContext <$> (message ^? fdStructuredMessageL . _SomeStructuredMessage . msgEnvelopeErrorL . _TcRnMessage) of
177
+ Just s -> concat $ mapMaybe (\ case
178
+ SuggestExtension s -> Just $ ghcHintSuggestsExtension s
179
+ _ -> Nothing ) (diagnosticHints s)
180
+ _ -> []
181
+
182
+ ghcHintSuggestsExtension :: LanguageExtensionHint -> [Extension ]
183
+ ghcHintSuggestsExtension (SuggestSingleExtension _ ext) = [ext]
184
+ ghcHintSuggestsExtension (SuggestAnyExtension _ (ext: _)) = [ext] -- ghc suggests any of those, we pick first
185
+ ghcHintSuggestsExtension (SuggestAnyExtension _ [] ) = []
186
+ ghcHintSuggestsExtension (SuggestExtensions _ ext) = ext
187
+ ghcHintSuggestsExtension (SuggestExtensionInOrderTo _ ext) = [ext]
162
188
163
189
-- | Find all Pragmas are an infix of the search term.
164
190
findPragma :: T. Text -> [T. Text ]
0 commit comments