Returned selection is changed
Try to format the following code. Note that that is an empty line between "foo" and "main". If initial selection is on this line, the returned selection is on "main". It does not seem right.
var foo;
main() {}
Also formatting of this code also changes selection when the full line with "print" is selected.
main() {
print("hello");
}
Handling selection markers in whitespace is really difficult. The formatter doesn't really model the original whitespace in its internal representation. It only tracks the number of newlines between tokens for the couple of places where that affects formatting (like inserting a blank line between statements). It's also not entirely clear how the selection markers should move if they are in whitespace and the formatter changes the whitespace.
Instead, the formatter has a sort of simplified approach to handling selection markers. If the selection start is in whitespace, it gets pushed forward until it reaches a non-whitespace token. Likewise, the selection end is pulled back until it hits the end of a token (or the selection start). So if you have something like:
main() {
‹ print("hello");
›
}
Where ‹ and › are the selection markers, then the formatter snaps them to:
main() {
‹print("hello");›
}
That's probably not ideal, but given how old this bug is, it's probably good enough. Also, it seems like VS Code at least is smart enough to fully preserve the original selection when you format. I think it's because the plug-in generates an actual diff from the format and applies the changes separately? (Is that right, @DanTup?)
Either way, I'm going to go ahead and close this because at 9 years old, this doesn't seem to be a burning issue. :)
Also, it seems like VS Code at least is smart enough to fully preserve the original selection when you format. I think it's because the plug-in generates an actual diff from the format and applies the changes separately? (Is that right, @DanTup?)
Yeah, we do that in the analysis server.. We parse the before/after and step through the token streams to figure out what actually changed (it's not a complete text diff, it's much simpler and only handles whitespace changes and added/missing commas).
The result is smaller diffs so if the caret location (and breakpoints, etc.) are more likely to be preserved than if the whole doc is replaced.
It looks like the legacy edit.format request in the server does allow for multiple edits to come back, so depending on how the IntelliJ plugin handles the response, it might be possible to also apply that diffing to the legacy protocol? (I don't know if it's worth it though - because I don't know how bad the issue here is).
because I don't know how bad the issue here is
No one seems to have complained over nearly a decade, so I don't think it's a big deal.