@@ -41,27 +41,35 @@ hsimportDescriptor plId = PluginDescriptor
41
41
, pluginFormattingProvider = Nothing
42
42
}
43
43
44
+ -- | Type of the symbol to import.
45
+ -- Important to offer the correct import list, or hiding code action.
44
46
data SymbolType
45
- = Symbol
46
- | Constructor
47
- | Type
47
+ = Symbol -- ^ Symbol is a simple function
48
+ | Constructor -- ^ Symbol is a constructor
49
+ | Type -- ^ Symbol is a type
48
50
deriving (Show , Eq , Generics.Generic , ToJSON , FromJSON )
49
51
50
52
51
53
-- | What of the symbol should be taken.
54
+ -- Import a simple symbol, or a value constructor.
52
55
data SymbolKind
53
- = Only SymbolName -- ^ only the symbol should be taken
54
- | AllOf DatatypeName -- ^ all constructors or methods of the symbol should be taken: Symbol(.. )
55
- | OneOf DatatypeName SymbolName -- ^ some constructors or methods of the symbol should be taken: Symbol(X, Y )
56
+ = Only SymbolName -- ^ Only the symbol should be taken
57
+ | OneOf DatatypeName SymbolName -- ^ Some constructors or methods of the symbol should be taken: Symbol(X )
58
+ | AllOf DatatypeName -- ^ All constructors or methods of the symbol should be taken: Symbol(.. )
56
59
deriving (Show , Eq , Generics.Generic , ToJSON , FromJSON )
57
60
58
- -- | The imported or from the import hidden symbol.
61
+ -- | Disambiguates between an import action and an hiding action.
62
+ -- Can be used to determine suggestion tpye from ghc-mod,
63
+ -- e.g. whether ghc-mod suggests to hide an identifier or to import an identifier.
64
+ -- Also important later, to know how the symbol shall be imported.
59
65
data SymbolImport a
60
66
= Import a -- ^ the symbol to import
61
67
| Hiding a -- ^ the symbol to hide from the import
62
68
deriving (Show , Eq , Generics.Generic , ToJSON , FromJSON )
63
69
64
70
71
+ -- | Utility to retrieve the contents of the 'SymbolImport'.
72
+ -- May never fail.
65
73
extractSymbolImport :: SymbolImport a -> a
66
74
extractSymbolImport (Hiding s) = s
67
75
extractSymbolImport (Import s) = s
@@ -70,19 +78,26 @@ type ModuleName = T.Text
70
78
type SymbolName = T. Text
71
79
type DatatypeName = T. Text
72
80
81
+ -- | How to import a module.
82
+ -- Can be used to express to import a whole module or only specific symbols
83
+ -- from a module.
84
+ -- Is used to either hide symbols from an import or use an import-list to
85
+ -- import only a specific symbol.
73
86
data ImportStyle
74
87
= Simple -- ^ Import the whole module
75
88
| Complex (SymbolImport SymbolKind ) -- ^ Complex operation, import module hiding symbols or import only selected symbols.
76
89
deriving (Show , Eq , Generics.Generic , ToJSON , FromJSON )
77
90
91
+ -- | Contains information about the diagnostic, the symbol ghc-mod
92
+ -- complained about and what the kind of the symbol is and whether
93
+ -- to import or hide the symbol as suggested by ghc-mod.
78
94
data ImportDiagnostic = ImportDiagnostic
79
95
{ diagnostic :: J. Diagnostic
80
96
, term :: SymbolName
81
97
, termType :: SymbolImport SymbolType
82
98
}
83
99
deriving (Show , Eq , Generics.Generic , ToJSON , FromJSON )
84
100
85
-
86
101
-- | Import Parameters for Modules.
87
102
-- Can be used to import every symbol from a module,
88
103
-- or to import only a specific function from a module.
@@ -189,23 +204,31 @@ importModule uri impStyle modName =
189
204
$ IdeResultOk (J. WorkspaceEdit newChanges newDocChanges)
190
205
else return $ IdeResultOk (J. WorkspaceEdit mChanges mDocChanges)
191
206
207
+ -- | Convert the import style arguments into HsImport arguments.
208
+ -- Takes an input and an output file as well as a module name.
192
209
importStyleToHsImportArgs
193
210
:: FilePath -> FilePath -> ModuleName -> ImportStyle -> HsImport. HsImportArgs
194
211
importStyleToHsImportArgs input output modName style =
195
- let defaultArgs =
212
+ let defaultArgs = -- Default args, must be set every time.
196
213
HsImport. defaultArgs { HsImport. moduleName = T. unpack modName
197
214
, HsImport. inputSrcFile = input
198
215
, HsImport. outputSrcFile = output
199
216
}
217
+
218
+ kindToArgs :: SymbolKind -> HsImport. HsImportArgs
200
219
kindToArgs kind = case kind of
220
+ -- Only import a single symbol e.g. Data.Text (isPrefixOf)
201
221
Only sym -> defaultArgs { HsImport. symbolName = T. unpack sym }
222
+ -- Import a constructor e.g. Data.Mabye (Maybe(Just))
202
223
OneOf dt sym -> defaultArgs { HsImport. symbolName = T. unpack dt
203
224
, HsImport. with = [T. unpack sym]
204
225
}
226
+ -- Import all constructors e.g. Data.Maybe (Maybe(..))
205
227
AllOf dt -> defaultArgs { HsImport. symbolName = T. unpack dt
206
228
, HsImport. all = True
207
229
}
208
230
in case style of
231
+ -- If the import style is simple, import thw whole module
209
232
Simple -> defaultArgs
210
233
Complex s -> case s of
211
234
Hiding kind -> kindToArgs kind {- TODO: wait for hsimport version bump -}
@@ -265,8 +288,8 @@ codeActionProvider plId docId _ context = do
265
288
(x : _) -> " is:exact " <> x
266
289
applySearchStyle (Relax relax) termName = relax termName
267
290
268
- -- | Turn a search term with function name into Import Actions.
269
- -- Function name may be of only the exact phrase to import.
291
+ -- | Turn a search term with function name into an Import Actions.
292
+ -- The function name may be of only the exact phrase to import.
270
293
-- The resulting CodeAction's contain a general import of a module or
271
294
-- uses an Import-List.
272
295
--
@@ -282,20 +305,35 @@ codeActionProvider plId docId _ context = do
282
305
termToActions style modules impDiagnostic =
283
306
concat <$> mapM (importModuleAction style impDiagnostic) modules
284
307
308
+ -- | Creates various import actions for a module and the diagnostic.
309
+ -- Possible import actions depend on the type of the symbol to import.
310
+ -- It may be a 'Constructor', so the import actions need to be different
311
+ -- to a simple function symbol.
312
+ -- Thus, it may return zero, one or multiple import actions for a module.
313
+ -- List of import actions does contain no duplicates.
285
314
importModuleAction
286
315
:: SearchStyle -> ImportDiagnostic -> ModuleName -> IdeM [J. CodeAction ]
287
316
importModuleAction searchStyle impDiagnostic moduleName =
288
317
catMaybes <$> sequenceA codeActions
289
318
where
290
319
importListActions :: [IdeM (Maybe J. CodeAction )]
291
320
importListActions = case searchStyle of
321
+ -- If the search has been relaxed by a custom function,
322
+ -- we cant know how much the search query has been altered
323
+ -- and how close the result terms are to the initial diagnostic.
324
+ -- Thus, we cant offer more specific imports.
292
325
Relax _ -> []
293
326
_ -> catMaybes
294
327
$ case extractSymbolImport $ termType impDiagnostic of
328
+ -- If the term to import is a simple symbol, such as a function,
329
+ -- import only this function
295
330
Symbol
296
331
-> [ mkImportAction moduleName impDiagnostic . Just . Only
297
332
<$> symName (term impDiagnostic)
298
333
]
334
+ -- Constructors can be imported in two ways, either all
335
+ -- constructors of a type or only a subset.
336
+ -- We can only import a single constructor at a time though.
299
337
Constructor
300
338
-> [ mkImportAction moduleName impDiagnostic . Just . AllOf
301
339
<$> datatypeName (term impDiagnostic)
@@ -304,22 +342,43 @@ codeActionProvider plId docId _ context = do
304
342
<$> datatypeName (term impDiagnostic)
305
343
<*> symName (term impDiagnostic)
306
344
]
345
+ -- If we are looking for a type, import it as just a symbol
307
346
Type
308
347
-> [ mkImportAction moduleName impDiagnostic . Just . Only
309
348
<$> symName (term impDiagnostic)]
310
349
350
+ -- | All code actions that may be available
351
+ -- Currently, omits all
311
352
codeActions :: [IdeM (Maybe J. CodeAction )]
312
353
codeActions = case termType impDiagnostic of
313
- Hiding _ -> []
354
+ Hiding _ -> [] {- If we are hiding an import, we can not import
355
+ a module hiding everything from it. -}
314
356
Import _ -> [mkImportAction moduleName impDiagnostic Nothing ]
357
+ -- ^ Simple import, import the whole module
315
358
++ importListActions
316
359
360
+ -- | Retrieve the function signature of a term such as
361
+ -- >>> signatureOf "take :: Int -> [a] -> [a]"
362
+ -- Just " Int -> [a] -> [a]"
317
363
signatureOf :: T. Text -> Maybe T. Text
318
364
signatureOf sig = do
319
365
let parts = T. splitOn " ::" sig
320
366
typeSig <- S. tailMay parts
321
367
S. headMay typeSig
322
368
369
+ -- | Retrieve the datatype name of a Constructor.
370
+ --
371
+ -- >>> datatypeName "Null :: Data.Aeson.Internal.Types.Value"
372
+ -- Just "Value"
373
+ --
374
+ -- >>> datatypeName "take :: Int -> [a] -> [a]" -- Not a constructor
375
+ -- Just "[a]"
376
+ --
377
+ -- >>> datatypeName "Just :: a -> Maybe a"
378
+ -- Just "Maybe"
379
+ --
380
+ -- Thus, the result of this function only makes sense,
381
+ -- if the symbol kind of the diagnostic term is of type 'Constructor'
323
382
datatypeName :: T. Text -> Maybe T. Text
324
383
datatypeName sig = do
325
384
sig_ <- signatureOf sig
@@ -330,6 +389,10 @@ codeActionProvider plId docId _ context = do
330
389
let qualifiedDtNameParts = T. splitOn " ." qualifiedDtName
331
390
S. lastMay qualifiedDtNameParts
332
391
392
+ -- | Name of a symbol. May contain a function signature.
393
+ --
394
+ -- >>> symName "take :: Int -> [a] -> [a]"
395
+ -- Just "take"
333
396
symName :: T. Text -> Maybe SymbolName
334
397
symName = S. headMay . T. words
335
398
0 commit comments