@@ -559,10 +559,54 @@ getCompletions
559
559
-> CompletionsConfig
560
560
-> ModuleNameEnv (HashSet. HashSet IdentInfo )
561
561
-> Uri
562
- -> IO [Scored CompletionItem ]
563
- getCompletions plugins ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls, qualCompls, importableModules}
564
- maybe_parsed maybe_ast_res (localBindings, bmapping) prefixInfo caps config moduleExportsMap uri = do
565
- let PosPrefixInfo { fullLine, prefixScope, prefixText } = prefixInfo
562
+ -> [Scored CompletionItem ]
563
+ getCompletions
564
+ plugins
565
+ ideOpts
566
+ CC {allModNamesAsNS, anyQualCompls, unqualCompls, qualCompls, importableModules}
567
+ maybe_parsed
568
+ maybe_ast_res
569
+ (localBindings, bmapping)
570
+ prefixInfo@ (PosPrefixInfo { fullLine, prefixScope, prefixText })
571
+ caps
572
+ config
573
+ moduleExportsMap
574
+ uri
575
+ -- ------------------------------------------------------------------------
576
+ -- IMPORT MODULENAME (NAM|)
577
+ | Just (ImportListContext moduleName) <- maybeContext
578
+ = moduleImportListCompletions moduleName
579
+
580
+ | Just (ImportHidingContext moduleName) <- maybeContext
581
+ = moduleImportListCompletions moduleName
582
+
583
+ -- ------------------------------------------------------------------------
584
+ -- IMPORT MODULENAM|
585
+ | Just (ImportContext _moduleName) <- maybeContext
586
+ = filtImportCompls
587
+
588
+ -- ------------------------------------------------------------------------
589
+ -- {-# LA| #-}
590
+ -- we leave this condition here to avoid duplications and return empty list
591
+ -- since HLS implements these completions (#haskell-language-server/pull/662)
592
+ | " {-# " `T.isPrefixOf` fullLine
593
+ = []
594
+
595
+ -- ------------------------------------------------------------------------
596
+ | otherwise =
597
+ -- assumes that nubOrdBy is stable
598
+ let uniqueFiltCompls = nubOrdBy (uniqueCompl `on` snd . Fuzzy. original) filtCompls
599
+ compls = (fmap . fmap . fmap ) (mkCompl pId ideOpts uri) uniqueFiltCompls
600
+ pId = lookupCommandProvider plugins (CommandId extendImportCommandId)
601
+ in
602
+ (fmap . fmap ) snd $
603
+ sortBy (compare `on` lexicographicOrdering) $
604
+ mergeListsBy (flip compare `on` score)
605
+ [ (fmap . fmap ) (notQual,) filtModNameCompls
606
+ , (fmap . fmap ) (notQual,) filtKeywordCompls
607
+ , (fmap . fmap . fmap ) (toggleSnippets caps config) compls
608
+ ]
609
+ where
566
610
enteredQual = if T. null prefixScope then " " else prefixScope <> " ."
567
611
fullPrefix = enteredQual <> prefixText
568
612
@@ -585,11 +629,9 @@ getCompletions plugins ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls,
585
629
$ Fuzzy. simpleFilter chunkSize maxC fullPrefix
586
630
$ (if T. null enteredQual then id else mapMaybe (T. stripPrefix enteredQual))
587
631
allModNamesAsNS
588
-
589
- filtCompls = Fuzzy. filter chunkSize maxC prefixText ctxCompls (label . snd )
590
- where
591
-
592
- mcc = case maybe_parsed of
632
+ -- If we have a parsed module, use it to determine which completion to show.
633
+ maybeContext :: Maybe Context
634
+ maybeContext = case maybe_parsed of
593
635
Nothing -> Nothing
594
636
Just (pm, pmapping) ->
595
637
let PositionMapping pDelta = pmapping
@@ -598,7 +640,9 @@ getCompletions plugins ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls,
598
640
hpos = upperRange position'
599
641
in getCContext lpos pm <|> getCContext hpos pm
600
642
601
-
643
+ filtCompls :: [Scored (Bool , CompItem )]
644
+ filtCompls = Fuzzy. filter chunkSize maxC prefixText ctxCompls (label . snd )
645
+ where
602
646
-- We need the hieast to be "fresh". We can't get types from "stale" hie files, so hasfield won't work,
603
647
-- since it gets the record fields from the types.
604
648
-- Perhaps this could be fixed with a refactor to GHC's IfaceTyCon, to have it also contain record fields.
@@ -636,7 +680,7 @@ getCompletions plugins ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls,
636
680
})
637
681
638
682
-- completions specific to the current context
639
- ctxCompls' = case mcc of
683
+ ctxCompls' = case maybeContext of
640
684
Nothing -> compls
641
685
Just TypeContext -> filter ( isTypeCompl . snd ) compls
642
686
Just ValueContext -> filter (not . isTypeCompl . snd ) compls
@@ -677,54 +721,36 @@ getCompletions plugins ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls,
677
721
, enteredQual `T.isPrefixOf` original label
678
722
]
679
723
724
+ moduleImportListCompletions :: String -> [Scored CompletionItem ]
725
+ moduleImportListCompletions moduleNameS =
726
+ let moduleName = T. pack moduleNameS
727
+ funcs = lookupWithDefaultUFM moduleExportsMap HashSet. empty $ mkModuleName moduleNameS
728
+ funs = map (show . name) $ HashSet. toList funcs
729
+ in filterModuleExports moduleName $ map T. pack funs
730
+
731
+ filtImportCompls :: [Scored CompletionItem ]
680
732
filtImportCompls = filtListWith (mkImportCompl enteredQual) importableModules
733
+
734
+ filterModuleExports :: T. Text -> [T. Text ] -> [Scored CompletionItem ]
681
735
filterModuleExports moduleName = filtListWith $ mkModuleFunctionImport moduleName
736
+
737
+ filtKeywordCompls :: [Scored CompletionItem ]
682
738
filtKeywordCompls
683
739
| T. null prefixScope = filtListWith mkExtCompl (optKeywords ideOpts)
684
740
| otherwise = []
685
741
686
- if
687
- -- TODO: handle multiline imports
688
- | " import " `T.isPrefixOf` fullLine
689
- && (List. length (words (T. unpack fullLine)) >= 2 )
690
- && " (" `isInfixOf` T. unpack fullLine
691
- -> do
692
- let moduleName = words (T. unpack fullLine) !! 1
693
- funcs = lookupWithDefaultUFM moduleExportsMap HashSet. empty $ mkModuleName moduleName
694
- funs = map (renderOcc . name) $ HashSet. toList funcs
695
- return $ filterModuleExports (T. pack moduleName) funs
696
- | " import " `T.isPrefixOf` fullLine
697
- -> return filtImportCompls
698
- -- we leave this condition here to avoid duplications and return empty list
699
- -- since HLS implements these completions (#haskell-language-server/pull/662)
700
- | " {-# " `T.isPrefixOf` fullLine
701
- -> return []
702
- | otherwise -> do
703
- -- assumes that nubOrdBy is stable
704
- let uniqueFiltCompls = nubOrdBy (uniqueCompl `on` snd . Fuzzy. original) filtCompls
705
- let compls = (fmap . fmap . fmap ) (mkCompl pId ideOpts uri) uniqueFiltCompls
706
- pId = lookupCommandProvider plugins (CommandId extendImportCommandId)
707
- return $
708
- (fmap . fmap ) snd $
709
- sortBy (compare `on` lexicographicOrdering) $
710
- mergeListsBy (flip compare `on` score)
711
- [ (fmap . fmap ) (notQual,) filtModNameCompls
712
- , (fmap . fmap ) (notQual,) filtKeywordCompls
713
- , (fmap . fmap . fmap ) (toggleSnippets caps config) compls
714
- ]
715
- where
716
- -- We use this ordering to alphabetically sort suggestions while respecting
717
- -- all the previously applied ordering sources. These are:
718
- -- 1. Qualified suggestions go first
719
- -- 2. Fuzzy score ranks next
720
- -- 3. In-scope completions rank next
721
- -- 4. label alphabetical ordering next
722
- -- 4. detail alphabetical ordering (proxy for module)
723
- lexicographicOrdering Fuzzy. Scored {score, original} =
724
- case original of
725
- (isQual, CompletionItem {_label,_detail}) -> do
726
- let isLocal = maybe False (" :" `T.isPrefixOf` ) _detail
727
- (Down isQual, Down score, Down isLocal, _label, _detail)
742
+ -- We use this ordering to alphabetically sort suggestions while respecting
743
+ -- all the previously applied ordering sources. These are:
744
+ -- 1. Qualified suggestions go first
745
+ -- 2. Fuzzy score ranks next
746
+ -- 3. In-scope completions rank next
747
+ -- 4. label alphabetical ordering next
748
+ -- 4. detail alphabetical ordering (proxy for module)
749
+ lexicographicOrdering Fuzzy. Scored {score, original} =
750
+ case original of
751
+ (isQual, CompletionItem {_label,_detail}) -> do
752
+ let isLocal = maybe False (" :" `T.isPrefixOf` ) _detail
753
+ (Down isQual, Down score, Down isLocal, _label, _detail)
728
754
729
755
730
756
0 commit comments