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