diff --git a/service/dap/daptest/client.go b/service/dap/daptest/client.go index 1a4f13a397..fbf4b89df3 100644 --- a/service/dap/daptest/client.go +++ b/service/dap/daptest/client.go @@ -231,6 +231,8 @@ func (c *Client) InitializeRequest() { SupportsVariablePaging: true, SupportsRunInTerminalRequest: true, SupportsMemoryReferences: true, + SupportsMemoryEvent: true, + SupportsInvalidatedEvent: true, Locale: "en-us", } c.send(request) diff --git a/service/dap/server.go b/service/dap/server.go index c73b36660a..c83838c2e5 100644 --- a/service/dap/server.go +++ b/service/dap/server.go @@ -337,6 +337,8 @@ type dapClientCapabilities struct { supportsRunInTerminalRequest bool supportsMemoryReferences bool supportsProgressReporting bool + supportsMemoryEvent bool + supportsInvalidatedEvent bool } // DefaultLoadConfig controls how variables are loaded from the target's memory. @@ -994,6 +996,8 @@ func (s *Session) setClientCapabilities(args dap.InitializeRequestArguments) { s.clientCapabilities.supportsRunInTerminalRequest = args.SupportsRunInTerminalRequest s.clientCapabilities.supportsVariablePaging = args.SupportsVariablePaging s.clientCapabilities.supportsVariableType = args.SupportsVariableType + s.clientCapabilities.supportsMemoryEvent = args.SupportsMemoryEvent + s.clientCapabilities.supportsInvalidatedEvent = args.SupportsInvalidatedEvent } func cleanExeName(name string) string { @@ -3652,6 +3656,17 @@ func (s *Session) onSetVariableRequest(request *dap.SetVariableRequest) { // TODO(hyangah): instead of arg.Value, reload the variable and return // the presentation of the new value. s.send(response) + + if s.clientCapabilities.supportsInvalidatedEvent { + // Enforce editors to reload full state after successfull variable update + // to fix problem described above + s.send(&dap.InvalidatedEvent{ + Event: *s.newEvent("invalidated"), + Body: dap.InvalidatedEventBody{ + Areas: []dap.InvalidatedAreas{"all"}, + }, + }) + } } // onSetExpressionRequest sends a not-yet-implemented error response. @@ -3788,6 +3803,16 @@ func (s *Session) onWriteMemoryRequest(request *dap.WriteMemoryRequest) { BytesWritten: n, }, }) + + if s.clientCapabilities.supportsInvalidatedEvent { + // Inform editor to refetch variables after changes + s.send(&dap.InvalidatedEvent{ + Event: *s.newEvent("invalidated"), + Body: dap.InvalidatedEventBody{ + Areas: []dap.InvalidatedAreas{"variables"}, + }, + }) + } } func (s *Session) writeTargetMemory(addr uint64, data []byte) (int, error) { diff --git a/service/dap/server_test.go b/service/dap/server_test.go index 01d0dcd58f..29e78d2fe0 100644 --- a/service/dap/server_test.go +++ b/service/dap/server_test.go @@ -6636,6 +6636,10 @@ func (h *helperForSetVariable) expectSetVariable0(ref int, name, value string, w if got, want := h.c.ExpectSetVariableResponse(h.t), value; got.Success != true || got.Body.Value != want { h.t.Errorf("SetVariableRequest(%v, %v)=%#v, want {Success=true, Body.Value=%q", name, value, got, want) } + ie := h.c.ExpectInvalidatedEvent(h.t) + if len(ie.Body.Areas) != 1 && ie.Body.Areas[0] != "all" { + h.t.Errorf("expected 'all' invalidated areas, got %v", ie.Body.Areas) + } } func (h *helperForSetVariable) failSetVariable0(ref int, name, value, wantErrInfo string, wantStop bool) { @@ -8596,6 +8600,10 @@ func TestWriteMemory(t *testing.T) { if wr.Body.BytesWritten != len(newData) { t.Fatalf("expected %d bytes written, got %d", len(newData), wr.Body.BytesWritten) } + ie := client.ExpectInvalidatedEvent(t) + if len(ie.Body.Areas) != 1 && ie.Body.Areas[0] != "variables" { + t.Fatalf("expected 'varianles' invalidated areas, got %v", ie.Body.Areas) + } client.ReadMemoryRequest(bytesVar.MemoryReference, 0, len(newData)) rm = client.ExpectReadMemoryResponse(t) @@ -8612,6 +8620,10 @@ func TestWriteMemory(t *testing.T) { if wr.Body.BytesWritten != len(origData) { t.Fatalf("expected %d bytes written, got %d", len(newData), wr.Body.BytesWritten) } + ie = client.ExpectInvalidatedEvent(t) + if len(ie.Body.Areas) != 1 && ie.Body.Areas[0] != "variables" { + t.Fatalf("expected 'variables' invalidated areas, got %v", ie.Body.Areas) + } }, disconnect: true, },