Skip to content

Commit d51c68d

Browse files
committed
Always handle "completion/resolve" requests
Resolves the LSP "completion/resolve" requests, even if there is nothing more to resolve. If there is nothing to resolve, we simply return the initial completion item. If we reject "completion/resolve" requests, then some LSP clients show our rejection as pop-ups which are hugely distracting. We change completion tests to always resolve completions, regardless of the existence of `_data_`, as this seems to be the behaviour of VSCode.
1 parent 25c5d82 commit d51c68d

File tree

4 files changed

+31
-14
lines changed

4 files changed

+31
-14
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ dropListFromImportDecl iDecl = let
127127
in f <$> iDecl
128128

129129
resolveCompletion :: ResolveFunction IdeState CompletionResolveData Method_CompletionItemResolve
130+
resolveCompletion _ide _pid comp _uri NothingToResolve = pure comp
130131
resolveCompletion ide _pid comp@CompletionItem{_detail,_documentation,_data_} uri (CompletionResolveData _ needType (NameDetails mod occ)) =
131132
do
132133
file <- getNormalizedFilePathE uri

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,9 @@ mkCompl
229229
_additionalTextEdits = Nothing,
230230
_commitCharacters = Nothing,
231231
_command = mbCommand,
232-
_data_ = toJSON <$> fmap (CompletionResolveData uri (isNothing typeText)) nameDetails,
232+
_data_ = Just $ toJSON $ case nameDetails of
233+
Nothing -> NothingToResolve
234+
Just nameDets -> CompletionResolveData uri (isNothing typeText) nameDets,
233235
_labelDetails = Nothing,
234236
_textEditText = Nothing}
235237
removeSnippetsWhen (isJust isInfix) ci
@@ -309,7 +311,7 @@ mkExtCompl label =
309311
defaultCompletionItemWithLabel :: T.Text -> CompletionItem
310312
defaultCompletionItemWithLabel label =
311313
CompletionItem label def def def def def def def def def
312-
def def def def def def def def def
314+
def def def def def def def def (Just $ toJSON NothingToResolve)
313315

314316
fromIdentInfo :: Uri -> IdentInfo -> Maybe T.Text -> CompItem
315317
fromIdentInfo doc identInfo@IdentInfo{..} q = CI

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

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,19 @@ instance Show NameDetails where
199199
-- | The data that is actually sent for resolve support
200200
-- We need the URI to be able to reconstruct the GHC environment
201201
-- in the file the completion was triggered in.
202-
data CompletionResolveData = CompletionResolveData
203-
{ itemFile :: Uri
204-
, itemNeedsType :: Bool -- ^ Do we need to lookup a type for this item?
205-
, itemName :: NameDetails
206-
}
202+
data CompletionResolveData
203+
= NothingToResolve
204+
-- ^ The client requested to resolve a completion, but there is nothing to resolve,
205+
-- as we can't add any additional information, such as docs.
206+
-- We still handle these requests, otherwise HLS will reject "completion/resolve" requests
207+
-- which present on some clients (e.g., emacs) as an error message.
208+
-- See https://github.com/haskell/haskell-language-server/issues/4451 for the issue that
209+
-- triggered this change.
210+
| CompletionResolveData
211+
-- ^ Data that we use to handle "completion/resolve" requests.
212+
{ itemFile :: Uri
213+
, itemNeedsType :: Bool -- ^ Do we need to lookup a type for this item?
214+
, itemName :: NameDetails
215+
}
207216
deriving stock Generic
208217
deriving anyclass (FromJSON, ToJSON)

ghcide/test/exe/CompletionTests.hs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -557,19 +557,24 @@ completionDocTests =
557557
]
558558
let expected = "*Imported from 'Prelude'*\n"
559559
test doc (Position 1 7) "id" (Just $ T.length expected) [expected]
560+
, testSessionEmpty "defined in where clause" $ do
561+
doc <- createDoc "A.hs" "haskell" $ T.unlines
562+
[ "module A where"
563+
, "bar = foo"
564+
, " where foobar = 5"
565+
]
566+
let expected = "*Defined at line 3, column"
567+
test doc (Position 1 9) "foobar" (Just $ T.length expected) [expected]
560568
]
561569
where
562570
test doc pos label mn expected = do
563571
_ <- waitForDiagnostics
564572
compls <- getCompletions doc pos
565573
rcompls <- forM compls $ \item -> do
566-
if isJust (item ^. L.data_)
567-
then do
568-
rsp <- request SMethod_CompletionItemResolve item
569-
case rsp ^. L.result of
570-
Left err -> liftIO $ assertFailure ("completionItem/resolve failed with: " <> show err)
571-
Right x -> pure x
572-
else pure item
574+
rsp <- request SMethod_CompletionItemResolve item
575+
case rsp ^. L.result of
576+
Left err -> liftIO $ assertFailure ("completionItem/resolve failed with: " <> show err)
577+
Right x -> pure x
573578
let compls' = [
574579
-- We ignore doc uris since it points to the local path which determined by specific machines
575580
case mn of

0 commit comments

Comments
 (0)