Skip to content

Commit 46c3e1f

Browse files
committed
Enforce max completions across HLS plugins
1 parent 15c070c commit 46c3e1f

File tree

2 files changed

+39
-19
lines changed

2 files changed

+39
-19
lines changed

ghcide/src/Development/IDE/Plugin/Completions.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import Development.IDE.GHC.Util
3030
import Development.IDE.LSP.Server
3131
import TcRnDriver (tcRnImportDecls)
3232
import Data.Maybe
33-
import Ide.Plugin.Config (Config (completionSnippetsOn, maxCompletions))
33+
import Ide.Plugin.Config (Config (completionSnippetsOn))
3434
import Ide.PluginUtils (getClientConfig)
3535

3636
#if defined(GHC_LIB)
@@ -146,8 +146,7 @@ getCompletionsLSP lsp ide
146146
config <- getClientConfig lsp
147147
let snippets = WithSnippets . completionSnippetsOn $ config
148148
allCompletions <- getCompletions ideOpts cci' parsedMod bindMap pfix' clientCaps snippets
149-
let (topCompletions, rest) = splitAt (maxCompletions config) allCompletions
150-
pure $ CompletionList (CompletionListType (null rest) (List topCompletions))
149+
pure $ Completions (List allCompletions)
151150
_ -> return (Completions $ List [])
152151
_ -> return (Completions $ List [])
153152
_ -> return (Completions $ List [])

ghcide/src/Development/IDE/Plugin/HLS.hs

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ module Development.IDE.Plugin.HLS
66
) where
77

88
import Control.Exception(SomeException, catch)
9-
import Control.Lens ( (^.) )
9+
import Control.Lens ((^.))
1010
import Control.Monad
1111
import qualified Data.Aeson as J
12+
import qualified Data.DList as DList
1213
import Data.Either
1314
import qualified Data.List as List
1415
import qualified Data.Map as Map
@@ -436,35 +437,55 @@ makeCompletions :: [(PluginId, CompletionProvider IdeState)]
436437
makeCompletions sps lf ideState params@(CompletionParams (TextDocumentIdentifier doc) pos _context _mt)
437438
= do
438439
mprefix <- getPrefixAtPos lf doc pos
439-
_snippets <- WithSnippets . completionSnippetsOn <$> getClientConfig lf
440+
config <- getClientConfig lf
440441

441442
let
442443
combine :: [CompletionResponseResult] -> CompletionResponseResult
443-
combine cs = go (Completions $ List []) cs
444-
where
445-
go acc [] = acc
446-
go (Completions (List ls)) (Completions (List ls2):rest)
447-
= go (Completions (List (ls <> ls2))) rest
448-
go (Completions (List ls)) (CompletionList (CompletionListType complete (List ls2)):rest)
449-
= go (CompletionList $ CompletionListType complete (List (ls <> ls2))) rest
450-
go (CompletionList (CompletionListType complete (List ls))) (CompletionList (CompletionListType complete2 (List ls2)):rest)
451-
= go (CompletionList $ CompletionListType (complete || complete2) (List (ls <> ls2))) rest
452-
go (CompletionList (CompletionListType complete (List ls))) (Completions (List ls2):rest)
453-
= go (CompletionList $ CompletionListType complete (List (ls <> ls2))) rest
454-
makeAction (pid,p) = do
444+
combine cs = go True mempty cs
445+
446+
go !comp acc [] =
447+
CompletionList (CompletionListType comp (List $ DList.toList acc))
448+
go comp acc (Completions (List ls) : rest) =
449+
go comp (acc <> DList.fromList ls) rest
450+
go comp acc (CompletionList (CompletionListType comp' (List ls)) : rest) =
451+
go (comp && comp') (acc <> DList.fromList ls) rest
452+
453+
-- | Process a list of completion providers until we reach a max number of results
454+
makeAction ::
455+
Int ->
456+
[(PluginId, CompletionProvider IdeState)] ->
457+
IO [Either ResponseError CompletionResponseResult]
458+
makeAction 0 _ = return []
459+
makeAction _ [] = return []
460+
makeAction n ((pid, p) : rest) = do
455461
pluginConfig <- getPluginConfig lf pid
456-
if pluginEnabled pluginConfig plcCompletionOn
462+
results <- if pluginEnabled pluginConfig plcCompletionOn
457463
then otTracedProvider pid "completions" $ p lf ideState params
458464
else return $ Right $ Completions $ List []
465+
case results of
466+
Right resp -> do
467+
let (n', results') = consumeCompletionResponse n resp
468+
(Right results' :) <$> makeAction n' rest
469+
Left err ->
470+
(Left err :) <$> makeAction n rest
459471

460472
case mprefix of
461473
Nothing -> return $ Right $ Completions $ List []
462474
Just _prefix -> do
463-
mhs <- mapM makeAction sps
475+
mhs <- makeAction (maxCompletions config) sps
464476
case rights mhs of
465477
[] -> return $ Left $ responseError $ T.pack $ show $ lefts mhs
466478
hs -> return $ Right $ combine hs
467479

480+
-- | Crops a completion response. Returns the final number of completions and the cropped response
481+
consumeCompletionResponse :: Int -> CompletionResponseResult -> (Int, CompletionResponseResult)
482+
consumeCompletionResponse n it@(CompletionList (CompletionListType _ (List xx))) =
483+
case splitAt n xx of
484+
(_, []) -> (n - length xx, it)
485+
(xx', _) -> (0, CompletionList (CompletionListType False (List xx')))
486+
consumeCompletionResponse n (Completions (List xx)) =
487+
consumeCompletionResponse n (CompletionList (CompletionListType False (List xx)))
488+
468489
getPrefixAtPos :: LSP.LspFuncs Config -> Uri -> Position -> IO (Maybe VFS.PosPrefixInfo)
469490
getPrefixAtPos lf uri pos = do
470491
mvf <- LSP.getVirtualFileFunc lf (J.toNormalizedUri uri)

0 commit comments

Comments
 (0)