Breakpoints flicker as they are removed/re-added when breakpoints are added/removed
Because we mark breakpoints as unverified initially now, and we delete/re-create them when anything changes (because VS Code just gives us a whole new set), there's a noticable flicker.
https://github.com/Dart-Code/Dart-Code/assets/21116742/daa2f555-2830-4fd7-8f21-7b00d4dc103c
I have a fix for this, but I implemented my tests in a different way to what VS Code does, because the spec doesn't make it clear whether "changed" breakpoint events should affect what's sent to setBreakpoints. I've opened some issues to try and get clarification/a fix:
- https://github.com/microsoft/debug-adapter-protocol/issues/545
- https://github.com/microsoft/debug-adapter-protocol/issues/542
VS Code clarified the current behaviour is intended (and will hopefully update the spec). I've updated my change to match this behaviour and verified that adding a single breakpoint to a file with lots of existing breakpoints only results in one additional breakpoint added to the VM (instead of lots of deletes and then re-adding them all):
[1:06:57 PM] [DAP] [Info] ==> {"command":"setBreakpoints","arguments":{"lines":[2,9,13,17,18,20,23,25,27],"breakpoints":[{"line":2},{"line":9},{"line":13},{"line":17},{"line":18},{"line":20},{"line":23},{"line":25},{"line":27}],"sourceModified":false},"type":"request","seq":16}
[1:06:57 PM] [DAP] [Info] <== {"seq":153,"type":"event","body":{"message":"==> [VM] {\"jsonrpc\":\"2.0\",\"id\":\"50\",\"method\":\"addBreakpointWithScriptUri\",\"params\":{\"isolateId\":\"isolates/8439425881979019\",\"scriptUri\":\"file:///D:/Dev/Test%20Projects/dart_sample/bin/bptesting.dart\",\"line\":18}}"},"event":"dart.log"}
[1:06:57 PM] [VmService] [Info] [dart_sample] ==> [VM] {"jsonrpc":"2.0","id":"50","method":"addBreakpointWithScriptUri","params":{"isolateId":"isolates/8439425881979019","scriptUri":"file:///D:/Dev/Test%20Projects/dart_sample/bin/bptesting.dart","line":18}}
[1:06:57 PM] [DAP] [Info] <== {"seq":154,"type":"event","body":{"message":"<== [VM] {\"jsonrpc\":\"2.0\",\"method\":\"streamNotify\",\"params\":{\"streamId\":\"Debug\",\"event\":{\"type\":\"Event\",\"kind\":\"BreakpointAdded\",\"isolateGroup\":{\"type\":\"@IsolateGroup\",\"id\":\"isolateGroups/8483241635529567\",\"name\":\"D:\\\\Dev\\\\Test Projects\\\\dart_sample\\\\bin\\\\bptesting.dart\",\"number\":\"8483241635529567\",\"isSystemIsolateGroup\":false},\"isolate\":{\"type\":\"@Isolate\",\"id\":\"isolates/8439425881979019\",\"name\":\"main\",\"number\":\"8439425881979019\",\"isSystemIsolate\":false,\"isolateGroupId\":\"isolateGroups/8483241635529567\"},\"timestamp\":1749557217363,\"breakpoint\":{\"type\":\"Breakpoint\",\"fixedId\":true,\"id\":\"breakpoints/14\",\"enabled\":true,\"breakpointNumber\":14,\"resolved\":true,\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"libraries/@21043771/scripts/file%3A%2F%2F%2FD%3A%2FDev%2FTest%2520Projects%2Fdart_sample%2Fbin%2Fbptesting.dart/19759bc50c1\",\"uri\":\"file:///D:/Dev/Test%20Projects/dart_sample/bin/bptesting.dart\"},\"tokenPos\":361,\"line\":18,\"column\":3}}}}}"},"event":"dart.log"}
[1:06:57 PM] [DAP] [Info] <== {"seq":155,"type":"event","body":{"message":"<== [VM] {\"jsonrpc\":\"2.0\",\"result\":{\"type\":\"Breakpoint\",\"fixedId\":true,\"id\":\"breakpoints/14\",\"enabled\":true,\"breakpointNumber\":14,\"resolved\":true,\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"libraries/@21043771/scripts/file%3A%2F%2F%2FD%3A%2FDev%2FTest%2520Projects%2Fdart_sample%2Fbin%2Fbptesting.dart/19759bc50c1\",\"uri\":\"file:///D:/Dev/Test%20Projects/dart_sample/bin/bptesting.dart\",\"_kind\":\"kernel\"},\"tokenPos\":361,\"line\":18,\"column\":3}},\"id\":\"50\"}"},"event":"dart.log"}
[1:06:57 PM] [DAP] [Info] <== {"seq":156,"type":"response","body":{"breakpoints":[{"column":3,"id":100000,"line":2,"verified":true},{"column":3,"id":100001,"line":9,"verified":true},{"column":3,"id":100002,"line":13,"verified":true},{"column":3,"id":100003,"line":17,"verified":true},{"id":100013,"message":"Breakpoint has not yet been resolved","reason":"pending","verified":false},{"column":3,"id":100004,"line":20,"verified":true},{"column":3,"id":100005,"line":23,"verified":true},{"column":3,"id":100006,"line":25,"verified":true},{"column":3,"id":100007,"line":27,"verified":true}]},"command":"setBreakpoints","request_seq":16,"success":true}
[1:06:57 PM] [VmService] [Info] [dart_sample] <== [VM] {"jsonrpc":"2.0","method":"streamNotify","params":{"streamId":"Debug","event":{"type":"Event","kind":"BreakpointAdded","isolateGroup":{"type":"@IsolateGroup","id":"isolateGroups/8483241635529567","name":"D:\\Dev\\Test Projects\\dart_sample\\bin\\bptesting.dart","number":"8483241635529567","isSystemIsolateGroup":false},"isolate":{"type":"@Isolate","id":"isolates/8439425881979019","name":"main","number":"8439425881979019","isSystemIsolate":false,"isolateGroupId":"isolateGroups/8483241635529567"},"timestamp":1749557217363,"breakpoint":{"type":"Breakpoint","fixedId":true,"id":"breakpoints/14","enabled":true,"breakpointNumber":14,"resolved":true,"location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@21043771/scripts/file%3A%2F%2F%2FD%3A%2FDev%2FTest%2520Projects%2Fdart_sample%2Fbin%2Fbptesting.dart/19759bc50c1","uri":"file:///D:/Dev/Test%20Projects/dart_sample/bin/bptesting.dart"},"tokenPos":361,"line":18,"column":3}}}}}
[1:06:57 PM] [VmService] [Info] [dart_sample] <== [VM] {"jsonrpc":"2.0","result":{"type":"Breakpoint","fixedId":true,"id":"breakpoints/14","enabled":true,"breakpointNumber":14,"resolved":true,"location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@21043771/scripts/file%3A%2F%2F%2FD%3A%2FDev%2FTest%2520Projects%2Fdart_sample%2Fbin%2Fbptesting.dart/19759bc50c1","uri":"file:///D:/Dev/Test%20Projects/dart_sample/bin/bptesting.dart","_kind":"kernel"},"tokenPos":361,"line":18,"column":3}},"id":"50"}
[1:06:57 PM] [DAP] [Info] <== {"seq":157,"type":"event","body":{"breakpoint":{"column":3,"id":100013,"line":18,"verified":true},"reason":"changed"},"event":"breakpoint"}
https://dart-review.googlesource.com/c/sdk/+/433700
Fixed by https://github.com/dart-lang/sdk/commit/d0a7ef44595fc7ab2991c391c6cd0609b7688402, but will require a DDS release to get to Flutter.
@bkonyi it's not urgent, but would it be possible to do a DDS release in time to roll into Flutter before the next beta branch? (I don't know when that is, but perhaps you do)
@bkonyi it's not urgent, but would it be possible to do a DDS release in time to roll into Flutter before the next beta branch? (I don't know when that is, but perhaps you do)
Published! I'll try to make sure it gets rolled in today. Not sure when the next beta cut is, but I think it's soon.
@bkonyi thank you! Please let me know if you encounter any issues rolling it in (or if it needs doing manually, if you'd like me to look at it).
This fix is now in Flutter too. When adding/removing breakpoints, I now see just one add/remove request to the VM for each, and the responses indicate breakpoints that were already verified (therefore would not temporarily change back to grey):
It's likely this fix will be reverted for now due to some other issues (see https://docs.google.com/document/d/1eeEHG3EL4D5EbB3YiAO5X2TcCRIciFMSPKL_hFGP0Gk/edit?disco=AAABk-csO5o), so re-opening this to fix again after.