@@ -25,8 +25,7 @@ import Control.Monad.IO.Class (MonadIO (liftIO))
25
25
import Control.Monad.Trans.Class (MonadTrans (lift ))
26
26
import Control.Monad.Trans.Except (ExceptT (.. ), runExceptT ,
27
27
throwE )
28
- import Data.Aeson (ToJSON (toJSON ), Value (Null ))
29
- import Data.Aeson.Types (FromJSON )
28
+ import Data.Aeson (genericParseJSON , FromJSON (.. ), ToJSON (.. ), Value (Null ))
30
29
import Data.Bifunctor (Bifunctor (first ), second )
31
30
import Data.Coerce
32
31
import Data.Either (partitionEithers )
@@ -35,7 +34,7 @@ import qualified Data.HashMap.Strict as HM
35
34
import qualified Data.HashSet as Set
36
35
import Data.IORef.Extra (atomicModifyIORef'_ , newIORef ,
37
36
readIORef )
38
- import Data.List.Extra (nubOrdOn )
37
+ import Data.List.Extra (find , nubOrdOn )
39
38
import Data.String (IsString (fromString ))
40
39
import qualified Data.Text as T
41
40
import qualified Data.Text.IO as T
@@ -86,6 +85,9 @@ import Retrie.SYB (listify)
86
85
import Retrie.Util (Verbosity (Loud ))
87
86
import StringBuffer (stringToStringBuffer )
88
87
import System.Directory (makeAbsolute )
88
+ import Control.Monad.Trans.Maybe
89
+ import Development.IDE.Core.PositionMapping
90
+ import qualified Data.Aeson as Aeson
89
91
90
92
descriptor :: PluginId -> PluginDescriptor
91
93
descriptor plId =
@@ -104,59 +106,110 @@ retrieCommand =
104
106
-- | Parameters for the runRetrie PluginCommand.
105
107
data RunRetrieParams = RunRetrieParams
106
108
{ description :: T. Text ,
107
- -- | rewrites for Retrie
108
- rewrites :: [Either ImportSpec RewriteSpec ],
109
- -- | Originating file
110
- originatingFile :: String ,
109
+ rewrites :: [RewriteSpec ],
110
+ originatingFile :: NormalizedUriJSON ,
111
111
restrictToOriginatingFile :: Bool
112
112
}
113
113
deriving (Eq , Show , Generic , FromJSON , ToJSON )
114
114
115
+ newtype NormalizedUriJSON = NormalizedUriJSON NormalizedUri
116
+ deriving (Eq , Show )
117
+
118
+ instance FromJSON NormalizedUriJSON where
119
+ parseJSON = fmap NormalizedUriJSON . genericParseJSON Aeson. defaultOptions
120
+
121
+ instance ToJSON NormalizedUriJSON where
122
+ toJSON (NormalizedUriJSON x) = Aeson. genericToJSON Aeson. defaultOptions x
123
+
115
124
runRetrieCmd ::
116
125
LspFuncs a ->
117
126
IdeState ->
118
127
RunRetrieParams ->
119
128
IO (Either ResponseError Value , Maybe (ServerMethod , ApplyWorkspaceEditParams ))
120
- runRetrieCmd lsp state RunRetrieParams { .. } =
129
+ runRetrieCmd lsp state RunRetrieParams {originatingFile = NormalizedUriJSON nuri, .. } =
121
130
withIndefiniteProgress lsp description Cancellable $ do
122
- session <-
123
- runAction " Retrie.GhcSessionDeps" state $
124
- use_ GhcSessionDeps $
125
- toNormalizedFilePath originatingFile
126
- (errors, edits) <-
127
- callRetrie
128
- state
129
- (hscEnv session)
130
- rewrites
131
- (toNormalizedFilePath originatingFile)
132
- restrictToOriginatingFile
133
- unless (null errors) $
134
- sendFunc lsp $
135
- NotShowMessage $
136
- NotificationMessage " 2.0" WindowShowMessage $
137
- ShowMessageParams MtWarning $
138
- T. unlines $
139
- " ## Found errors during rewrite:" :
140
- [" -" <> T. pack (show e) | e <- errors]
131
+ res <- runMaybeT $ do
132
+ nfp <- MaybeT $ return $ uriToNormalizedFilePath nuri
133
+ (session, _) <- MaybeT $
134
+ runAction " Retrie.GhcSessionDeps" state $
135
+ useWithStale GhcSessionDeps $
136
+ nfp
137
+ (ms, binds, _, _, _) <- MaybeT $ runAction " Retrie.getBinds" state $ getBinds nfp
138
+ let importRewrites = concatMap (extractImports ms binds) rewrites
139
+ (errors, edits) <- lift $
140
+ callRetrie
141
+ state
142
+ (hscEnv session)
143
+ (map Right rewrites <> map Left importRewrites)
144
+ nfp
145
+ restrictToOriginatingFile
146
+ unless (null errors) $
147
+ lift $ sendFunc lsp $
148
+ NotShowMessage $
149
+ NotificationMessage " 2.0" WindowShowMessage $
150
+ ShowMessageParams MtWarning $
151
+ T. unlines $
152
+ " ## Found errors during rewrite:" :
153
+ [" -" <> T. pack (show e) | e <- errors]
154
+ return (WorkspaceApplyEdit , ApplyWorkspaceEditParams edits)
141
155
return
142
- (Right Null , Just (WorkspaceApplyEdit , ApplyWorkspaceEditParams edits))
156
+ (Right Null , res)
157
+
158
+ extractImports :: ModSummary -> [HsBindLR GhcRn GhcRn ] -> RewriteSpec -> [ImportSpec ]
159
+ extractImports ModSummary {ms_mod} topLevelBinds (Unfold thing)
160
+ | Just FunBind {fun_matches}
161
+ <- find (\ case FunBind {fun_id = L _ n} -> prettyPrint n == thing ; _ -> False ) topLevelBinds
162
+ , names <- listify p fun_matches
163
+ =
164
+ [ AddImport {.. }
165
+ | name <- names,
166
+ Just ideclNameString <-
167
+ [moduleNameString . GHC. moduleName <$> nameModule_maybe name],
168
+ let ideclSource = False ,
169
+ let r = nameRdrName name,
170
+ let ideclQualifiedBool = isQual r,
171
+ let ideclAsString = moduleNameString . fst <$> isQual_maybe r,
172
+ let ideclThing = Just (IEVar $ occNameString $ rdrNameOcc r)
173
+ ]
174
+ where
175
+ p name = nameModule_maybe name /= Just ms_mod
176
+ -- TODO handle imports for all rewrites
177
+ extractImports _ _ _ = []
143
178
144
179
-------------------------------------------------------------------------------
145
180
146
181
provider :: CodeActionProvider
147
182
provider _a state plId (TextDocumentIdentifier uri) range ca = response $ do
148
183
let (J. CodeActionContext _diags _monly) = ca
149
- fp <- handleMaybe " uri" $ uriToFilePath' uri
150
- let nfp = toNormalizedFilePath' fp
184
+ nuri = toNormalizedUri uri
185
+ nuriJson = NormalizedUriJSON nuri
186
+ nfp <- handleMaybe " uri" $ uriToNormalizedFilePath nuri
151
187
152
- tm <-
153
- handleMaybeM " no typechecked module" $
154
- useRule " retrie.typecheckModule" state TypeCheck nfp
188
+ (ModSummary {ms_mod}, topLevelBinds, posMapping, hs_ruleds, hs_tyclds)
189
+ <- handleMaybeM " typecheck" $ runAction " retrie" state $ getBinds nfp
155
190
156
- ModSummary {ms_mod} <-
157
- handleMaybeM " no mod summary" $
158
- useRule " retrie.typecheckModule" state GetModSummary nfp
191
+ pos <- handleMaybe " pos" $ _start <$> fromCurrentRange posMapping range
192
+ let rewrites =
193
+ concatMap (suggestBindRewrites nuriJson pos ms_mod) topLevelBinds
194
+ ++ concatMap (suggestRuleRewrites nuriJson pos ms_mod) hs_ruleds
195
+ ++ [ r
196
+ | TyClGroup {group_tyclds} <- hs_tyclds,
197
+ L l g <- group_tyclds,
198
+ r <- suggestTypeRewrites nuriJson ms_mod g,
199
+ pos `isInsideSrcSpan` l
200
+
201
+ ]
202
+
203
+ commands <- lift $
204
+ forM rewrites $ \ (title, kind, params) -> do
205
+ c <- mkLspCommand plId (coerce retrieCommandName) title (Just [toJSON params])
206
+ return $ CodeAction title (Just kind) Nothing Nothing (Just c)
207
+
208
+ return $ J. List [CACodeAction c | c <- commands]
159
209
210
+ getBinds :: NormalizedFilePath -> Action (Maybe (ModSummary , [HsBindLR GhcRn GhcRn ], PositionMapping , [LRuleDecls GhcRn ], [TyClGroup GhcRn ]))
211
+ getBinds nfp = runMaybeT $ do
212
+ (tm, posMapping) <- MaybeT $ useWithStale TypeCheck nfp
160
213
-- we use the typechecked source instead of the parsed source
161
214
-- to be able to extract module names from the Ids,
162
215
-- so that we can include adding the required imports in the retrie command
@@ -173,60 +226,29 @@ provider _a state plId (TextDocumentIdentifier uri) range ca = response $ do
173
226
_
174
227
) = rn
175
228
176
- pos = _start range
177
229
topLevelBinds =
178
230
[ decl
179
231
| (_, bagBinds) <- binds,
180
232
L _ decl <- GHC. bagToList bagBinds
181
233
]
182
-
183
- rewrites =
184
- concatMap (suggestBindRewrites fp pos ms_mod) topLevelBinds
185
- ++ concatMap (suggestRuleRewrites fp pos ms_mod) hs_ruleds
186
- ++ [ r
187
- | TyClGroup {group_tyclds} <- hs_tyclds,
188
- L _ g <- group_tyclds,
189
- r <- suggestTypeRewrites fp pos ms_mod g
190
- ]
191
-
192
- commands <- lift $
193
- forM rewrites $ \ (title, kind, params) -> do
194
- c <- mkLspCommand plId (coerce retrieCommandName) title (Just [toJSON params])
195
- return $ CodeAction title (Just kind) Nothing Nothing (Just c)
196
-
197
- return $ J. List [CACodeAction c | c <- commands]
234
+ return (tmrModSummary tm, topLevelBinds, posMapping, hs_ruleds, hs_tyclds)
198
235
199
236
suggestBindRewrites ::
200
- String ->
237
+ NormalizedUriJSON ->
201
238
Position ->
202
239
GHC. Module ->
203
240
HsBindLR GhcRn GhcRn ->
204
241
[(T. Text , CodeActionKind , RunRetrieParams )]
205
- suggestBindRewrites originatingFile pos ms_mod (FunBind {fun_id = L l' rdrName, fun_matches })
242
+ suggestBindRewrites originatingFile pos ms_mod (FunBind {fun_id = L l' rdrName})
206
243
| pos `isInsideSrcSpan` l' =
207
244
let pprName = prettyPrint rdrName
208
245
pprNameText = T. pack pprName
209
- names = listify p fun_matches
210
- p name = nameModule_maybe name /= Just ms_mod
211
- imports =
212
- [ AddImport {.. }
213
- | name <- names,
214
- Just ideclNameString <-
215
- [moduleNameString . GHC. moduleName <$> nameModule_maybe name],
216
- let ideclSource = False ,
217
- let r = nameRdrName name,
218
- let ideclQualifiedBool = isQual r,
219
- let ideclAsString = moduleNameString . fst <$> isQual_maybe r,
220
- let ideclThing = Just (IEVar $ occNameString $ rdrNameOcc r)
221
- ]
222
246
unfoldRewrite restrictToOriginatingFile =
223
- let rewrites =
224
- [Right $ Unfold (qualify ms_mod pprName)]
225
- ++ map Left imports
247
+ let rewrites = [Unfold (qualify ms_mod pprName)]
226
248
description = " Unfold " <> pprNameText <> describeRestriction restrictToOriginatingFile
227
249
in (description, CodeActionRefactorInline , RunRetrieParams {.. })
228
250
foldRewrite restrictToOriginatingFile =
229
- let rewrites = [Right $ Fold (qualify ms_mod pprName)]
251
+ let rewrites = [Fold (qualify ms_mod pprName)]
230
252
description = " Fold " <> pprNameText <> describeRestriction restrictToOriginatingFile
231
253
in (description, CodeActionRefactorExtract , RunRetrieParams {.. })
232
254
in [unfoldRewrite False , unfoldRewrite True , foldRewrite False , foldRewrite True ]
@@ -237,32 +259,28 @@ describeRestriction :: IsString p => Bool -> p
237
259
describeRestriction restrictToOriginatingFile =
238
260
if restrictToOriginatingFile then " in current file" else " "
239
261
240
- -- TODO add imports to the rewrite
241
262
suggestTypeRewrites ::
242
263
(Outputable (IdP pass )) =>
243
- String ->
244
- Position ->
264
+ NormalizedUriJSON ->
245
265
GHC. Module ->
246
266
TyClDecl pass ->
247
267
[(T. Text , CodeActionKind , RunRetrieParams )]
248
- suggestTypeRewrites originatingFile pos ms_mod (SynDecl {tcdLName = L l rdrName})
249
- | pos `isInsideSrcSpan` l =
268
+ suggestTypeRewrites originatingFile ms_mod (SynDecl {tcdLName = L _ rdrName}) =
250
269
let pprName = prettyPrint rdrName
251
270
pprNameText = T. pack pprName
252
271
unfoldRewrite restrictToOriginatingFile =
253
- let rewrites = [Right $ TypeForward (qualify ms_mod pprName)]
272
+ let rewrites = [TypeForward (qualify ms_mod pprName)]
254
273
description = " Unfold " <> pprNameText <> describeRestriction restrictToOriginatingFile
255
274
in (description, CodeActionRefactorInline , RunRetrieParams {.. })
256
275
foldRewrite restrictToOriginatingFile =
257
- let rewrites = [Right $ TypeBackward (qualify ms_mod pprName)]
276
+ let rewrites = [TypeBackward (qualify ms_mod pprName)]
258
277
description = " Fold " <> pprNameText <> describeRestriction restrictToOriginatingFile
259
278
in (description, CodeActionRefactorExtract , RunRetrieParams {.. })
260
279
in [unfoldRewrite False , unfoldRewrite True , foldRewrite False , foldRewrite True ]
261
- suggestTypeRewrites _ _ _ _ = []
280
+ suggestTypeRewrites _ _ _ = []
262
281
263
- -- TODO add imports to the rewrite
264
282
suggestRuleRewrites ::
265
- FilePath ->
283
+ NormalizedUriJSON ->
266
284
Position ->
267
285
GHC. Module ->
268
286
LRuleDecls pass ->
@@ -285,8 +303,7 @@ suggestRuleRewrites originatingFile pos ms_mod (L _ (HsRules {rds_rules})) =
285
303
]
286
304
where
287
305
forwardRewrite ruleName restrictToOriginatingFile =
288
- let rewrites =
289
- [Right $ RuleForward (qualify ms_mod ruleName)]
306
+ let rewrites = [RuleForward (qualify ms_mod ruleName)]
290
307
description = " Apply rule " <> T. pack ruleName <> " forward" <>
291
308
describeRestriction restrictToOriginatingFile
292
309
@@ -295,8 +312,7 @@ suggestRuleRewrites originatingFile pos ms_mod (L _ (HsRules {rds_rules})) =
295
312
RunRetrieParams {.. }
296
313
)
297
314
backwardsRewrite ruleName restrictToOriginatingFile =
298
- let rewrites =
299
- [Right $ RuleBackward (qualify ms_mod ruleName)]
315
+ let rewrites = [RuleBackward (qualify ms_mod ruleName)]
300
316
description = " Apply rule " <> T. pack ruleName <> " backwards"
301
317
in ( description,
302
318
CodeActionRefactor ,
0 commit comments