diff --git a/ilsp/bicep_lsp/proxy.py b/ilsp/bicep_lsp/proxy.py index c618dc8..04555e8 100644 --- a/ilsp/bicep_lsp/proxy.py +++ b/ilsp/bicep_lsp/proxy.py @@ -187,8 +187,12 @@ class _ProxySession: return {"type": "unknown"} - def pop_context(self, msg_id) -> dict: - return self.pending.pop(msg_id, {"type": "unknown"}) + def pop_context(self, msg_id) -> dict | None: + """Return the tracked completion context for msg_id, or None if this + response id does not correspond to a textDocument/completion request + we recorded (e.g. hover/definition/references/... responses must never + be treated as completion responses).""" + return self.pending.pop(msg_id, None) # ── Completion injection ─────────────────────────────────────────────────────── @@ -316,10 +320,14 @@ def _ls_to_client( logger.debug("LS→Client: %d bytes", len(body)) try: msg = json.loads(body) - context: dict = {} + context = None if "id" in msg and "result" in msg: context = session.pop_context(msg["id"]) - out = _inject_completions(msg, context) + # Only rewrite responses that actually correspond to a + # textDocument/completion request we tracked — any other + # response (hover, definition, references, documentSymbol, + # formatting, codeAction, ...) must pass through untouched. + out = _inject_completions(msg, context) if context is not None else body except json.JSONDecodeError: out = body conn.sendall(_frame(out)) diff --git a/tests/test_proxy.py b/tests/test_proxy.py index 091bde8..e03f81f 100644 --- a/tests/test_proxy.py +++ b/tests/test_proxy.py @@ -502,6 +502,7 @@ def test_session_records_and_pops_context(): assert ctx["type"] == "param" assert ctx["module"] == "appservice" - # Second pop returns unknown - assert session.pop_context(42)["type"] == "unknown" + # Second pop (or any untracked id) returns None — the response must pass + # through untouched rather than being mistaken for a completion response. + assert session.pop_context(42) is None