Skip to content

Limit completions to top 40 #1218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 18, 2021
12 changes: 10 additions & 2 deletions ghcide/src/Development/IDE/Plugin/Completions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Development.IDE.Plugin.Completions
(
plugin
, getCompletionsLSP
, maxCompletions
) where

import Language.Haskell.LSP.Messages
Expand Down Expand Up @@ -116,6 +117,12 @@ instance Hashable NonLocalCompletions
instance NFData NonLocalCompletions
instance Binary NonLocalCompletions

-- | 40 may seem conservative but note that most editors limit how many completions
-- are displayed in the screen, and most users rarely scroll.
-- For instance, VSCode only shows 12 completions in its popup, and Emacs has a similar limit.
maxCompletions :: Int
maxCompletions = 40

-- | Generate code actions.
getCompletionsLSP
:: LSP.LspFuncs Config
Expand Down Expand Up @@ -145,11 +152,12 @@ getCompletionsLSP lsp ide
(Just pfix', _) -> do
let clientCaps = clientCapabilities $ shakeExtras ide
snippets <- WithSnippets . completionSnippetsOn <$> getClientConfig lsp
Completions . List <$> getCompletions ideOpts cci' parsedMod bindMap pfix' clientCaps snippets
allCompletions <- getCompletions ideOpts cci' parsedMod bindMap pfix' clientCaps snippets
let (topCompletions, rest) = splitAt maxCompletions allCompletions
pure $ CompletionList (CompletionListType (null rest) (List topCompletions))
_ -> return (Completions $ List [])
_ -> return (Completions $ List [])
_ -> return (Completions $ List [])

setHandlersCompletion :: PartialHandlers Config
setHandlersCompletion = PartialHandlers $ \WithMessage{..} x -> return x{
LSP.completionHandler = withResponse RspCompletion getCompletionsLSP
Expand Down
8 changes: 5 additions & 3 deletions ghcide/src/Development/IDE/Plugin/Completions/Logic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -565,9 +565,11 @@ getCompletions ideOpts CC { allModNamesAsNS, unqualCompls, qualCompls, importabl
= filtPragmaCompls (pragmaSuffix fullLine)
| otherwise
= let uniqueFiltCompls = nubOrdOn insertText filtCompls
in filtModNameCompls ++ map (toggleSnippets caps withSnippets
. mkCompl ideOpts . stripAutoGenerated) uniqueFiltCompls
++ filtKeywordCompls
in filtModNameCompls
++ filtKeywordCompls
++ map ( toggleSnippets caps withSnippets
. mkCompl ideOpts . stripAutoGenerated
) uniqueFiltCompls
return result


Expand Down
13 changes: 12 additions & 1 deletion ghcide/test/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import Development.IDE.Plugin.Test (WaitForIdeRuleResult(..), TestRequest(BlockS
import Control.Monad.Extra (whenJust)
import qualified Language.Haskell.LSP.Types.Lens as L
import Control.Lens ((^.))
import Development.IDE.Plugin.Completions (maxCompletions)

main :: IO ()
main = do
Expand Down Expand Up @@ -3213,7 +3214,17 @@ otherCompletionTests = [
-- This should be sufficient to detect that we are in a
-- type context and only show the completion to the type.
(Position 3 11)
[("Integer", CiStruct, "Integer ", True, True, Nothing)]
[("Integer", CiStruct, "Integer ", True, True, Nothing)],

testSessionWait "maxCompletions" $ do
doc <- createDoc "A.hs" "haskell" $ T.unlines
[ "{-# OPTIONS_GHC -Wunused-binds #-}",
"module A () where",
"a = Prelude."
]
_ <- waitForDiagnostics
compls <- getCompletions doc (Position 3 13)
liftIO $ length compls @?= maxCompletions
]

highlightTests :: TestTree
Expand Down