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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ Here is a list of the additional settings currently supported by `haskell-langua
- Completion snippets (`haskell.completionSnippetsOn`, default true): whether to support completion snippets
- Liquid Haskell (`haskell.liquidOn`, default false): whether to enable Liquid Haskell support (currently unused until the Liquid Haskell support is functional again)
- Hlint (`haskell.hlintOn`, default true): whether to enable Hlint support
- Max completions (`haskell.maxCompletions`, default 40): maximum number of completions sent to the LSP client.

Settings like this are typically provided by the language-specific LSP client support for your editor, for example in Emacs by `lsp-haskell`.

Expand Down
11 changes: 6 additions & 5 deletions ghcide/src/Development/IDE/Plugin/Completions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Development.IDE.GHC.Util
import Development.IDE.LSP.Server
import TcRnDriver (tcRnImportDecls)
import Data.Maybe
import Ide.Plugin.Config (Config(completionSnippetsOn))
import Ide.Plugin.Config (Config (completionSnippetsOn, maxCompletions))
import Ide.PluginUtils (getClientConfig)

#if defined(GHC_LIB)
Expand Down Expand Up @@ -115,7 +115,6 @@ data NonLocalCompletions = NonLocalCompletions
instance Hashable NonLocalCompletions
instance NFData NonLocalCompletions
instance Binary NonLocalCompletions

-- | Generate code actions.
getCompletionsLSP
:: LSP.LspFuncs Config
Expand Down Expand Up @@ -144,12 +143,14 @@ getCompletionsLSP lsp ide
-> return (Completions $ List [])
(Just pfix', _) -> do
let clientCaps = clientCapabilities $ shakeExtras ide
snippets <- WithSnippets . completionSnippetsOn <$> getClientConfig lsp
Completions . List <$> getCompletions ideOpts cci' parsedMod bindMap pfix' clientCaps snippets
config <- getClientConfig lsp
let snippets = WithSnippets . completionSnippetsOn $ config
allCompletions <- getCompletions ideOpts cci' parsedMod bindMap pfix' clientCaps snippets
let (topCompletions, rest) = splitAt (maxCompletions config) 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
12 changes: 11 additions & 1 deletion ghcide/test/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3262,7 +3262,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 def
]

highlightTests :: TestTree
Expand Down
3 changes: 3 additions & 0 deletions hls-plugin-api/src/Ide/Plugin/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ data Config =
, completionSnippetsOn :: !Bool
, formatOnImportOn :: !Bool
, formattingProvider :: !T.Text
, maxCompletions :: !Int
, plugins :: !(Map.Map T.Text PluginConfig)
} deriving (Show,Eq)

Expand All @@ -87,6 +88,7 @@ instance Default Config where
, formattingProvider = "ormolu"
-- , formattingProvider = "floskell"
-- , formattingProvider = "stylish-haskell"
, maxCompletions = 40
, plugins = Map.empty
}

Expand All @@ -107,6 +109,7 @@ instance A.FromJSON Config where
<*> o .:? "completionSnippetsOn" .!= completionSnippetsOn def
<*> o .:? "formatOnImportOn" .!= formatOnImportOn def
<*> o .:? "formattingProvider" .!= formattingProvider def
<*> o .:? "maxCompletions" .!= maxCompletions def
<*> o .:? "plugin" .!= plugins def

-- 2017-10-09 23:22:00.710515298 [ThreadId 11] - ---> {"jsonrpc":"2.0","method":"workspace/didChangeConfiguration","params":{"settings":{"haskell":{"maxNumberOfProblems":100,"hlintOn":true}}}}
Expand Down
25 changes: 12 additions & 13 deletions test/functional/Completion.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import Test.Tasty
import Test.Tasty.ExpectedFailure (ignoreTestBecause)
import Test.Tasty.HUnit
import qualified Data.Text as T
import System.Time.Extra (sleep)

tests :: TestTree
tests = testGroup "completions" [
Expand Down Expand Up @@ -54,12 +53,12 @@ tests = testGroup "completions" [
, testCase "completes imports" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
doc <- openDoc "Completion.hs" "haskell"

liftIO $ sleep 4
_ <- waitForDiagnostics

let te = TextEdit (Range (Position 1 17) (Position 1 26)) "Data.M"
_ <- applyEdit doc te

compls <- getCompletions doc (Position 1 22)
compls <- getCompletions doc (Position 1 23)
let item = head $ filter ((== "Maybe") . (^. label)) compls
liftIO $ do
item ^. label @?= "Maybe"
Expand All @@ -69,22 +68,22 @@ tests = testGroup "completions" [
, testCase "completes qualified imports" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
doc <- openDoc "Completion.hs" "haskell"

liftIO $ sleep 4
_ <- waitForDiagnostics

let te = TextEdit (Range (Position 2 17) (Position 1 25)) "Dat"
let te = TextEdit (Range (Position 2 17) (Position 2 25)) "Data.L"
_ <- applyEdit doc te

compls <- getCompletions doc (Position 1 19)
let item = head $ filter ((== "Data.List") . (^. label)) compls
compls <- getCompletions doc (Position 2 24)
let item = head $ filter ((== "List") . (^. label)) compls
liftIO $ do
item ^. label @?= "Data.List"
item ^. label @?= "List"
item ^. detail @?= Just "Data.List"
item ^. kind @?= Just CiModule

, testCase "completes language extensions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
doc <- openDoc "Completion.hs" "haskell"

liftIO $ sleep 4
_ <- waitForDiagnostics

let te = TextEdit (Range (Position 0 24) (Position 0 31)) ""
_ <- applyEdit doc te
Expand All @@ -98,7 +97,7 @@ tests = testGroup "completions" [
, testCase "completes pragmas" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
doc <- openDoc "Completion.hs" "haskell"

liftIO $ sleep 4
_ <- waitForDiagnostics

let te = TextEdit (Range (Position 0 4) (Position 0 34)) ""
_ <- applyEdit doc te
Expand Down Expand Up @@ -128,7 +127,7 @@ tests = testGroup "completions" [
, testCase "completes options pragma" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
doc <- openDoc "Completion.hs" "haskell"

liftIO $ sleep 4
_ <- waitForDiagnostics

let te = TextEdit (Range (Position 0 4) (Position 0 34)) "OPTIONS"
_ <- applyEdit doc te
Expand Down Expand Up @@ -159,7 +158,7 @@ tests = testGroup "completions" [
doc <- openDoc "Completion.hs" "haskell"

compls <- getCompletions doc (Position 5 7)
liftIO $ any ((== "!!") . (^. label)) compls @? ""
liftIO $ assertBool "Expected completions" $ not $ null compls

-- See https://github.com/haskell/haskell-ide-engine/issues/903
, testCase "strips compiler generated stuff from completions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
Expand Down Expand Up @@ -349,7 +348,7 @@ contextTests = testGroup "contexts" [
, testCase "only provides value suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do
doc <- openDoc "Context.hs" "haskell"

compls <- getCompletions doc (Position 3 9)
compls <- getCompletions doc (Position 3 10)
liftIO $ do
compls `shouldContainCompl` "abs"
compls `shouldNotContainCompl` "Applicative"
Expand Down