1
1
{-# LANGUAGE CPP #-}
2
2
3
3
#include "ghc-api-version.h"
4
+ #if MIN_GHC_API_VERSION (8,8,4)
5
+ {-# LANGUAGE GADTs#-}
6
+ #endif
4
7
-- Mostly taken from "haskell-ide-engine"
5
8
module Development.IDE.Plugin.Completions.Logic (
6
9
CachedCompletions
@@ -11,7 +14,7 @@ module Development.IDE.Plugin.Completions.Logic (
11
14
) where
12
15
13
16
import Control.Applicative
14
- import Data.Char (isUpper )
17
+ import Data.Char (isAlphaNum , isUpper )
15
18
import Data.Generics
16
19
import Data.List.Extra as List hiding (stripPrefix )
17
20
import qualified Data.Map as Map
@@ -144,21 +147,44 @@ occNameToComKind ty oc
144
147
showModName :: ModuleName -> T. Text
145
148
showModName = T. pack . moduleNameString
146
149
150
+ -- mkCompl :: IdeOptions -> CompItem -> CompletionItem
151
+ -- mkCompl IdeOptions{..} CI{compKind,insertText, importedFrom,typeText,label,docs} =
152
+ -- CompletionItem label kind (List []) ((colon <>) <$> typeText)
153
+ -- (Just $ CompletionDocMarkup $ MarkupContent MkMarkdown $ T.intercalate sectionSeparator docs')
154
+ -- Nothing Nothing Nothing Nothing (Just insertText) (Just Snippet)
155
+ -- Nothing Nothing Nothing Nothing Nothing
156
+
147
157
mkCompl :: IdeOptions -> CompItem -> CompletionItem
148
- mkCompl IdeOptions {.. } CI {compKind,insertText, importedFrom,typeText,label,docs} =
149
- CompletionItem label kind (List [] ) ((colon <> ) <$> typeText)
150
- (Just $ CompletionDocMarkup $ MarkupContent MkMarkdown $ T. intercalate sectionSeparator docs')
151
- Nothing Nothing Nothing Nothing (Just insertText) (Just Snippet )
152
- Nothing Nothing Nothing Nothing Nothing
158
+ mkCompl IdeOptions {.. } CI {compKind,insertText, importedFrom,typeText,label,docs, additionalTextEdits} =
159
+ CompletionItem {_label = label,
160
+ _kind = kind,
161
+ _tags = List [] ,
162
+ _detail = (colon <> ) <$> typeText,
163
+ _documentation = documentation,
164
+ _deprecated = Nothing ,
165
+ _preselect = Nothing ,
166
+ _sortText = Nothing ,
167
+ _filterText = Nothing ,
168
+ _insertText = Just insertText,
169
+ _insertTextFormat = Just Snippet ,
170
+ _textEdit = Nothing ,
171
+ _additionalTextEdits = List <$> additionalTextEdits,
172
+ _commitCharacters = Nothing ,
173
+ _command = Nothing ,
174
+ _xdata = Nothing }
175
+
153
176
where kind = Just compKind
154
177
docs' = imported : spanDocToMarkdown docs
155
178
imported = case importedFrom of
156
179
Left pos -> " *Defined at '" <> ppr pos <> " '*\n '"
157
180
Right mod -> " *Defined in '" <> mod <> " '*\n "
158
181
colon = if optNewColonConvention then " : " else " :: "
182
+ documentation = Just $ CompletionDocMarkup $
183
+ MarkupContent MkMarkdown $
184
+ T. intercalate sectionSeparator docs'
159
185
160
- mkNameCompItem :: Name -> ModuleName -> Maybe Type -> Maybe Backtick -> SpanDoc -> CompItem
161
- mkNameCompItem origName origMod thingType isInfix docs = CI {.. }
186
+ mkNameCompItem :: Name -> ModuleName -> Maybe Type -> Maybe Backtick -> SpanDoc -> Maybe ( LImportDecl GhcPs ) -> CompItem
187
+ mkNameCompItem origName origMod thingType isInfix docs ! imp = CI {.. }
162
188
where
163
189
compKind = occNameToComKind typeText $ occName origName
164
190
importedFrom = Right $ showModName origMod
@@ -174,7 +200,7 @@ mkNameCompItem origName origMod thingType isInfix docs = CI{..}
174
200
typeText
175
201
| Just t <- thingType = Just . stripForall $ T. pack (showGhc t)
176
202
| otherwise = Nothing
177
-
203
+ additionalTextEdits = imp >>= extendImportList (showGhc origName)
178
204
179
205
stripForall :: T. Text -> T. Text
180
206
stripForall t
@@ -236,11 +262,37 @@ mkPragmaCompl label insertText =
236
262
Nothing Nothing Nothing Nothing Nothing (Just insertText) (Just Snippet )
237
263
Nothing Nothing Nothing Nothing Nothing
238
264
265
+ extendImportList :: String -> LImportDecl GhcPs -> Maybe [TextEdit ]
266
+ extendImportList name lDecl = let
267
+ f (Just range) ImportDecl {ideclHiding} = case ideclHiding of
268
+ Just (False , x)
269
+ | Set. notMember name (Set. fromList [show y| y <- unLoc x])
270
+ -> let
271
+ start_pos = _end range
272
+ new_start_pos = start_pos {_character = _character start_pos - 1 }
273
+ -- use to same start_pos to handle situation where we do not have latest edits due to caching of Rules
274
+ new_range = Range new_start_pos new_start_pos
275
+ -- we cannot wrap mapM_ inside (mapM_) but we need to wrap (<$)
276
+ alpha = all isAlphaNum $ filter (\ c -> c /= ' _' ) name
277
+ result = if alpha then name ++ " , "
278
+ else " (" ++ name ++ " ), "
279
+ in Just [TextEdit new_range (T. pack result)]
280
+ | otherwise -> Nothing
281
+ _ -> Nothing -- hiding import list and no list
282
+ f _ _ = Nothing
283
+ src_span = srcSpanToRange . getLoc $ lDecl
284
+ in f src_span . unLoc $ lDecl
285
+
286
+
239
287
cacheDataProducer :: HscEnv -> Module -> GlobalRdrEnv -> [LImportDecl GhcPs ] -> [ParsedModule ] -> IO CachedCompletions
240
288
cacheDataProducer packageState curMod rdrEnv limports deps = do
241
289
let dflags = hsc_dflags packageState
242
290
curModName = moduleName curMod
243
291
292
+ importMap = Map. fromList [
293
+ (getLoc imp, imp)
294
+ | imp <- limports ]
295
+
244
296
iDeclToModName :: ImportDecl name -> ModuleName
245
297
iDeclToModName = unLoc . ideclName
246
298
@@ -266,10 +318,11 @@ cacheDataProducer packageState curMod rdrEnv limports deps = do
266
318
267
319
getComplsForOne :: GlobalRdrElt -> IO ([CompItem ],QualCompls )
268
320
getComplsForOne (GRE n _ True _) =
269
- (, mempty ) <$> toCompItem curMod curModName n
321
+ (, mempty ) <$> toCompItem curMod curModName n Nothing
270
322
getComplsForOne (GRE n _ False prov) =
271
323
flip foldMapM (map is_decl prov) $ \ spec -> do
272
- compItem <- toCompItem curMod (is_mod spec) n
324
+ let originalImportDecl = Map. lookup (is_dloc spec) importMap
325
+ compItem <- toCompItem curMod (is_mod spec) n originalImportDecl
273
326
let unqual
274
327
| is_qual spec = []
275
328
| otherwise = compItem
@@ -280,8 +333,8 @@ cacheDataProducer packageState curMod rdrEnv limports deps = do
280
333
origMod = showModName (is_mod spec)
281
334
return (unqual,QualCompls qual)
282
335
283
- toCompItem :: Module -> ModuleName -> Name -> IO [CompItem ]
284
- toCompItem m mn n = do
336
+ toCompItem :: Module -> ModuleName -> Name -> Maybe ( LImportDecl GhcPs ) -> IO [CompItem ]
337
+ toCompItem m mn n imp' = do
285
338
docs <- getDocumentationTryGhc packageState curMod deps n
286
339
ty <- catchSrcErrors (hsc_dflags packageState) " completion" $ do
287
340
name' <- lookupName packageState m n
@@ -294,10 +347,10 @@ cacheDataProducer packageState curMod rdrEnv limports deps = do
294
347
let recordCompls = case either (const Nothing ) id record_ty of
295
348
Just (ctxStr, flds) -> case flds of
296
349
[] -> []
297
- _ -> [mkRecordSnippetCompItem ctxStr flds (ppr mn) docs]
350
+ _ -> [mkRecordSnippetCompItem ctxStr flds (ppr mn) docs imp' ]
298
351
Nothing -> []
299
352
300
- return $ [mkNameCompItem n mn (either (const Nothing ) id ty) Nothing docs] ++
353
+ return $ [mkNameCompItem n mn (either (const Nothing ) id ty) Nothing docs imp' ] ++
301
354
recordCompls
302
355
303
356
(unquals,quals) <- getCompls rdrElts
@@ -360,19 +413,17 @@ localCompletionsForParsedModule pm@ParsedModule{pm_parsed_source = L _ HsModule{
360
413
]
361
414
362
415
mkComp n ctyp ty =
363
- CI ctyp pn (Right thisModName) ty pn Nothing doc (ctyp `elem` [CiStruct , CiClass ])
416
+ CI ctyp pn (Right thisModName) ty pn Nothing doc (ctyp `elem` [CiStruct , CiClass ]) Nothing
364
417
where
365
418
pn = ppr n
366
419
doc = SpanDocText (getDocumentation [pm] n) (SpanDocUris Nothing Nothing )
367
420
368
421
thisModName = ppr hsmodName
369
422
370
- -- recordCompls = localRecordSnippetProducer pm thisModName
371
-
372
423
findRecordCompl :: ParsedModule -> T. Text -> TyClDecl GhcPs -> [CompItem ]
373
424
findRecordCompl pmod mn DataDecl {tcdLName, tcdDataDefn} = result
374
425
where
375
- result = [mkRecordSnippetCompItem (T. pack . showGhc . unLoc $ con_name) field_labels mn doc
426
+ result = [mkRecordSnippetCompItem (T. pack . showGhc . unLoc $ con_name) field_labels mn doc Nothing
376
427
| ConDeclH98 {.. } <- unLoc <$> dd_cons tcdDataDefn
377
428
, Just con_details <- [getFlds con_args]
378
429
, let field_names = mapMaybe extract con_details
@@ -468,7 +519,7 @@ getCompletions ideOpts CC { allModNamesAsNS, unqualCompls, qualCompls, importabl
468
519
endLoc = upperRange oldPos
469
520
localCompls = map (uncurry localBindsToCompItem) $ getFuzzyScope localBindings startLoc endLoc
470
521
localBindsToCompItem :: Name -> Maybe Type -> CompItem
471
- localBindsToCompItem name typ = CI ctyp pn thisModName ty pn Nothing emptySpanDoc (not $ isValOcc occ)
522
+ localBindsToCompItem name typ = CI ctyp pn thisModName ty pn Nothing emptySpanDoc (not $ isValOcc occ) Nothing
472
523
where
473
524
occ = nameOccName name
474
525
ctyp = occNameToComKind Nothing occ
@@ -665,8 +716,8 @@ safeTyThingForRecord (AConLike dc) =
665
716
Just (ctxStr, field_names)
666
717
safeTyThingForRecord _ = Nothing
667
718
668
- mkRecordSnippetCompItem :: T. Text -> [T. Text ] -> T. Text -> SpanDoc -> CompItem
669
- mkRecordSnippetCompItem ctxStr compl mn docs = r
719
+ mkRecordSnippetCompItem :: T. Text -> [T. Text ] -> T. Text -> SpanDoc -> Maybe ( LImportDecl GhcPs ) -> CompItem
720
+ mkRecordSnippetCompItem ctxStr compl mn docs imp = r
670
721
where
671
722
r = CI {
672
723
compKind = CiSnippet
@@ -677,6 +728,7 @@ mkRecordSnippetCompItem ctxStr compl mn docs = r
677
728
, isInfix = Nothing
678
729
, docs = docs
679
730
, isTypeCompl = False
731
+ , additionalTextEdits = imp >>= extendImportList (T. unpack ctxStr)
680
732
}
681
733
682
734
placeholder_pairs = zip compl ([1 .. ]:: [Int ])
0 commit comments