@@ -559,10 +559,54 @@ getCompletions
559559 -> CompletionsConfig
560560 -> ModuleNameEnv (HashSet. HashSet IdentInfo )
561561 -> 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
566610 enteredQual = if T. null prefixScope then " " else prefixScope <> " ."
567611 fullPrefix = enteredQual <> prefixText
568612
@@ -585,11 +629,9 @@ getCompletions plugins ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls,
585629 $ Fuzzy. simpleFilter chunkSize maxC fullPrefix
586630 $ (if T. null enteredQual then id else mapMaybe (T. stripPrefix enteredQual))
587631 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
593635 Nothing -> Nothing
594636 Just (pm, pmapping) ->
595637 let PositionMapping pDelta = pmapping
@@ -598,7 +640,9 @@ getCompletions plugins ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls,
598640 hpos = upperRange position'
599641 in getCContext lpos pm <|> getCContext hpos pm
600642
601-
643+ filtCompls :: [Scored (Bool , CompItem )]
644+ filtCompls = Fuzzy. filter chunkSize maxC prefixText ctxCompls (label . snd )
645+ where
602646 -- We need the hieast to be "fresh". We can't get types from "stale" hie files, so hasfield won't work,
603647 -- since it gets the record fields from the types.
604648 -- 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,
636680 })
637681
638682 -- completions specific to the current context
639- ctxCompls' = case mcc of
683+ ctxCompls' = case maybeContext of
640684 Nothing -> compls
641685 Just TypeContext -> filter ( isTypeCompl . snd ) compls
642686 Just ValueContext -> filter (not . isTypeCompl . snd ) compls
@@ -677,54 +721,36 @@ getCompletions plugins ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls,
677721 , enteredQual `T.isPrefixOf` original label
678722 ]
679723
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 ]
680732 filtImportCompls = filtListWith (mkImportCompl enteredQual) importableModules
733+
734+ filterModuleExports :: T. Text -> [T. Text ] -> [Scored CompletionItem ]
681735 filterModuleExports moduleName = filtListWith $ mkModuleFunctionImport moduleName
736+
737+ filtKeywordCompls :: [Scored CompletionItem ]
682738 filtKeywordCompls
683739 | T. null prefixScope = filtListWith mkExtCompl (optKeywords ideOpts)
684740 | otherwise = []
685741
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)
728754
729755
730756
0 commit comments