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