Support overlays in completion_metrics_client.dart

Change-Id: Idedb38193ed80be0fa10e8e6be3fa04f8f30b100
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243649
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
Sam Rawlins 2022-05-04 20:58:54 +00:00 committed by Commit Bot
parent 78f218eb4c
commit 84ca405b35
3 changed files with 125 additions and 69 deletions

View file

@ -155,11 +155,11 @@ ArgParser createArgParser() {
) )
..addOption(CompletionMetricsOptions.OVERLAY, ..addOption(CompletionMetricsOptions.OVERLAY,
allowed: [ allowed: [
CompletionMetricsOptions.OVERLAY_NONE, OverlayMode.none.flag,
CompletionMetricsOptions.OVERLAY_REMOVE_TOKEN, OverlayMode.removeRestOfFile.flag,
CompletionMetricsOptions.OVERLAY_REMOVE_REST_OF_FILE OverlayMode.removeToken.flag,
], ],
defaultsTo: CompletionMetricsOptions.OVERLAY_NONE, defaultsTo: OverlayMode.none.flag,
help: help:
'Before attempting a completion at the location of each token, the ' 'Before attempting a completion at the location of each token, the '
'token can be removed, or the rest of the file can be removed to ' 'token can be removed, or the rest of the file can be removed to '
@ -745,17 +745,20 @@ class CompletionQualityMetricsComputer extends CompletionMetricsComputer {
ExpectedCompletion expectedCompletion, ExpectedCompletion expectedCompletion,
) async { ) async {
// If an overlay option is being used, compute the overlay file, and // If an overlay option is being used, compute the overlay file, and
// have the context reanalyze the file // have the context reanalyze the file.
if (options.overlay != CompletionMetricsOptions.OVERLAY_NONE) { if (options.overlay != OverlayMode.none) {
var overlayContents = CompletionMetricsComputer.getOverlayContents( final overlayContents = CompletionMetricsComputer.getOverlayContent(
resolvedUnitResult.content, resolvedUnitResult.content,
expectedCompletion, expectedCompletion,
options.overlay, options.overlay,
options.prefixLength); options.prefixLength,
);
provider.setOverlay(filePath, provider.setOverlay(
content: overlayContents, filePath,
modificationStamp: overlayModificationStamp++); content: overlayContents,
modificationStamp: overlayModificationStamp++,
);
context.changeFile(filePath); context.changeFile(filePath);
await context.applyPendingFileChanges(); await context.applyPendingFileChanges();
resolvedUnitResult = await context.currentSession resolvedUnitResult = await context.currentSession
@ -1396,10 +1399,10 @@ class CompletionQualityMetricsComputer extends CompletionMetricsComputer {
} }
@override @override
void removeOverlay(String filePath) { Future<void> removeOverlay(String filePath) async {
// If an overlay option is being used, remove the overlay applied // If an overlay option is being used, remove the overlay applied
// earlier. // earlier.
if (options.overlay != CompletionMetricsOptions.OVERLAY_NONE) { if (options.overlay != OverlayMode.none) {
provider.removeOverlay(filePath); provider.removeOverlay(filePath);
} }
} }

View file

@ -87,7 +87,7 @@ abstract class CompletionMetricsComputer {
documentationCache, documentationCache,
); );
removeOverlay(filePath); await removeOverlay(filePath);
} }
progress.tick(); progress.tick();
} }
@ -113,7 +113,7 @@ abstract class CompletionMetricsComputer {
); );
/// Removes the overlay which has been applied to [filePath]. /// Removes the overlay which has been applied to [filePath].
void removeOverlay(String filePath); Future<void> removeOverlay(String filePath);
/// Resolves all analyzed files within [context]. /// Resolves all analyzed files within [context].
Future<List<ResolvedUnitResult>> resolveAnalyzedFiles({ Future<List<ResolvedUnitResult>> resolveAnalyzedFiles({
@ -171,17 +171,16 @@ abstract class CompletionMetricsComputer {
return null; return null;
} }
/// Gets overlay contents for [contents], applying a change at /// Gets overlay content for [content], applying a change at
/// [expectedCompletion] with [prefixLength], according to [overlay], one of /// [expectedCompletion] with [prefixLength], according to [overlay], one of
/// the [CompletionMetricsOptions]. /// the [CompletionMetricsOptions].
static String getOverlayContents( static String getOverlayContent(
String contents, String content,
ExpectedCompletion expectedCompletion, ExpectedCompletion expectedCompletion,
// TODO(srawlins): Replace this with an enum. OverlayMode overlay,
String overlay,
int prefixLength, int prefixLength,
) { ) {
assert(contents.isNotEmpty); assert(content.isNotEmpty);
var offset = expectedCompletion.offset; var offset = expectedCompletion.offset;
final length = expectedCompletion.syntacticEntity.length; final length = expectedCompletion.syntacticEntity.length;
assert(offset >= 0); assert(offset >= 0);
@ -192,16 +191,12 @@ abstract class CompletionMetricsComputer {
// the given prefix length. // the given prefix length.
offset += prefixLength; offset += prefixLength;
} }
if (overlay == CompletionMetricsOptions.OVERLAY_REMOVE_TOKEN) { if (overlay == OverlayMode.removeToken) {
return contents.substring(0, offset) + contents.substring(tokenEndOffset); return content.substring(0, offset) + content.substring(tokenEndOffset);
} else if (overlay == } else if (overlay == OverlayMode.removeRestOfFile) {
CompletionMetricsOptions.OVERLAY_REMOVE_REST_OF_FILE) { return content.substring(0, offset);
return contents.substring(0, offset);
} else { } else {
final removeToken = CompletionMetricsOptions.OVERLAY_REMOVE_TOKEN; throw ArgumentError.value(overlay, 'overlay');
final removeRest = CompletionMetricsOptions.OVERLAY_REMOVE_REST_OF_FILE;
throw Exception('\'getOverlayContents\' called with option other than'
'$removeToken and $removeRest: $overlay');
} }
} }
} }
@ -211,18 +206,6 @@ class CompletionMetricsOptions {
/// An option to control whether and how overlays should be produced. /// An option to control whether and how overlays should be produced.
static const String OVERLAY = 'overlay'; static const String OVERLAY = 'overlay';
/// A mode indicating that no overlays should be produced.
/// TODO(srawlins): Replace this and the other two overlay values with enums.
static const String OVERLAY_NONE = 'none';
/// A mode indicating that everything from the completion offset to the end of
/// the file should be removed.
static const String OVERLAY_REMOVE_REST_OF_FILE = 'remove-rest-of-file';
/// A mode indicating that the token whose offset is the same as the
/// completion offset should be removed.
static const String OVERLAY_REMOVE_TOKEN = 'remove-token';
/// An option controlling how long of a prefix should be used. /// An option controlling how long of a prefix should be used.
/// ///
/// This affects the offset of the completion request, and how much content is /// This affects the offset of the completion request, and how much content is
@ -234,8 +217,7 @@ class CompletionMetricsOptions {
static const String PRINT_SLOWEST_RESULTS = 'print-slowest-results'; static const String PRINT_SLOWEST_RESULTS = 'print-slowest-results';
/// The overlay mode that should be used. /// The overlay mode that should be used.
/// TODO(srawlins): Replace this with an enum. final OverlayMode overlay;
final String overlay;
final int prefixLength; final int prefixLength;
@ -244,12 +226,34 @@ class CompletionMetricsOptions {
final bool printSlowestResults; final bool printSlowestResults;
CompletionMetricsOptions(ArgResults results) CompletionMetricsOptions(ArgResults results)
: overlay = results[OVERLAY] as String, : overlay = OverlayMode.parseFlag(results[OVERLAY] as String),
prefixLength = int.parse(results[PREFIX_LENGTH] as String), prefixLength = int.parse(results[PREFIX_LENGTH] as String),
printSlowestResults = results[PRINT_SLOWEST_RESULTS] as bool { printSlowestResults = results[PRINT_SLOWEST_RESULTS] as bool;
assert(overlay == OVERLAY_NONE || }
overlay == OVERLAY_REMOVE_TOKEN ||
overlay == OVERLAY_REMOVE_REST_OF_FILE); enum OverlayMode {
/// A mode indicating that no overlays should be produced.
none('none'),
/// A mode indicating that everything from the completion offset to the end of
/// the file should be removed.
removeRestOfFile('remove-rest-of-file'),
/// A mode indicating that the token whose offset is the same as the
/// completion offset should be removed.
removeToken('remove-token');
final String flag;
const OverlayMode(this.flag);
static OverlayMode parseFlag(String flag) {
for (final mode in values) {
if (flag == mode.flag) {
return mode;
}
}
throw ArgumentError.value(flag, 'overlay');
} }
} }

View file

@ -68,11 +68,11 @@ ArgParser _createArgParser() {
..addOption( ..addOption(
CompletionMetricsOptions.OVERLAY, CompletionMetricsOptions.OVERLAY,
allowed: [ allowed: [
CompletionMetricsOptions.OVERLAY_NONE, OverlayMode.none.flag,
CompletionMetricsOptions.OVERLAY_REMOVE_TOKEN, OverlayMode.removeRestOfFile.flag,
CompletionMetricsOptions.OVERLAY_REMOVE_REST_OF_FILE, OverlayMode.removeToken.flag,
], ],
defaultsTo: CompletionMetricsOptions.OVERLAY_NONE, defaultsTo: OverlayMode.none.flag,
help: 'Before attempting a completion at the location of each token, the ' help: 'Before attempting a completion at the location of each token, the '
'token can be removed, or the rest of the file can be removed to ' 'token can be removed, or the rest of the file can be removed to '
'test code completion with diverse methods. The default mode is to ' 'test code completion with diverse methods. The default mode is to '
@ -143,7 +143,21 @@ class CompletionClientMetricsComputer extends CompletionMetricsComputer {
String filePath, String filePath,
ExpectedCompletion expectedCompletion, ExpectedCompletion expectedCompletion,
) async { ) async {
// TODO(srawlins): Support overlays. if (options.overlay != OverlayMode.none) {
final overlayContent = CompletionMetricsComputer.getOverlayContent(
resolvedUnitResult.content,
expectedCompletion,
options.overlay,
options.prefixLength,
);
provider.setOverlay(
filePath,
content: overlayContent,
modificationStamp: overlayModificationStamp++,
);
await client.addOverlay(filePath, overlayContent);
}
} }
@override @override
@ -193,8 +207,10 @@ class CompletionClientMetricsComputer extends CompletionMetricsComputer {
} }
@override @override
void removeOverlay(String filePath) { Future<void> removeOverlay(String filePath) async {
// TODO(srawlins): Support overlays. if (options.overlay != OverlayMode.none) {
await client.removeOverlay(filePath);
}
} }
@override @override
@ -275,19 +291,55 @@ class _AnalysisServerClient {
Future<int> get onExit => _process!.exitCode; Future<int> get onExit => _process!.exitCode;
Future<AnalysisUpdateContentResult> addOverlay(
String file, String content) async {
final response = await _sendCommand(
'analysis.updateContent',
params: {
'files': {
file: {'type': 'add', 'content': content},
}
},
);
final result = response['result'] as Map<String, dynamic>;
return AnalysisUpdateContentResult.fromJson(
ResponseDecoder(null),
'result',
result,
);
}
Future<bool> dispose() async { Future<bool> dispose() async {
return _process?.kill() ?? true; return _process?.kill() ?? true;
} }
Future<AnalysisUpdateContentResult> removeOverlay(String file) async {
final response = await _sendCommand(
'analysis.updateContent',
params: {
'files': {
file: {'type': 'remove'},
}
},
);
final result = response['result'] as Map<String, dynamic>;
return AnalysisUpdateContentResult.fromJson(
ResponseDecoder(null),
'result',
result,
);
}
/// Requests a completion for [file] at [offset]. /// Requests a completion for [file] at [offset].
Future<_SuggestionsData> requestCompletion( Future<_SuggestionsData> requestCompletion(
String file, int offset, int maxResults) async { String file, int offset, int maxResults) async {
final response = await _sendCommand('completion.getSuggestions2', final response = await _sendCommand('completion.getSuggestions2', params: {
params: <String, dynamic>{ 'file': file,
'file': file, 'offset': offset,
'offset': offset, 'maxResults': maxResults,
'maxResults': maxResults, });
});
final result = response['result'] as Map<String, dynamic>; final result = response['result'] as Map<String, dynamic>;
final metadata = _requestMetadata[response['id']]!; final metadata = _requestMetadata[response['id']]!;
@ -440,10 +492,7 @@ class _AnalysisServerClient {
.remove(id) .remove(id)
?.completeError(_RequestError.parse(error)); ?.completeError(_RequestError.parse(error));
} else { } else {
_requestCompleters.remove(id)?.complete( _requestCompleters.remove(id)?.complete(response);
//response['result'] as Map<String, dynamic>? ??
// <String, dynamic>{});
response);
} }
} }
} }