[analysis_server] Support formatting leading whitespace at the start or ranges in LSP format range

Fixes https://github.com/Dart-Code/Dart-Code/issues/3583.

Change-Id: Id2974b173eb3589ff983316d1cec0ea1e45ecd97
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/218141
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny 2021-10-26 17:37:21 +00:00 committed by commit-bot@chromium.org
parent 0fe438812b
commit 9a873bc23f
2 changed files with 65 additions and 5 deletions

View file

@ -167,7 +167,48 @@ ErrorOr<List<TextEdit>> _generateMinimalEdits(
int formattedStart,
int formattedEnd,
) {
final unformattedWhitespace =
unformatted.substring(unformattedStart, unformattedEnd);
final formattedWhitespace =
formatted.substring(formattedStart, formattedEnd);
if (rangeStart != null && rangeEnd != null) {
// If this change crosses over the start of the requested range, discarding
// the change may result in leading whitespace of the next line not being
// formatted correctly.
//
// To handle this, if both unformatted/formatted contain at least one
// newline, split this change into two around the last newline so that the
// final part (likely leading whitespace) can be included without
// including the whole change.
//
// Without this, functionality like VS Code's "format modified lines"
// (which uses Git status to know which lines are edited) may appear to
// fail to format the first newly added line in a range.
if (unformattedStart < rangeStart.result &&
unformattedEnd > rangeStart.result &&
unformattedWhitespace.contains('\n') &&
formattedWhitespace.contains('\n')) {
// Find the offsets of the character after the last newlines.
final unformattedOffset = unformattedWhitespace.lastIndexOf('\n') + 1;
final formattedOffset = formattedWhitespace.lastIndexOf('\n') + 1;
// Call us again for the leading part
addEditFor(
unformattedStart,
unformattedStart + unformattedOffset,
formattedStart,
formattedStart + formattedOffset,
);
// Call us again for the trailing part
addEditFor(
unformattedStart + unformattedOffset,
unformattedEnd,
formattedStart + formattedOffset,
formattedEnd,
);
return;
}
// If we're formatting only a range, skip over any segments that don't fall
// entirely within that range.
if (unformattedStart < rangeStart.result ||
@ -176,11 +217,6 @@ ErrorOr<List<TextEdit>> _generateMinimalEdits(
}
}
final unformattedWhitespace =
unformatted.substring(unformattedStart, unformattedEnd);
final formattedWhitespace =
formatted.substring(formattedStart, formattedEnd);
if (unformattedWhitespace == formattedWhitespace) {
return;
}

View file

@ -210,6 +210,30 @@ void f()
await expectRangeFormattedContents(mainFileUri, contents, expected);
}
Future<void> test_formatRange_expandsLeadingWhitespaceToNearestLine() async {
const contents = '''
void main()
{
[[ print('test'); // line 2
print('test'); // line 3
print('test'); // line 4]]
}
''';
const expected = '''
void main()
{
print('test'); // line 2
print('test'); // line 3
print('test'); // line 4
}
''';
await initialize();
await openFile(mainFileUri, withoutMarkers(contents));
await expectRangeFormattedContents(mainFileUri, contents, expected);
}
Future<void> test_formatRange_invalidRange() async {
const contents = '''
void f()