@@ -107,10 +107,16 @@ instance Show CollectRecordSelectorsResult where
107
107
108
108
type instance RuleResult CollectRecordSelectors = CollectRecordSelectorsResult
109
109
110
-
111
- data RecordSelectorExpr = RecordSelectorExpr { location :: Range ,
112
- selectorExpr :: LHsExpr (GhcPass 'Renamed),
113
- recordExpr :: LHsExpr (GhcPass 'Renamed) }
110
+ -- | Where we store our collected record selectors
111
+ data RecordSelectorExpr =
112
+ RecordSelectorExpr { -- | the location of the matched record selector, and record
113
+ location :: Range ,
114
+ -- | the record selector, this is found in front of recordExpr, but
115
+ -- | get's placed after it when converted into record dot syntax
116
+ selectorExpr :: LHsExpr (GhcPass 'Renamed),
117
+ -- | the record. Whereas it can be many different structures, the only
118
+ -- | requirement is that it evaluates to a record in the end
119
+ recordExpr :: LHsExpr (GhcPass 'Renamed) }
114
120
115
121
instance Pretty RecordSelectorExpr where
116
122
pretty (RecordSelectorExpr l rs se) = pretty (printOutputable rs) <> " :" <+> pretty (printOutputable se)
@@ -133,10 +139,14 @@ codeActionProvider ideState pId (CodeActionParams _ _ caDocId caRange _) = plugi
133
139
pragmaEdit = if OverloadedRecordDot `elem` exts
134
140
then Nothing
135
141
else Just $ insertNewPragma pragma OverloadedRecordDot
136
- edits crs = maybeToList ( convertRecordSelectors crs) <> maybeToList pragmaEdit
142
+ edits crs = convertRecordSelectors crs : maybeToList pragmaEdit
137
143
changes crs = Just $ HashMap. singleton (fromNormalizedUri (normalizedFilePathToUri nfp)) (List (edits crs))
138
144
mkCodeAction crs = InR CodeAction
139
- { _title = mkCodeActionTitle exts crs
145
+ { -- we pass the record selector to the title function, so that it con be used to generate the file
146
+ -- the advantage of that is that the user can easily distinguish between the the different code actions
147
+ -- with nested record selectors, the disadvantage is we need to print out the name of the record selector
148
+ -- which may decrease performance
149
+ _title = mkCodeActionTitle exts crs
140
150
, _kind = Just CodeActionRefactorRewrite
141
151
, _diagnostics = Nothing
142
152
, _isPreferred = Nothing
@@ -162,42 +172,45 @@ collectRecSelsRule recorder = define (cmapWithPrio LogShake recorder) $ \Collect
162
172
use TypeCheck nfp >>= \ case
163
173
Nothing -> pure ([] , Nothing )
164
174
Just tmr -> do
165
- let exts = getEnabledExtensions tmr
166
- recSels = getRecordSelectors tmr
175
+ let exts = getEnabledExtensions tmr -- We need the extensions to check whether we need to add OverloadedRecordDot
176
+ recSels = getRecordSelectors tmr -- And we need the record selectors for obvious reasons
167
177
logWith recorder Debug (LogCollectedRecordSelectors recSels)
168
178
let crsMap :: RangeMap RecordSelectorExpr
169
- crsMap = RangeMap. fromList location recSels
179
+ crsMap = RangeMap. fromList location recSels -- We need the rangeMap to be able to filter by range later
170
180
pure ([] , CRSR <$> Just crsMap <*> Just exts)
171
181
where
172
182
getEnabledExtensions :: TcModuleResult -> [Extension ]
173
183
getEnabledExtensions = getExtensions . tmrParsed
184
+ getRecordSelectors :: TcModuleResult -> [RecordSelectorExpr ]
185
+ getRecordSelectors (tmrRenamed -> (hs_valds -> valBinds,_,_,_)) =
186
+ collectRecordSelectors valBinds
174
187
175
- getRecordSelectors :: TcModuleResult -> [RecordSelectorExpr ]
176
- getRecordSelectors (tmrRenamed -> (hs_valds -> valBinds,_,_,_)) =
177
- collectRecordSelectors valBinds
178
-
179
- convertRecordSelectors :: RecordSelectorExpr -> Maybe TextEdit
180
- convertRecordSelectors (RecordSelectorExpr l se re) = TextEdit l <$> convertRecSel se re
188
+ convertRecordSelectors :: RecordSelectorExpr -> TextEdit
189
+ convertRecordSelectors (RecordSelectorExpr l se re) = TextEdit l $ convertRecSel se re
181
190
182
- convertRecSel :: Outputable (LHsExpr (GhcPass 'Renamed)) => LHsExpr (GhcPass 'Renamed) -> LHsExpr (GhcPass 'Renamed) -> Maybe Text
183
- convertRecSel se re =
184
- Just $ printOutputable (parenthesizeHsExpr appPrec re) <> " ." <> printOutputable se
191
+ -- | Converts a record selector expression into record dot syntax,
192
+ -- | currently we are using printOutputable to do it. We are also letting GHC
193
+ -- | decide when to parenthesizing the record expression
194
+ convertRecSel :: Outputable (LHsExpr (GhcPass 'Renamed)) => LHsExpr (GhcPass 'Renamed) -> LHsExpr (GhcPass 'Renamed) -> Text
195
+ convertRecSel se re = printOutputable (parenthesizeHsExpr appPrec re) <> " ." <> printOutputable se
185
196
186
197
-- It's important that we use everthingBut here, because if we used everything we would
187
- -- get duplicates for every case that occures inside a HsExpanded expression.
198
+ -- get duplicates for every case that occurs inside a HsExpanded expression.
188
199
collectRecordSelectors :: GenericQ [RecordSelectorExpr ]
189
200
collectRecordSelectors = everythingBut (<>) (([] , False ) `mkQ` getRecSels)
190
201
202
+ -- | We want to return a list here, because on the occasion that we encounter a HsExpanded expression,
203
+ -- | we want to return all the results from recursing on one branch, which could be multiple matches
191
204
getRecSels :: LHsExpr (GhcPass 'Renamed) -> ([RecordSelectorExpr ], Bool )
192
- -- When we stumble upon an occurance of HsExpanded, we only want to follow one branch
193
- -- we do this here, by explicitly returning occurances from traversing the original branch,
205
+ -- When we stumble upon an occurrence of HsExpanded, we only want to follow one branch
206
+ -- we do this here, by explicitly returning occurrences from traversing the original branch,
194
207
-- and returning True, which keeps syb from implicitly continuing to traverse.
195
208
getRecSels (unLoc -> XExpr (HsExpanded a _)) = (collectRecordSelectors a, True )
196
209
#if __GLASGOW_HASKELL__ >= 903
197
- -- applied record selection: "field record" or "field (record)" or "field field.record "
210
+ -- applied record selection: "selector record" or "selector (record)" or "selector selector2.record2 "
198
211
getRecSels e@ (unLoc -> HsApp _ se@ (unLoc -> HsRecSel _ _) re) =
199
212
( [ RecordSelectorExpr (realSrcSpanToRange realSpan') se re | RealSrcSpan realSpan' _ <- [ getLoc e ]], False )
200
- -- Record selection where the field is being applied with the "$" operator: "field $ record"
213
+ -- Record selection where the field is being applied with the "$" operator: "selector $ record"
201
214
getRecSels e@ (unLoc -> OpApp _ se@ (unLoc -> HsRecSel _ _) (unLoc -> HsVar _ (unLoc -> d)) re)
202
215
| d == dollarName = ( [ RecordSelectorExpr (realSrcSpanToRange realSpan') se re | RealSrcSpan realSpan' _ <- [ getLoc e ]], False )
203
216
#else
0 commit comments