Bump DAS to use Dart SDK 3.9.0
Change-Id: I04bc285d822a657adb5573c6de3eb38655ab0fcd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/448232 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
committed by
Commit Queue
parent
cb23ff22a4
commit
33f664940a
@@ -139,18 +139,17 @@ class CmdLineSeveralProjectsBenchmark extends AbstractCmdLineBenchmark {
|
||||
String get workingDir => packageRoot;
|
||||
|
||||
@override
|
||||
List<String> analyzeWhat(bool quick) =>
|
||||
quick
|
||||
? ['meta']
|
||||
: [
|
||||
'analysis_server',
|
||||
'analysis_server_client',
|
||||
'analyzer',
|
||||
'analyzer_cli',
|
||||
'analyzer_plugin',
|
||||
'analyzer_utilities',
|
||||
'_fe_analyzer_shared',
|
||||
];
|
||||
List<String> analyzeWhat(bool quick) => quick
|
||||
? ['meta']
|
||||
: [
|
||||
'analysis_server',
|
||||
'analysis_server_client',
|
||||
'analyzer',
|
||||
'analyzer_cli',
|
||||
'analyzer_plugin',
|
||||
'analyzer_utilities',
|
||||
'_fe_analyzer_shared',
|
||||
];
|
||||
}
|
||||
|
||||
class CmdLineSmallFileBenchmark extends AbstractCmdLineBenchmark {
|
||||
|
||||
@@ -34,8 +34,8 @@ class Bar {
|
||||
await analysisFinished;
|
||||
|
||||
var result =
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
await sendAnalysisGetReachableSources(pathname);
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
await sendAnalysisGetReachableSources(pathname);
|
||||
var sources = result.sources;
|
||||
var keys = sources.keys.toList();
|
||||
var url = File(pathname).uri.toString();
|
||||
|
||||
@@ -52,10 +52,9 @@ void f() {
|
||||
}
|
||||
|
||||
void check(String elementName, Iterable<String> expectedOccurrences) {
|
||||
var expectedOffsets =
|
||||
expectedOccurrences
|
||||
.map((String substring) => text.indexOf(substring))
|
||||
.toSet();
|
||||
var expectedOffsets = expectedOccurrences
|
||||
.map((String substring) => text.indexOf(substring))
|
||||
.toSet();
|
||||
var foundOffsets = findOffsets(elementName);
|
||||
expect(foundOffsets, equals(expectedOffsets));
|
||||
}
|
||||
@@ -102,10 +101,9 @@ void f() {
|
||||
}
|
||||
|
||||
void check(String elementName, Iterable<String> expectedOccurrences) {
|
||||
var expectedOffsets =
|
||||
expectedOccurrences
|
||||
.map((String substring) => text.indexOf(substring))
|
||||
.toSet();
|
||||
var expectedOffsets = expectedOccurrences
|
||||
.map((String substring) => text.indexOf(substring))
|
||||
.toSet();
|
||||
var foundOffsets = findOffsets(elementName);
|
||||
expect(foundOffsets, equals(expectedOffsets));
|
||||
}
|
||||
@@ -156,10 +154,9 @@ void f() {
|
||||
}
|
||||
|
||||
void check(String elementName, Iterable<String> expectedOccurrences) {
|
||||
var expectedOffsets =
|
||||
expectedOccurrences
|
||||
.map((String substring) => text.indexOf(substring))
|
||||
.toSet();
|
||||
var expectedOffsets = expectedOccurrences
|
||||
.map((String substring) => text.indexOf(substring))
|
||||
.toSet();
|
||||
var foundOffsets = findOffsets(elementName);
|
||||
expect(foundOffsets, equals(expectedOffsets));
|
||||
}
|
||||
@@ -212,10 +209,9 @@ void f() {
|
||||
}
|
||||
|
||||
void check(String elementName, Iterable<String> expectedOccurrences) {
|
||||
var expectedOffsets =
|
||||
expectedOccurrences
|
||||
.map((String substring) => text.indexOf(substring))
|
||||
.toSet();
|
||||
var expectedOffsets = expectedOccurrences
|
||||
.map((String substring) => text.indexOf(substring))
|
||||
.toSet();
|
||||
var foundOffsets = findOffsets(elementName);
|
||||
expect(foundOffsets, equals(expectedOffsets));
|
||||
}
|
||||
|
||||
@@ -37,11 +37,10 @@ void f() {
|
||||
// order in which they appear in the file. If these edits are applied in
|
||||
// the wrong order, some of the quotation marks will be in the wrong
|
||||
// places, and there will still be errors.
|
||||
var edits =
|
||||
'"'
|
||||
.allMatches(goodText)
|
||||
.map((Match match) => SourceEdit(match.start, 0, '"'))
|
||||
.toList();
|
||||
var edits = '"'
|
||||
.allMatches(goodText)
|
||||
.map((Match match) => SourceEdit(match.start, 0, '"'))
|
||||
.toList();
|
||||
await sendAnalysisUpdateContent({pathname: ChangeContentOverlay(edits)});
|
||||
await analysisFinished;
|
||||
// There should be no errors now, assuming that quotation marks have been
|
||||
|
||||
@@ -23,35 +23,29 @@ void main() {
|
||||
var lines = coverageFile.readAsLinesSync();
|
||||
|
||||
// ## server domain
|
||||
var coveredDomains =
|
||||
lines
|
||||
.where((line) => line.startsWith('## ') && line.endsWith(' domain'))
|
||||
.map(
|
||||
(line) =>
|
||||
line
|
||||
.substring('##'.length, line.length - 'domain'.length)
|
||||
.trim(),
|
||||
)
|
||||
.toSet();
|
||||
var coveredDomains = lines
|
||||
.where((line) => line.startsWith('## ') && line.endsWith(' domain'))
|
||||
.map(
|
||||
(line) =>
|
||||
line.substring('##'.length, line.length - 'domain'.length).trim(),
|
||||
)
|
||||
.toSet();
|
||||
|
||||
// Remove any ' (test failed)' suffixes.
|
||||
lines =
|
||||
lines.map((String line) {
|
||||
var index = line.indexOf('(');
|
||||
return index != -1 ? line.substring(0, index).trim() : line;
|
||||
}).toList();
|
||||
lines = lines.map((String line) {
|
||||
var index = line.indexOf('(');
|
||||
return index != -1 ? line.substring(0, index).trim() : line;
|
||||
}).toList();
|
||||
|
||||
// - [ ] server.getVersion
|
||||
var allMembers =
|
||||
lines
|
||||
.where((line) => line.startsWith('- '))
|
||||
.map((line) => line.substring('- [ ]'.length).trim())
|
||||
.toSet();
|
||||
var coveredMembers =
|
||||
lines
|
||||
.where((line) => line.startsWith('- [x]'))
|
||||
.map((line) => line.substring('- [x]'.length).trim())
|
||||
.toSet();
|
||||
var allMembers = lines
|
||||
.where((line) => line.startsWith('- '))
|
||||
.map((line) => line.substring('- [ ]'.length).trim())
|
||||
.toSet();
|
||||
var coveredMembers = lines
|
||||
.where((line) => line.startsWith('- [x]'))
|
||||
.map((line) => line.substring('- [x]'.length).trim())
|
||||
.toSet();
|
||||
|
||||
// generate domain tests
|
||||
for (var domain in api.domains) {
|
||||
@@ -85,10 +79,9 @@ void main() {
|
||||
expect(
|
||||
fileExists,
|
||||
isMarkedAsCovered,
|
||||
reason:
|
||||
isMarkedAsCovered
|
||||
? '$testName marked as covered but has no test at $testPath'
|
||||
: '$testName marked as not covered has test at $testPath',
|
||||
reason: isMarkedAsCovered
|
||||
? '$testName marked as covered but has no test at $testPath'
|
||||
: '$testName marked as not covered has test at $testPath',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -139,10 +139,9 @@ abstract class AbstractLspAnalysisServerIntegrationTest
|
||||
@mustCallSuper
|
||||
Future<void> setUp() async {
|
||||
// Set up temporary folder for the test.
|
||||
projectFolderPath =
|
||||
Directory.systemTemp
|
||||
.createTempSync('analysisServer_test_integration_lspProject')
|
||||
.resolveSymbolicLinksSync();
|
||||
projectFolderPath = Directory.systemTemp
|
||||
.createTempSync('analysisServer_test_integration_lspProject')
|
||||
.resolveSymbolicLinksSync();
|
||||
_temporaryFolders.add(projectFolderPath);
|
||||
newFolder(projectFolderPath);
|
||||
newFolder(path.join(projectFolderPath, 'lib'));
|
||||
|
||||
@@ -56,12 +56,11 @@ class BlazeChangesTest extends AbstractAnalysisServerIntegrationTest {
|
||||
await super.setUp();
|
||||
oldSourceDirectory = sourceDirectory;
|
||||
|
||||
tmpPath =
|
||||
Directory(
|
||||
Directory.systemTemp
|
||||
.createTempSync('analysisServer_test_integration_blazeProject')
|
||||
.resolveSymbolicLinksSync(),
|
||||
).path;
|
||||
tmpPath = Directory(
|
||||
Directory.systemTemp
|
||||
.createTempSync('analysisServer_test_integration_blazeProject')
|
||||
.resolveSymbolicLinksSync(),
|
||||
).path;
|
||||
_temporaryFolders.add(tmpPath);
|
||||
workspacePath = inTmpDir('workspace_root');
|
||||
writeFile(inWorkspace(file_paths.blazeWorkspaceMarker), '');
|
||||
|
||||
@@ -285,8 +285,8 @@ abstract class IntegrationTest {
|
||||
///
|
||||
/// The stack trace associated with the generation of the error, used for
|
||||
/// debugging the server.
|
||||
late final Stream<ServerErrorParams> onServerError =
|
||||
_onServerError.stream.asBroadcastStream();
|
||||
late final Stream<ServerErrorParams> onServerError = _onServerError.stream
|
||||
.asBroadcastStream();
|
||||
|
||||
/// Stream controller for [onServerError].
|
||||
final _onServerError = StreamController<ServerErrorParams>(sync: true);
|
||||
@@ -314,8 +314,8 @@ abstract class IntegrationTest {
|
||||
/// Parameters
|
||||
///
|
||||
/// entry: ServerLogEntry
|
||||
late final Stream<ServerLogParams> onServerLog =
|
||||
_onServerLog.stream.asBroadcastStream();
|
||||
late final Stream<ServerLogParams> onServerLog = _onServerLog.stream
|
||||
.asBroadcastStream();
|
||||
|
||||
/// Stream controller for [onServerLog].
|
||||
final _onServerLog = StreamController<ServerLogParams>(sync: true);
|
||||
@@ -341,8 +341,8 @@ abstract class IntegrationTest {
|
||||
///
|
||||
/// Note: this status type is deprecated, and is no longer sent by the
|
||||
/// server.
|
||||
late final Stream<ServerStatusParams> onServerStatus =
|
||||
_onServerStatus.stream.asBroadcastStream();
|
||||
late final Stream<ServerStatusParams> onServerStatus = _onServerStatus.stream
|
||||
.asBroadcastStream();
|
||||
|
||||
/// Stream controller for [onServerStatus].
|
||||
final _onServerStatus = StreamController<ServerStatusParams>(sync: true);
|
||||
@@ -973,8 +973,9 @@ abstract class IntegrationTest {
|
||||
/// errors: List<AnalysisError>
|
||||
///
|
||||
/// The errors contained in the file.
|
||||
late final Stream<AnalysisErrorsParams> onAnalysisErrors =
|
||||
_onAnalysisErrors.stream.asBroadcastStream();
|
||||
late final Stream<AnalysisErrorsParams> onAnalysisErrors = _onAnalysisErrors
|
||||
.stream
|
||||
.asBroadcastStream();
|
||||
|
||||
/// Stream controller for [onAnalysisErrors].
|
||||
final _onAnalysisErrors = StreamController<AnalysisErrorsParams>(sync: true);
|
||||
@@ -1436,8 +1437,8 @@ abstract class IntegrationTest {
|
||||
///
|
||||
/// The existing imports in the library.
|
||||
late final Stream<CompletionExistingImportsParams>
|
||||
onCompletionExistingImports =
|
||||
_onCompletionExistingImports.stream.asBroadcastStream();
|
||||
onCompletionExistingImports = _onCompletionExistingImports.stream
|
||||
.asBroadcastStream();
|
||||
|
||||
/// Stream controller for [onCompletionExistingImports].
|
||||
final _onCompletionExistingImports =
|
||||
@@ -1723,8 +1724,9 @@ abstract class IntegrationTest {
|
||||
///
|
||||
/// True if this is that last set of results that will be returned for the
|
||||
/// indicated search.
|
||||
late final Stream<SearchResultsParams> onSearchResults =
|
||||
_onSearchResults.stream.asBroadcastStream();
|
||||
late final Stream<SearchResultsParams> onSearchResults = _onSearchResults
|
||||
.stream
|
||||
.asBroadcastStream();
|
||||
|
||||
/// Stream controller for [onSearchResults].
|
||||
final _onSearchResults = StreamController<SearchResultsParams>(sync: true);
|
||||
@@ -3014,8 +3016,9 @@ abstract class IntegrationTest {
|
||||
/// outline: FlutterOutline
|
||||
///
|
||||
/// The outline associated with the file.
|
||||
late final Stream<FlutterOutlineParams> onFlutterOutline =
|
||||
_onFlutterOutline.stream.asBroadcastStream();
|
||||
late final Stream<FlutterOutlineParams> onFlutterOutline = _onFlutterOutline
|
||||
.stream
|
||||
.asBroadcastStream();
|
||||
|
||||
/// Stream controller for [onFlutterOutline].
|
||||
final _onFlutterOutline = StreamController<FlutterOutlineParams>(sync: true);
|
||||
|
||||
@@ -604,11 +604,9 @@ class Server {
|
||||
]) {
|
||||
// Provide a default implementation of the reverse request processor that
|
||||
// just throws because there are many tests that don't use reverse-requests.
|
||||
reverseRequestProcessor ??=
|
||||
(_) =>
|
||||
throw UnimplementedError(
|
||||
"A reverse request was received but the test did not provide 'reverseRequestProcessor'",
|
||||
);
|
||||
reverseRequestProcessor ??= (_) => throw UnimplementedError(
|
||||
"A reverse request was received but the test did not provide 'reverseRequestProcessor'",
|
||||
);
|
||||
|
||||
_process.stdout.transform(utf8.decoder).transform(LineSplitter()).listen((
|
||||
String line,
|
||||
@@ -620,18 +618,16 @@ class Server {
|
||||
// {"event":"server.connected","params":{...}}The Dart VM service is listening on ...
|
||||
const dartVMServiceMessage = 'The Dart VM service is listening on ';
|
||||
if (trimmedLine.contains(dartVMServiceMessage)) {
|
||||
trimmedLine =
|
||||
trimmedLine
|
||||
.substring(0, trimmedLine.indexOf(dartVMServiceMessage))
|
||||
.trim();
|
||||
trimmedLine = trimmedLine
|
||||
.substring(0, trimmedLine.indexOf(dartVMServiceMessage))
|
||||
.trim();
|
||||
}
|
||||
const devtoolsMessage =
|
||||
'The Dart DevTools debugger and profiler is available at:';
|
||||
if (trimmedLine.contains(devtoolsMessage)) {
|
||||
trimmedLine =
|
||||
trimmedLine
|
||||
.substring(0, trimmedLine.indexOf(devtoolsMessage))
|
||||
.trim();
|
||||
trimmedLine = trimmedLine
|
||||
.substring(0, trimmedLine.indexOf(devtoolsMessage))
|
||||
.trim();
|
||||
}
|
||||
if (trimmedLine.isEmpty) {
|
||||
return;
|
||||
@@ -998,10 +994,9 @@ abstract class _RecursiveMatcher extends Matcher {
|
||||
mismatchDescription = mismatchDescription
|
||||
.add(' (should be ')
|
||||
.addDescriptionOf(matcher);
|
||||
var subDescription =
|
||||
matcher
|
||||
.describeMismatch(item, StringDescription(), subState, false)
|
||||
.toString();
|
||||
var subDescription = matcher
|
||||
.describeMismatch(item, StringDescription(), subState, false)
|
||||
.toString();
|
||||
if (subDescription.isNotEmpty) {
|
||||
mismatchDescription = mismatchDescription
|
||||
.add('; ')
|
||||
@@ -1062,10 +1057,9 @@ abstract class _RecursiveMatcher extends Matcher {
|
||||
void populateMismatches(Object? item, List<MismatchDescriber> mismatches);
|
||||
|
||||
/// Create a [MismatchDescriber] describing a mismatch with a simple string.
|
||||
MismatchDescriber simpleDescription(String description) => (
|
||||
Description mismatchDescription,
|
||||
) {
|
||||
mismatchDescription.add(description);
|
||||
return mismatchDescription;
|
||||
};
|
||||
MismatchDescriber simpleDescription(String description) =>
|
||||
(Description mismatchDescription) {
|
||||
mismatchDescription.add(description);
|
||||
return mismatchDescription;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -257,17 +257,15 @@ int _preferRequiredParams(
|
||||
engine.FormalParameterElement e1,
|
||||
engine.FormalParameterElement e2,
|
||||
) {
|
||||
var rank1 =
|
||||
(e1.isRequiredNamed || e1.metadata.hasRequired)
|
||||
? 0
|
||||
: !e1.isNamed
|
||||
? -1
|
||||
: 1;
|
||||
var rank2 =
|
||||
(e2.isRequiredNamed || e2.metadata.hasRequired)
|
||||
? 0
|
||||
: !e2.isNamed
|
||||
? -1
|
||||
: 1;
|
||||
var rank1 = (e1.isRequiredNamed || e1.metadata.hasRequired)
|
||||
? 0
|
||||
: !e1.isNamed
|
||||
? -1
|
||||
: 1;
|
||||
var rank2 = (e2.isRequiredNamed || e2.metadata.hasRequired)
|
||||
? 0
|
||||
: !e2.isNamed
|
||||
? -1
|
||||
: 1;
|
||||
return rank1 - rank2;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -319,14 +319,13 @@ abstract class AnalysisServer {
|
||||
}
|
||||
var disablePubCommandVariable =
|
||||
Platform.environment[PubCommand.disablePubCommandEnvironmentKey];
|
||||
var pubCommand =
|
||||
processRunner != null && disablePubCommandVariable == null
|
||||
? PubCommand(
|
||||
instrumentationService,
|
||||
resourceProvider.pathContext,
|
||||
processRunner,
|
||||
)
|
||||
: null;
|
||||
var pubCommand = processRunner != null && disablePubCommandVariable == null
|
||||
? PubCommand(
|
||||
instrumentationService,
|
||||
resourceProvider.pathContext,
|
||||
processRunner,
|
||||
)
|
||||
: null;
|
||||
|
||||
pubPackageService = PubPackageService(
|
||||
instrumentationService,
|
||||
@@ -336,14 +335,13 @@ abstract class AnalysisServer {
|
||||
);
|
||||
performance = performanceDuringStartup;
|
||||
|
||||
this.pluginManager =
|
||||
pluginManager ??= PluginManager(
|
||||
resourceProvider,
|
||||
resourceProvider.byteStorePath,
|
||||
sdkManager.defaultSdkDirectory,
|
||||
notificationManager,
|
||||
instrumentationService,
|
||||
);
|
||||
this.pluginManager = pluginManager ??= PluginManager(
|
||||
resourceProvider,
|
||||
resourceProvider.byteStorePath,
|
||||
sdkManager.defaultSdkDirectory,
|
||||
notificationManager,
|
||||
instrumentationService,
|
||||
);
|
||||
var pluginWatcher = PluginWatcher(resourceProvider, pluginManager);
|
||||
|
||||
var logName = options.newAnalysisDriverLog;
|
||||
@@ -601,10 +599,9 @@ abstract class AnalysisServer {
|
||||
if (resourceProvider is PhysicalResourceProvider) {
|
||||
var stateLocation = resourceProvider.getStateLocation('.analysis-driver');
|
||||
if (stateLocation != null) {
|
||||
var timingByteStore =
|
||||
_timingByteStore = TimingByteStore(
|
||||
EvictingFileByteStore(stateLocation.path, G),
|
||||
);
|
||||
var timingByteStore = _timingByteStore = TimingByteStore(
|
||||
EvictingFileByteStore(stateLocation.path, G),
|
||||
);
|
||||
return MemoryCachingByteStore(timingByteStore, memoryCacheSize);
|
||||
}
|
||||
}
|
||||
@@ -840,10 +837,9 @@ abstract class AnalysisServer {
|
||||
// This is FutureOr<> because for the legacy server it's never a future, so
|
||||
// we can skip the await.
|
||||
var initializedLspHandler = lspInitialized;
|
||||
var handler =
|
||||
initializedLspHandler is lsp.InitializedStateMessageHandler
|
||||
? initializedLspHandler
|
||||
: await initializedLspHandler;
|
||||
var handler = initializedLspHandler is lsp.InitializedStateMessageHandler
|
||||
? initializedLspHandler
|
||||
: await initializedLspHandler;
|
||||
|
||||
return handler.handleMessage(
|
||||
message,
|
||||
|
||||
@@ -516,10 +516,10 @@ class AnalyticsManager {
|
||||
transitiveFileUniqueCount: contextStructure.transitiveFileUniqueCount,
|
||||
transitiveFileUniqueLineCount:
|
||||
contextStructure.transitiveFileUniqueLineCount,
|
||||
libraryCycleLibraryCounts:
|
||||
contextStructure.libraryCycleLibraryCounts.toAnalyticsString(),
|
||||
libraryCycleLineCounts:
|
||||
contextStructure.libraryCycleLineCounts.toAnalyticsString(),
|
||||
libraryCycleLibraryCounts: contextStructure.libraryCycleLibraryCounts
|
||||
.toAnalyticsString(),
|
||||
libraryCycleLineCounts: contextStructure.libraryCycleLineCounts
|
||||
.toAnalyticsString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -598,16 +598,16 @@ class AnalyticsManager {
|
||||
method: data.method,
|
||||
duration: data.responseTimes.toAnalyticsString(),
|
||||
added: data.additionalPercentiles[addedKey]?.toAnalyticsString(),
|
||||
excluded:
|
||||
data.additionalPercentiles[excludedKey]?.toAnalyticsString(),
|
||||
excluded: data.additionalPercentiles[excludedKey]
|
||||
?.toAnalyticsString(),
|
||||
files: data.additionalPercentiles[filesKey]?.toAnalyticsString(),
|
||||
included:
|
||||
data.additionalPercentiles[includedKey]?.toAnalyticsString(),
|
||||
openWorkspacePaths:
|
||||
data.additionalPercentiles[openWorkspacePathsKey]
|
||||
?.toAnalyticsString(),
|
||||
removed:
|
||||
data.additionalPercentiles[removedKey]?.toAnalyticsString(),
|
||||
included: data.additionalPercentiles[includedKey]
|
||||
?.toAnalyticsString(),
|
||||
openWorkspacePaths: data
|
||||
.additionalPercentiles[openWorkspacePathsKey]
|
||||
?.toAnalyticsString(),
|
||||
removed: data.additionalPercentiles[removedKey]
|
||||
?.toAnalyticsString(),
|
||||
),
|
||||
);
|
||||
var commandMap = data.additionalEnumCounts[commandEnumKey];
|
||||
|
||||
@@ -48,9 +48,8 @@ class PercentileCalculator {
|
||||
return 0;
|
||||
}
|
||||
var targetIndex = _valueCount * percentile / 100;
|
||||
var entries =
|
||||
_counts.entries.toList()
|
||||
..sort((first, second) => first.key.compareTo(second.key));
|
||||
var entries = _counts.entries.toList()
|
||||
..sort((first, second) => first.key.compareTo(second.key));
|
||||
// The number of values represented by walking the counts.
|
||||
var accumulation = 0;
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
|
||||
@@ -25,26 +25,23 @@ class ByteStreamClientChannel implements ClientCommunicationChannel {
|
||||
Stream<Notification> notificationStream;
|
||||
|
||||
factory ByteStreamClientChannel(Stream<List<int>> input, IOSink output) {
|
||||
var jsonStream =
|
||||
input
|
||||
.transform(const Utf8Decoder())
|
||||
.transform(LineSplitter())
|
||||
.transform(JsonStreamDecoder())
|
||||
.where((json) => json is Map<String, Object?>)
|
||||
.cast<Map<String, Object?>>()
|
||||
.asBroadcastStream();
|
||||
var responseStream =
|
||||
jsonStream
|
||||
.where((json) => json[Notification.EVENT] == null)
|
||||
.transform(ResponseConverter())
|
||||
.where((response) => response != null)
|
||||
.cast<Response>()
|
||||
.asBroadcastStream();
|
||||
var notificationStream =
|
||||
jsonStream
|
||||
.where((json) => json[Notification.EVENT] != null)
|
||||
.transform(NotificationConverter())
|
||||
.asBroadcastStream();
|
||||
var jsonStream = input
|
||||
.transform(const Utf8Decoder())
|
||||
.transform(LineSplitter())
|
||||
.transform(JsonStreamDecoder())
|
||||
.where((json) => json is Map<String, Object?>)
|
||||
.cast<Map<String, Object?>>()
|
||||
.asBroadcastStream();
|
||||
var responseStream = jsonStream
|
||||
.where((json) => json[Notification.EVENT] == null)
|
||||
.transform(ResponseConverter())
|
||||
.where((response) => response != null)
|
||||
.cast<Response>()
|
||||
.asBroadcastStream();
|
||||
var notificationStream = jsonStream
|
||||
.where((json) => json[Notification.EVENT] != null)
|
||||
.transform(NotificationConverter())
|
||||
.asBroadcastStream();
|
||||
return ByteStreamClientChannel._(
|
||||
output,
|
||||
responseStream,
|
||||
|
||||
@@ -170,12 +170,11 @@ class CiderCompletionComputer {
|
||||
required OperationPerformanceImpl performance,
|
||||
}) {
|
||||
var suggestionBuilders = <CompletionSuggestionBuilder>[];
|
||||
var importedLibraries =
|
||||
target.withEnclosing2
|
||||
.expand((fragment) => fragment.libraryImports)
|
||||
.map((import) => import.importedLibrary)
|
||||
.nonNulls
|
||||
.toSet();
|
||||
var importedLibraries = target.withEnclosing2
|
||||
.expand((fragment) => fragment.libraryImports)
|
||||
.map((import) => import.importedLibrary)
|
||||
.nonNulls
|
||||
.toSet();
|
||||
for (var importedLibrary in importedLibraries) {
|
||||
var importedSuggestions = _importedLibrarySuggestions(
|
||||
element: importedLibrary,
|
||||
|
||||
@@ -47,10 +47,9 @@ class CiderDocumentSymbolsComputer {
|
||||
) {
|
||||
var codeRange = toRange(lineInfo, outline.codeOffset, outline.codeLength);
|
||||
var nameLocation = outline.element.location;
|
||||
var nameRange =
|
||||
nameLocation != null
|
||||
? toRange(lineInfo, nameLocation.offset, nameLocation.length)
|
||||
: null;
|
||||
var nameRange = nameLocation != null
|
||||
? toRange(lineInfo, nameLocation.offset, nameLocation.length)
|
||||
: null;
|
||||
return DocumentSymbol(
|
||||
name: toElementName(outline.element),
|
||||
detail: outline.element.parameters,
|
||||
@@ -58,12 +57,9 @@ class CiderDocumentSymbolsComputer {
|
||||
deprecated: outline.element.isDeprecated,
|
||||
range: codeRange,
|
||||
selectionRange: nameRange ?? codeRange,
|
||||
children:
|
||||
outline.children
|
||||
?.map(
|
||||
(child) => _asDocumentSymbol(supportedKinds, lineInfo, child),
|
||||
)
|
||||
.toList(),
|
||||
children: outline.children
|
||||
?.map((child) => _asDocumentSymbol(supportedKinds, lineInfo, child))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,10 +37,9 @@ class LibraryElementSuggestionBuilder
|
||||
String? prefix,
|
||||
]) {
|
||||
var opType = request.opType;
|
||||
var kind =
|
||||
request.target.isFunctionalArgument()
|
||||
? CompletionSuggestionKind.IDENTIFIER
|
||||
: opType.suggestKind;
|
||||
var kind = request.target.isFunctionalArgument()
|
||||
? CompletionSuggestionKind.IDENTIFIER
|
||||
: opType.suggestKind;
|
||||
return LibraryElementSuggestionBuilder._(
|
||||
request,
|
||||
builder,
|
||||
|
||||
@@ -316,23 +316,22 @@ class CheckNameResponse {
|
||||
} catch (_) {
|
||||
match.add(CiderSearchMatch(sourcePath, [searchInfo]));
|
||||
}
|
||||
var replacements =
|
||||
match
|
||||
.map(
|
||||
(m) => CiderReplaceMatch(
|
||||
m.path,
|
||||
m.references
|
||||
.map(
|
||||
(p) => ReplaceInfo(
|
||||
stateName,
|
||||
p.startPosition,
|
||||
stateClass.name!.length,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
var replacements = match
|
||||
.map(
|
||||
(m) => CiderReplaceMatch(
|
||||
m.path,
|
||||
m.references
|
||||
.map(
|
||||
(p) => ReplaceInfo(
|
||||
stateName,
|
||||
p.startPosition,
|
||||
stateClass.name!.length,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
return FlutterWidgetRename(stateName, match, replacements);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,8 +110,9 @@ class CallHierarchyItem {
|
||||
var enclosingElement =
|
||||
element.enclosingElement ??
|
||||
element.firstFragment.enclosingFragment?.element;
|
||||
var container =
|
||||
enclosingElement != null ? _getContainer(enclosingElement) : null;
|
||||
var container = enclosingElement != null
|
||||
? _getContainer(enclosingElement)
|
||||
: null;
|
||||
containerName = container != null ? _getDisplayName(container) : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,12 +106,11 @@ class ColorComputer {
|
||||
double? alpha, red, green, blue;
|
||||
for (var arg in args.whereType<NamedExpression>()) {
|
||||
var expression = arg.expression;
|
||||
var value =
|
||||
expression is DoubleLiteral
|
||||
? expression.value
|
||||
: expression is IntegerLiteral
|
||||
? expression.value?.toDouble()
|
||||
: null;
|
||||
var value = expression is DoubleLiteral
|
||||
? expression.value
|
||||
: expression is IntegerLiteral
|
||||
? expression.value?.toDouble()
|
||||
: null;
|
||||
switch (arg.name.label.name) {
|
||||
case 'alpha':
|
||||
alpha = value;
|
||||
@@ -154,12 +153,11 @@ class ColorComputer {
|
||||
var red = arg0 is IntegerLiteral ? arg0.value : null;
|
||||
var green = arg1 is IntegerLiteral ? arg1.value : null;
|
||||
var blue = arg2 is IntegerLiteral ? arg2.value : null;
|
||||
var opacity =
|
||||
arg3 is IntegerLiteral
|
||||
? arg3.value
|
||||
: arg3 is DoubleLiteral
|
||||
? arg3.value
|
||||
: null;
|
||||
var opacity = arg3 is IntegerLiteral
|
||||
? arg3.value
|
||||
: arg3 is DoubleLiteral
|
||||
? arg3.value
|
||||
: null;
|
||||
var alpha = opacity != null ? (opacity * 255).toInt() : null;
|
||||
|
||||
return alpha != null && red != null && green != null && blue != null
|
||||
@@ -175,9 +173,9 @@ class ColorComputer {
|
||||
String? name,
|
||||
List<Expression> args,
|
||||
) =>
|
||||
// MaterialAccentColor is a subclass of SwatchColor and has the same
|
||||
// constructor.
|
||||
_getFlutterSwatchColor(name, args);
|
||||
// MaterialAccentColor is a subclass of SwatchColor and has the same
|
||||
// constructor.
|
||||
_getFlutterSwatchColor(name, args);
|
||||
|
||||
/// Extracts the color information from Flutter ColorSwatch constructor args.
|
||||
ColorInformation? _getFlutterSwatchColor(
|
||||
@@ -270,11 +268,11 @@ class ColorComputer {
|
||||
}) {
|
||||
return alpha != null && red != null && green != null && blue != null
|
||||
? ColorInformation(
|
||||
(alpha * 255.0).round() & 0xff,
|
||||
(red * 255.0).round() & 0xff,
|
||||
(green * 255.0).round() & 0xff,
|
||||
(blue * 255.0).round() & 0xff,
|
||||
)
|
||||
(alpha * 255.0).round() & 0xff,
|
||||
(red * 255.0).round() & 0xff,
|
||||
(green * 255.0).round() & 0xff,
|
||||
(blue * 255.0).round() & 0xff,
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
@@ -283,11 +281,11 @@ class ColorComputer {
|
||||
static ColorInformation? getColorForInt(int? value) {
|
||||
return value != null
|
||||
? ColorInformation(
|
||||
(value >> 24) & 0xff,
|
||||
(value >> 16) & 0xff,
|
||||
(value >> 8) & 0xff,
|
||||
value & 0xff,
|
||||
)
|
||||
(value >> 24) & 0xff,
|
||||
(value >> 16) & 0xff,
|
||||
(value >> 8) & 0xff,
|
||||
value & 0xff,
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,13 +127,12 @@ class DartUnitFoldingComputer {
|
||||
_hasBlankLineBetween(end, _unit.beginToken.offset));
|
||||
}
|
||||
|
||||
var kind =
|
||||
isFileHeader
|
||||
? FoldingKind.FILE_HEADER
|
||||
: (commentToken.lexeme.startsWith('///') ||
|
||||
commentToken.lexeme.startsWith('/**'))
|
||||
? FoldingKind.DOCUMENTATION_COMMENT
|
||||
: FoldingKind.COMMENT;
|
||||
var kind = isFileHeader
|
||||
? FoldingKind.FILE_HEADER
|
||||
: (commentToken.lexeme.startsWith('///') ||
|
||||
commentToken.lexeme.startsWith('/**'))
|
||||
? FoldingKind.DOCUMENTATION_COMMENT
|
||||
: FoldingKind.COMMENT;
|
||||
|
||||
_addRegion(offset, end, kind);
|
||||
|
||||
|
||||
@@ -215,10 +215,9 @@ class DartUnitHighlightsComputer {
|
||||
type,
|
||||
semanticTokenType: semanticType,
|
||||
semanticTokenModifiers: semanticModifiers,
|
||||
additionalSemanticTokenModifiers:
|
||||
_isAnnotationIdentifier(parent)
|
||||
? {CustomSemanticTokenModifiers.annotation}
|
||||
: null,
|
||||
additionalSemanticTokenModifiers: _isAnnotationIdentifier(parent)
|
||||
? {CustomSemanticTokenModifiers.annotation}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -304,10 +303,9 @@ class DartUnitHighlightsComputer {
|
||||
}
|
||||
// Handle tokens that are references to record fields.
|
||||
if (staticType is RecordType) {
|
||||
type =
|
||||
staticType.fieldByName(nameToken.lexeme) != null
|
||||
? HighlightRegionType.INSTANCE_GETTER_REFERENCE
|
||||
: HighlightRegionType.UNRESOLVED_INSTANCE_MEMBER_REFERENCE;
|
||||
type = staticType.fieldByName(nameToken.lexeme) != null
|
||||
? HighlightRegionType.INSTANCE_GETTER_REFERENCE
|
||||
: HighlightRegionType.UNRESOLVED_INSTANCE_MEMBER_REFERENCE;
|
||||
}
|
||||
}
|
||||
// Add the highlight region.
|
||||
@@ -315,10 +313,9 @@ class DartUnitHighlightsComputer {
|
||||
return _addRegion_token(
|
||||
nameToken,
|
||||
type,
|
||||
additionalSemanticTokenModifiers:
|
||||
_isAnnotationIdentifier(parent)
|
||||
? {CustomSemanticTokenModifiers.annotation}
|
||||
: null,
|
||||
additionalSemanticTokenModifiers: _isAnnotationIdentifier(parent)
|
||||
? {CustomSemanticTokenModifiers.annotation}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
return false;
|
||||
@@ -337,14 +334,13 @@ class DartUnitHighlightsComputer {
|
||||
parent is MethodInvocation && parent.methodName.token == nameToken;
|
||||
HighlightRegionType type;
|
||||
var isTopLevel = element is TopLevelFunctionElement;
|
||||
type =
|
||||
isTopLevel
|
||||
? isInvocation
|
||||
? HighlightRegionType.TOP_LEVEL_FUNCTION_REFERENCE
|
||||
: HighlightRegionType.TOP_LEVEL_FUNCTION_TEAR_OFF
|
||||
: isInvocation
|
||||
? HighlightRegionType.LOCAL_FUNCTION_REFERENCE
|
||||
: HighlightRegionType.LOCAL_FUNCTION_TEAR_OFF;
|
||||
type = isTopLevel
|
||||
? isInvocation
|
||||
? HighlightRegionType.TOP_LEVEL_FUNCTION_REFERENCE
|
||||
: HighlightRegionType.TOP_LEVEL_FUNCTION_TEAR_OFF
|
||||
: isInvocation
|
||||
? HighlightRegionType.LOCAL_FUNCTION_REFERENCE
|
||||
: HighlightRegionType.LOCAL_FUNCTION_TEAR_OFF;
|
||||
return _addRegion_token(nameToken, type);
|
||||
}
|
||||
|
||||
@@ -412,10 +408,9 @@ class DartUnitHighlightsComputer {
|
||||
return _addRegion_token(
|
||||
nameToken,
|
||||
HighlightRegionType.LABEL,
|
||||
semanticTokenModifiers:
|
||||
parent is! BreakStatement
|
||||
? {SemanticTokenModifiers.declaration}
|
||||
: null,
|
||||
semanticTokenModifiers: parent is! BreakStatement
|
||||
? {SemanticTokenModifiers.declaration}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -424,10 +419,9 @@ class DartUnitHighlightsComputer {
|
||||
return false;
|
||||
}
|
||||
// OK
|
||||
var type =
|
||||
element.type is DynamicType
|
||||
? HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE
|
||||
: HighlightRegionType.LOCAL_VARIABLE_REFERENCE;
|
||||
var type = element.type is DynamicType
|
||||
? HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE
|
||||
: HighlightRegionType.LOCAL_VARIABLE_REFERENCE;
|
||||
return _addRegion_token(nameToken, type);
|
||||
}
|
||||
|
||||
@@ -447,15 +441,13 @@ class DartUnitHighlightsComputer {
|
||||
// OK
|
||||
HighlightRegionType type;
|
||||
if (isStatic) {
|
||||
type =
|
||||
isInvocation
|
||||
? HighlightRegionType.STATIC_METHOD_REFERENCE
|
||||
: HighlightRegionType.STATIC_METHOD_TEAR_OFF;
|
||||
type = isInvocation
|
||||
? HighlightRegionType.STATIC_METHOD_REFERENCE
|
||||
: HighlightRegionType.STATIC_METHOD_TEAR_OFF;
|
||||
} else {
|
||||
type =
|
||||
isInvocation
|
||||
? HighlightRegionType.INSTANCE_METHOD_REFERENCE
|
||||
: HighlightRegionType.INSTANCE_METHOD_TEAR_OFF;
|
||||
type = isInvocation
|
||||
? HighlightRegionType.INSTANCE_METHOD_REFERENCE
|
||||
: HighlightRegionType.INSTANCE_METHOD_TEAR_OFF;
|
||||
}
|
||||
return _addRegion_token(nameToken, type);
|
||||
}
|
||||
@@ -468,21 +460,20 @@ class DartUnitHighlightsComputer {
|
||||
if (element is! FormalParameterElement) {
|
||||
return false;
|
||||
}
|
||||
var type =
|
||||
element.type is DynamicType
|
||||
? HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE
|
||||
: HighlightRegionType.PARAMETER_REFERENCE;
|
||||
var modifiers =
|
||||
parent is Label ? {CustomSemanticTokenModifiers.label} : null;
|
||||
var type = element.type is DynamicType
|
||||
? HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE
|
||||
: HighlightRegionType.PARAMETER_REFERENCE;
|
||||
var modifiers = parent is Label
|
||||
? {CustomSemanticTokenModifiers.label}
|
||||
: null;
|
||||
return _addRegion_token(nameToken, type, semanticTokenModifiers: modifiers);
|
||||
}
|
||||
|
||||
bool _addIdentifierRegion_typeAlias(Token nameToken, Element? element) {
|
||||
if (element is TypeAliasElement) {
|
||||
var type =
|
||||
element.aliasedType is FunctionType
|
||||
? HighlightRegionType.FUNCTION_TYPE_ALIAS
|
||||
: HighlightRegionType.TYPE_ALIAS;
|
||||
var type = element.aliasedType is FunctionType
|
||||
? HighlightRegionType.FUNCTION_TYPE_ALIAS
|
||||
: HighlightRegionType.TYPE_ALIAS;
|
||||
return _addRegion_token(nameToken, type);
|
||||
}
|
||||
return false;
|
||||
@@ -1420,20 +1411,17 @@ class _DartUnitHighlightsComputerVisitor extends RecursiveAstVisitor<void> {
|
||||
|
||||
HighlightRegionType nameType;
|
||||
if (node.isGetter) {
|
||||
nameType =
|
||||
node.isStatic
|
||||
? HighlightRegionType.STATIC_GETTER_DECLARATION
|
||||
: HighlightRegionType.INSTANCE_GETTER_DECLARATION;
|
||||
nameType = node.isStatic
|
||||
? HighlightRegionType.STATIC_GETTER_DECLARATION
|
||||
: HighlightRegionType.INSTANCE_GETTER_DECLARATION;
|
||||
} else if (node.isSetter) {
|
||||
nameType =
|
||||
node.isStatic
|
||||
? HighlightRegionType.STATIC_SETTER_DECLARATION
|
||||
: HighlightRegionType.INSTANCE_SETTER_DECLARATION;
|
||||
nameType = node.isStatic
|
||||
? HighlightRegionType.STATIC_SETTER_DECLARATION
|
||||
: HighlightRegionType.INSTANCE_SETTER_DECLARATION;
|
||||
} else {
|
||||
nameType =
|
||||
node.isStatic
|
||||
? HighlightRegionType.STATIC_METHOD_DECLARATION
|
||||
: HighlightRegionType.INSTANCE_METHOD_DECLARATION;
|
||||
nameType = node.isStatic
|
||||
? HighlightRegionType.STATIC_METHOD_DECLARATION
|
||||
: HighlightRegionType.INSTANCE_METHOD_DECLARATION;
|
||||
}
|
||||
computer._addRegion_token(node.name, nameType);
|
||||
|
||||
|
||||
@@ -138,13 +138,12 @@ class DartLazyTypeHierarchyComputer {
|
||||
var mixins = type.mixins;
|
||||
var superclassConstraints = type.superclassConstraints;
|
||||
|
||||
var supertypes =
|
||||
[
|
||||
if (supertype != null) TypeHierarchyRelatedItem.extends_(supertype),
|
||||
...superclassConstraints.map(TypeHierarchyRelatedItem.constrainedTo),
|
||||
...interfaces.map(TypeHierarchyRelatedItem.implements),
|
||||
...mixins.map(TypeHierarchyRelatedItem.mixesIn),
|
||||
].nonNulls.toList();
|
||||
var supertypes = [
|
||||
if (supertype != null) TypeHierarchyRelatedItem.extends_(supertype),
|
||||
...superclassConstraints.map(TypeHierarchyRelatedItem.constrainedTo),
|
||||
...interfaces.map(TypeHierarchyRelatedItem.implements),
|
||||
...mixins.map(TypeHierarchyRelatedItem.mixesIn),
|
||||
].nonNulls.toList();
|
||||
|
||||
return supertypes;
|
||||
}
|
||||
|
||||
@@ -321,8 +321,9 @@ class DartUnitOutlineComputer {
|
||||
var name = nameToken.lexeme;
|
||||
|
||||
var aliasedType = node.type;
|
||||
var aliasedFunctionType =
|
||||
aliasedType is GenericFunctionType ? aliasedType : null;
|
||||
var aliasedFunctionType = aliasedType is GenericFunctionType
|
||||
? aliasedType
|
||||
: null;
|
||||
|
||||
var element = Element(
|
||||
aliasedFunctionType != null
|
||||
@@ -335,14 +336,12 @@ class DartUnitOutlineComputer {
|
||||
),
|
||||
aliasedType: _safeToSource(aliasedType),
|
||||
location: _getLocationToken(nameToken),
|
||||
parameters:
|
||||
aliasedFunctionType != null
|
||||
? _safeToSource(aliasedFunctionType.parameters)
|
||||
: null,
|
||||
returnType:
|
||||
aliasedFunctionType != null
|
||||
? _safeToSource(aliasedFunctionType.returnType)
|
||||
: null,
|
||||
parameters: aliasedFunctionType != null
|
||||
? _safeToSource(aliasedFunctionType.parameters)
|
||||
: null,
|
||||
returnType: aliasedFunctionType != null
|
||||
? _safeToSource(aliasedFunctionType.returnType)
|
||||
: null,
|
||||
typeParameters: _getTypeParametersStr(node.typeParameters),
|
||||
);
|
||||
|
||||
|
||||
@@ -48,19 +48,17 @@ class DartUnitOverridesComputer {
|
||||
var superElements = overridesResult.superElements;
|
||||
var interfaceElements = overridesResult.interfaceElements;
|
||||
if (superElements.isNotEmpty || interfaceElements.isNotEmpty) {
|
||||
var superMember =
|
||||
superElements.isNotEmpty
|
||||
? proto.newOverriddenMember_fromEngine(
|
||||
superElements.first.nonSynthetic,
|
||||
)
|
||||
: null;
|
||||
var interfaceMembers =
|
||||
interfaceElements
|
||||
.map(
|
||||
(member) =>
|
||||
proto.newOverriddenMember_fromEngine(member.nonSynthetic),
|
||||
)
|
||||
.toList();
|
||||
var superMember = superElements.isNotEmpty
|
||||
? proto.newOverriddenMember_fromEngine(
|
||||
superElements.first.nonSynthetic,
|
||||
)
|
||||
: null;
|
||||
var interfaceMembers = interfaceElements
|
||||
.map(
|
||||
(member) =>
|
||||
proto.newOverriddenMember_fromEngine(member.nonSynthetic),
|
||||
)
|
||||
.toList();
|
||||
_overrides.add(
|
||||
proto.Override(
|
||||
token.offset,
|
||||
|
||||
@@ -43,8 +43,9 @@ class DartUnitSignatureComputer {
|
||||
if (parent is MethodInvocation) {
|
||||
name = parent.methodName.name;
|
||||
element = ElementLocator.locate(parent);
|
||||
parameters =
|
||||
element is FunctionTypedElement ? element.formalParameters : null;
|
||||
parameters = element is FunctionTypedElement
|
||||
? element.formalParameters
|
||||
: null;
|
||||
} else if (parent is InstanceCreationExpression) {
|
||||
name = parent.constructorName.type.qualifiedName;
|
||||
var constructorName = parent.constructorName.name;
|
||||
@@ -52,8 +53,9 @@ class DartUnitSignatureComputer {
|
||||
name += '.${constructorName.name}';
|
||||
}
|
||||
element = ElementLocator.locate(parent);
|
||||
parameters =
|
||||
element is FunctionTypedElement ? element.formalParameters : null;
|
||||
parameters = element is FunctionTypedElement
|
||||
? element.formalParameters
|
||||
: null;
|
||||
} else if (parent case FunctionExpressionInvocation(
|
||||
function: Identifier function,
|
||||
)) {
|
||||
@@ -83,11 +85,10 @@ class DartUnitSignatureComputer {
|
||||
// If we're not a named expression, then we can count how many positional
|
||||
// parameters there are before us, and then find the index of the same
|
||||
// index positional parameter.
|
||||
var positionalArgsToSkip =
|
||||
argumentList.arguments
|
||||
.where((argument) => argument is! NamedExpression)
|
||||
.takeWhile((argument) => argument.end < _offset)
|
||||
.length;
|
||||
var positionalArgsToSkip = argumentList.arguments
|
||||
.where((argument) => argument is! NamedExpression)
|
||||
.takeWhile((argument) => argument.end < _offset)
|
||||
.length;
|
||||
for (var i = 0; i < parameters.length; i++) {
|
||||
if (parameters[i].isPositional) {
|
||||
// This is the first positional parameter after our skips, so this is
|
||||
|
||||
@@ -88,20 +88,15 @@ class DartTypeArgumentsSignatureComputer {
|
||||
String? documentation,
|
||||
List<TypeParameterElement> typeParameters,
|
||||
) {
|
||||
var parameters =
|
||||
typeParameters
|
||||
.map(
|
||||
(param) =>
|
||||
lsp.ParameterInformation(label: param.displayString()),
|
||||
)
|
||||
.toList();
|
||||
var parameters = typeParameters
|
||||
.map((param) => lsp.ParameterInformation(label: param.displayString()))
|
||||
.toList();
|
||||
|
||||
var signature = lsp.SignatureInformation(
|
||||
label: label,
|
||||
documentation:
|
||||
documentation != null
|
||||
? asMarkupContentOrString(preferredFormats, documentation)
|
||||
: null,
|
||||
documentation: documentation != null
|
||||
? asMarkupContentOrString(preferredFormats, documentation)
|
||||
: null,
|
||||
parameters: parameters,
|
||||
);
|
||||
|
||||
|
||||
@@ -389,8 +389,9 @@ class ContextManagerImpl implements ContextManager {
|
||||
var analysisOptions = driver.getAnalysisOptionsForFile(file);
|
||||
var content = file.readAsStringSync();
|
||||
var lineInfo = LineInfo.fromContent(content);
|
||||
var sdkVersionConstraint =
|
||||
(package is PubPackage) ? package.sdkVersionConstraint : null;
|
||||
var sdkVersionConstraint = (package is PubPackage)
|
||||
? package.sdkVersionConstraint
|
||||
: null;
|
||||
var errors = analyzeAnalysisOptions(
|
||||
FileSource(file),
|
||||
content,
|
||||
@@ -582,22 +583,21 @@ class ContextManagerImpl implements ContextManager {
|
||||
_fileContentCache.invalidateAll();
|
||||
|
||||
var watchers = <ResourceWatcher>[];
|
||||
var collection =
|
||||
_collection = AnalysisContextCollectionImpl(
|
||||
includedPaths: includedPaths,
|
||||
excludedPaths: excludedPaths,
|
||||
byteStore: _byteStore,
|
||||
drainStreams: false,
|
||||
enableIndex: true,
|
||||
performanceLog: _performanceLog,
|
||||
resourceProvider: resourceProvider,
|
||||
scheduler: _scheduler,
|
||||
sdkPath: sdkManager.defaultSdkDirectory,
|
||||
packagesFile: packagesFile,
|
||||
fileContentCache: _fileContentCache,
|
||||
unlinkedUnitStore: _unlinkedUnitStore,
|
||||
enabledExperiments: _enabledExperiments,
|
||||
);
|
||||
var collection = _collection = AnalysisContextCollectionImpl(
|
||||
includedPaths: includedPaths,
|
||||
excludedPaths: excludedPaths,
|
||||
byteStore: _byteStore,
|
||||
drainStreams: false,
|
||||
enableIndex: true,
|
||||
performanceLog: _performanceLog,
|
||||
resourceProvider: resourceProvider,
|
||||
scheduler: _scheduler,
|
||||
sdkPath: sdkManager.defaultSdkDirectory,
|
||||
packagesFile: packagesFile,
|
||||
fileContentCache: _fileContentCache,
|
||||
unlinkedUnitStore: _unlinkedUnitStore,
|
||||
enabledExperiments: _enabledExperiments,
|
||||
);
|
||||
|
||||
for (var analysisContext in collection.contexts) {
|
||||
var driver = analysisContext.driver;
|
||||
@@ -671,37 +671,35 @@ class ContextManagerImpl implements ContextManager {
|
||||
// Create temporary watchers before we start the context build so we can
|
||||
// tell if any files were modified while waiting for the "real" watchers to
|
||||
// become ready and start the process again.
|
||||
var temporaryWatchers =
|
||||
includedPaths
|
||||
.map((path) => resourceProvider.getResource(path))
|
||||
.map((resource) => resource.watch())
|
||||
.toList();
|
||||
var temporaryWatchers = includedPaths
|
||||
.map((path) => resourceProvider.getResource(path))
|
||||
.map((resource) => resource.watch())
|
||||
.toList();
|
||||
|
||||
// If any watcher picks up an important change while we're running the
|
||||
// rest of this method, we will need to start again.
|
||||
var needsBuild = true;
|
||||
var temporaryWatcherSubscriptions =
|
||||
temporaryWatchers
|
||||
.map(
|
||||
(watcher) => watcher.changes.listen(
|
||||
(event) {
|
||||
if (shouldRestartBuild(event.path)) {
|
||||
needsBuild = true;
|
||||
}
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
// Errors in the watcher such as "Directory watcher closed
|
||||
// unexpectedly" on Windows when the buffer overflows also
|
||||
// require that we restarted to be consistent.
|
||||
needsBuild = true;
|
||||
_instrumentationService.logError(
|
||||
'Temporary watcher error; restarting context build.\n'
|
||||
'$error\n$stackTrace',
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
var temporaryWatcherSubscriptions = temporaryWatchers
|
||||
.map(
|
||||
(watcher) => watcher.changes.listen(
|
||||
(event) {
|
||||
if (shouldRestartBuild(event.path)) {
|
||||
needsBuild = true;
|
||||
}
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
// Errors in the watcher such as "Directory watcher closed
|
||||
// unexpectedly" on Windows when the buffer overflows also
|
||||
// require that we restarted to be consistent.
|
||||
needsBuild = true;
|
||||
_instrumentationService.logError(
|
||||
'Temporary watcher error; restarting context build.\n'
|
||||
'$error\n$stackTrace',
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
try {
|
||||
// Ensure all watchers are ready before we begin any rebuild.
|
||||
@@ -949,10 +947,9 @@ class ContextManagerImpl implements ContextManager {
|
||||
|
||||
class NoopContextManagerCallbacks implements ContextManagerCallbacks {
|
||||
@override
|
||||
AnalysisServer get analysisServer =>
|
||||
throw StateError(
|
||||
'The callback object should have been set by the server.',
|
||||
);
|
||||
AnalysisServer get analysisServer => throw StateError(
|
||||
'The callback object should have been set by the server.',
|
||||
);
|
||||
|
||||
@override
|
||||
void afterContextsCreated() {}
|
||||
|
||||
@@ -24,11 +24,10 @@ void addDartOccurrences(OccurrencesCollector collector, CompilationUnit unit) {
|
||||
// what is in the source.
|
||||
var length =
|
||||
serverElement.location?.length ?? engineElement.name?.length ?? 0;
|
||||
var offsets =
|
||||
nodes
|
||||
.where((node) => node.length == length)
|
||||
.map((node) => node.offset)
|
||||
.toList();
|
||||
var offsets = nodes
|
||||
.where((node) => node.length == length)
|
||||
.map((node) => node.offset)
|
||||
.toList();
|
||||
|
||||
var occurrences = protocol.Occurrences(serverElement, offsets, length);
|
||||
collector.addOccurrences(occurrences);
|
||||
@@ -285,10 +284,9 @@ class DartUnitOccurrencesComputerVisitor extends GeneralizingAstVisitor<void> {
|
||||
var element = node.element;
|
||||
var pattern = node.pattern;
|
||||
// If no explicit field name, use the variables name.
|
||||
var name =
|
||||
node.name?.name == null && pattern is VariablePattern
|
||||
? pattern.name
|
||||
: node.name?.name;
|
||||
var name = node.name?.name == null && pattern is VariablePattern
|
||||
? pattern.name
|
||||
: node.name?.name;
|
||||
if (element != null && name != null) {
|
||||
_addOccurrence(element, name);
|
||||
}
|
||||
|
||||
@@ -36,14 +36,13 @@ String format(String content, {Version? languageVersion}) {
|
||||
/// cause of the failure, a list of [Diagnostic]s.
|
||||
ParseStringResult sortDirectives(String contents, {String? fileName}) {
|
||||
var (unit, diagnostics) = _parse(contents, fullName: fileName);
|
||||
var parseErrors =
|
||||
diagnostics
|
||||
.where(
|
||||
(d) =>
|
||||
d.diagnosticCode is ScannerErrorCode ||
|
||||
d.diagnosticCode is ParserErrorCode,
|
||||
)
|
||||
.toList();
|
||||
var parseErrors = diagnostics
|
||||
.where(
|
||||
(d) =>
|
||||
d.diagnosticCode is ScannerErrorCode ||
|
||||
d.diagnosticCode is ParserErrorCode,
|
||||
)
|
||||
.toList();
|
||||
if (parseErrors.isNotEmpty) {
|
||||
return ParseStringResultImpl(contents, unit, parseErrors);
|
||||
}
|
||||
@@ -63,10 +62,11 @@ ParseStringResult sortDirectives(String contents, {String? fileName}) {
|
||||
sdkLanguageVersion: ExperimentStatus.currentVersion,
|
||||
flags: [],
|
||||
);
|
||||
var scanner = Scanner(source, reader, diagnosticListener)..configureFeatures(
|
||||
featureSetForOverriding: FeatureSet.latestLanguageVersion(),
|
||||
featureSet: featureSet,
|
||||
);
|
||||
var scanner = Scanner(source, reader, diagnosticListener)
|
||||
..configureFeatures(
|
||||
featureSetForOverriding: FeatureSet.latestLanguageVersion(),
|
||||
featureSet: featureSet,
|
||||
);
|
||||
var token = scanner.tokenize(reportScannerErrors: false);
|
||||
var lineInfo = LineInfo(scanner.lineStarts);
|
||||
var languageVersion = LibraryLanguageVersion(
|
||||
|
||||
@@ -20,11 +20,10 @@ class AnalysisGetErrorsHandler extends LegacyHandler {
|
||||
|
||||
@override
|
||||
Future<void> handle() async {
|
||||
var file =
|
||||
AnalysisGetErrorsParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).file;
|
||||
var file = AnalysisGetErrorsParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).file;
|
||||
|
||||
if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
|
||||
return;
|
||||
|
||||
@@ -50,12 +50,11 @@ class AnalysisGetImportedElementsHandler extends LegacyHandler {
|
||||
if (disableManageImportsOnPaste) {
|
||||
elements = <ImportedElements>[];
|
||||
} else {
|
||||
elements =
|
||||
ImportedElementsComputer(
|
||||
result.unit,
|
||||
params.offset,
|
||||
params.length,
|
||||
).compute();
|
||||
elements = ImportedElementsComputer(
|
||||
result.unit,
|
||||
params.offset,
|
||||
params.length,
|
||||
).compute();
|
||||
}
|
||||
|
||||
sendResult(AnalysisGetImportedElementsResult(elements));
|
||||
|
||||
@@ -41,10 +41,9 @@ Future<CompletionSuggestion?> candidateToCompletionSuggestion(
|
||||
case TypedSuggestion():
|
||||
var data = await createTypedSuggestionData(candidate, request);
|
||||
requiredImports = data?.imports.toList() ?? requiredImports;
|
||||
var kind =
|
||||
request.target.isFunctionalArgument()
|
||||
? CompletionSuggestionKind.IDENTIFIER
|
||||
: null;
|
||||
var kind = request.target.isFunctionalArgument()
|
||||
? CompletionSuggestionKind.IDENTIFIER
|
||||
: null;
|
||||
candidate.data = data;
|
||||
|
||||
return switch (candidate) {
|
||||
@@ -84,20 +83,20 @@ Future<CompletionSuggestion?> candidateToCompletionSuggestion(
|
||||
),
|
||||
|
||||
MethodSuggestion(kind: var suggestionKind) =>
|
||||
// TODO(brianwilkerson): Correctly set the kind of suggestion in cases
|
||||
// where `isFunctionalArgument` would return `true` so we can stop
|
||||
// using the `request.target`.
|
||||
_getDartCompletionSuggestion(
|
||||
candidate.element,
|
||||
candidate.completion,
|
||||
candidate.relevanceScore,
|
||||
kind ?? suggestionKind,
|
||||
request,
|
||||
isNotImportedLibrary,
|
||||
libraryUriStr,
|
||||
requiredImports,
|
||||
displayString: data?.displayText,
|
||||
),
|
||||
// TODO(brianwilkerson): Correctly set the kind of suggestion in cases
|
||||
// where `isFunctionalArgument` would return `true` so we can stop
|
||||
// using the `request.target`.
|
||||
_getDartCompletionSuggestion(
|
||||
candidate.element,
|
||||
candidate.completion,
|
||||
candidate.relevanceScore,
|
||||
kind ?? suggestionKind,
|
||||
request,
|
||||
isNotImportedLibrary,
|
||||
libraryUriStr,
|
||||
requiredImports,
|
||||
displayString: data?.displayText,
|
||||
),
|
||||
RecordFieldSuggestion() => DartCompletionSuggestion(
|
||||
CompletionSuggestionKind.IDENTIFIER,
|
||||
candidate.relevanceScore,
|
||||
@@ -455,14 +454,14 @@ _ParameterData _createParameterData(e.Element element) {
|
||||
bool? hasNamedParameters;
|
||||
CompletionDefaultArgumentList? defaultArgumentList;
|
||||
if (element is e.ExecutableElement && element is! e.PropertyAccessorElement) {
|
||||
parameterNames =
|
||||
element.formalParameters.map((parameter) {
|
||||
return parameter.displayName;
|
||||
}).toList();
|
||||
parameterTypes =
|
||||
element.formalParameters.map((e.FormalParameterElement parameter) {
|
||||
return parameter.type.getDisplayString();
|
||||
}).toList();
|
||||
parameterNames = element.formalParameters.map((parameter) {
|
||||
return parameter.displayName;
|
||||
}).toList();
|
||||
parameterTypes = element.formalParameters.map((
|
||||
e.FormalParameterElement parameter,
|
||||
) {
|
||||
return parameter.type.getDisplayString();
|
||||
}).toList();
|
||||
|
||||
var requiredParameters = element.formalParameters.where(
|
||||
(e.FormalParameterElement param) => param.isRequiredPositional,
|
||||
|
||||
@@ -134,7 +134,8 @@ class EditGetAssistsHandler extends LegacyHandler
|
||||
} on InconsistentAnalysisException {
|
||||
// ignore
|
||||
} catch (exception, stackTrace) {
|
||||
var parametersFile = '''
|
||||
var parametersFile =
|
||||
'''
|
||||
offset: $offset
|
||||
length: $length
|
||||
''';
|
||||
|
||||
@@ -125,8 +125,9 @@ class EditGetFixesHandler extends LegacyHandler
|
||||
var package = analysisContext.contextRoot.workspace.findPackageFor(
|
||||
optionsFile.path,
|
||||
);
|
||||
var sdkVersionConstraint =
|
||||
(package is PubPackage) ? package.sdkVersionConstraint : null;
|
||||
var sdkVersionConstraint = (package is PubPackage)
|
||||
? package.sdkVersionConstraint
|
||||
: null;
|
||||
var diagnostics = analyzeAnalysisOptions(
|
||||
FileSource(optionsFile),
|
||||
content,
|
||||
@@ -222,7 +223,8 @@ class EditGetFixesHandler extends LegacyHandler
|
||||
} on InconsistentAnalysisException {
|
||||
fixes = [];
|
||||
} catch (exception, stackTrace) {
|
||||
var parametersFile = '''
|
||||
var parametersFile =
|
||||
'''
|
||||
offset: $offset
|
||||
error: $diagnostic
|
||||
error.errorCode: ${diagnostic.diagnosticCode}
|
||||
|
||||
+6
-7
@@ -21,13 +21,12 @@ class EditListPostfixCompletionTemplatesHandler extends LegacyHandler {
|
||||
|
||||
@override
|
||||
Future<void> handle() async {
|
||||
var templates =
|
||||
DartPostfixCompletion.ALL_TEMPLATES
|
||||
.map(
|
||||
(PostfixCompletionKind kind) =>
|
||||
PostfixTemplateDescriptor(kind.name, kind.key, kind.example),
|
||||
)
|
||||
.toList();
|
||||
var templates = DartPostfixCompletion.ALL_TEMPLATES
|
||||
.map(
|
||||
(PostfixCompletionKind kind) =>
|
||||
PostfixTemplateDescriptor(kind.name, kind.key, kind.example),
|
||||
)
|
||||
.toList();
|
||||
sendResult(EditListPostfixCompletionTemplatesResult(templates));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,10 @@ class ExecutionCreateContextHandler extends LegacyHandler {
|
||||
|
||||
@override
|
||||
Future<void> handle() async {
|
||||
var file =
|
||||
ExecutionCreateContextParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).contextRoot;
|
||||
var file = ExecutionCreateContextParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).contextRoot;
|
||||
var executionContext = server.executionContext;
|
||||
var contextId = (executionContext.nextContextId++).toString();
|
||||
executionContext.contextMap[contextId] = file;
|
||||
|
||||
@@ -20,11 +20,10 @@ class ExecutionDeleteContextHandler extends LegacyHandler {
|
||||
|
||||
@override
|
||||
Future<void> handle() async {
|
||||
var contextId =
|
||||
ExecutionDeleteContextParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).id;
|
||||
var contextId = ExecutionDeleteContextParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).id;
|
||||
server.executionContext.contextMap.remove(contextId);
|
||||
sendResult(ExecutionDeleteContextResult());
|
||||
}
|
||||
|
||||
@@ -40,14 +40,14 @@ class LspOverLegacyHandler extends LegacyHandler {
|
||||
var reporter = LspJsonReporter();
|
||||
var lspMessage =
|
||||
lspMessageJson is Map<String, Object?> &&
|
||||
RequestMessage.canParse(lspMessageJson, reporter)
|
||||
? RequestMessage.fromJson({
|
||||
// Pass across any clientRequestTime from the envelope so that we
|
||||
// can record latency for LSP-over-Legacy requests.
|
||||
'clientRequestTime': request.clientRequestTime,
|
||||
...lspMessageJson,
|
||||
})
|
||||
: null;
|
||||
RequestMessage.canParse(lspMessageJson, reporter)
|
||||
? RequestMessage.fromJson({
|
||||
// Pass across any clientRequestTime from the envelope so that we
|
||||
// can record latency for LSP-over-Legacy requests.
|
||||
'clientRequestTime': request.clientRequestTime,
|
||||
...lspMessageJson,
|
||||
})
|
||||
: null;
|
||||
|
||||
if (lspMessage != null) {
|
||||
server.analyticsManager.startedRequestMessage(
|
||||
|
||||
@@ -74,22 +74,21 @@ class SearchGetElementDeclarationsHandler extends LegacyHandler {
|
||||
).compute();
|
||||
|
||||
var declarations = workspaceSymbols.declarations;
|
||||
var elementDeclarations =
|
||||
declarations.map((declaration) {
|
||||
return protocol.ElementDeclaration(
|
||||
declaration.name,
|
||||
getElementKind(declaration.kind),
|
||||
declaration.fileIndex,
|
||||
declaration.offset,
|
||||
declaration.line,
|
||||
declaration.column,
|
||||
declaration.codeOffset,
|
||||
declaration.codeLength,
|
||||
className: declaration.className,
|
||||
mixinName: declaration.mixinName,
|
||||
parameters: declaration.parameters,
|
||||
);
|
||||
}).toList();
|
||||
var elementDeclarations = declarations.map((declaration) {
|
||||
return protocol.ElementDeclaration(
|
||||
declaration.name,
|
||||
getElementKind(declaration.kind),
|
||||
declaration.fileIndex,
|
||||
declaration.offset,
|
||||
declaration.line,
|
||||
declaration.column,
|
||||
declaration.codeOffset,
|
||||
declaration.codeLength,
|
||||
className: declaration.className,
|
||||
mixinName: declaration.mixinName,
|
||||
parameters: declaration.parameters,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
server.sendResponse(
|
||||
protocol.SearchGetElementDeclarationsResult(
|
||||
|
||||
@@ -20,11 +20,10 @@ class ServerCancelRequestHandler extends LegacyHandler {
|
||||
|
||||
@override
|
||||
Future<void> handle() async {
|
||||
var id =
|
||||
ServerCancelRequestParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).id;
|
||||
var id = ServerCancelRequestParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).id;
|
||||
server.cancelRequest(id);
|
||||
sendResult(ServerCancelRequestResult());
|
||||
}
|
||||
|
||||
@@ -22,11 +22,10 @@ class ServerSetSubscriptionsHandler extends LegacyHandler {
|
||||
@override
|
||||
Future<void> handle() async {
|
||||
try {
|
||||
server.serverServices =
|
||||
ServerSetSubscriptionsParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).subscriptions.toSet();
|
||||
server.serverServices = ServerSetSubscriptionsParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).subscriptions.toSet();
|
||||
server.requestStatistics?.isNotificationSubscribed = server.serverServices
|
||||
.contains(ServerService.LOG);
|
||||
} on RequestFailure catch (exception) {
|
||||
|
||||
@@ -777,14 +777,14 @@ class LegacyAnalysisServer extends AnalysisServer {
|
||||
return lspResponse is Map<String, Object?>
|
||||
? lsp.ResponseMessage.fromJson(lspResponse)
|
||||
: lsp.ResponseMessage(
|
||||
jsonrpc: lsp.jsonRpcVersion,
|
||||
error: lsp.ResponseError(
|
||||
code: lsp.ServerErrorCodes.UnhandledError,
|
||||
message:
|
||||
"The client responded to a '$method' LSP request but"
|
||||
' did not include a valid response in the lspResponse field',
|
||||
),
|
||||
);
|
||||
jsonrpc: lsp.jsonRpcVersion,
|
||||
error: lsp.ResponseError(
|
||||
code: lsp.ServerErrorCodes.UnhandledError,
|
||||
message:
|
||||
"The client responded to a '$method' LSP request but"
|
||||
' did not include a valid response in the lspResponse field',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Send the given [notification] to the client.
|
||||
|
||||
@@ -157,14 +157,13 @@ class LspClientConfiguration {
|
||||
|
||||
/// Gets the path for the WorkspaceFolder closest to [resourcePath].
|
||||
String? _getWorkspaceFolderPath(String resourcePath) {
|
||||
var candidates =
|
||||
_resourceSettings.keys
|
||||
.where(
|
||||
(wfPath) =>
|
||||
wfPath == _normaliseFolderPath(resourcePath) ||
|
||||
pathContext.isWithin(wfPath, resourcePath),
|
||||
)
|
||||
.toList();
|
||||
var candidates = _resourceSettings.keys
|
||||
.where(
|
||||
(wfPath) =>
|
||||
wfPath == _normaliseFolderPath(resourcePath) ||
|
||||
pathContext.isWithin(wfPath, resourcePath),
|
||||
)
|
||||
.toList();
|
||||
candidates.sort((a, b) => -a.length.compareTo(b.length));
|
||||
return candidates.firstOrNull;
|
||||
}
|
||||
@@ -341,13 +340,12 @@ class LspGlobalClientConfiguration extends LspResourceClientConfiguration {
|
||||
///
|
||||
/// [showAllTodos] should be checked first, as this will return an empty
|
||||
/// set if `showTodos` is a boolean.
|
||||
Set<String> get showTodoTypes =>
|
||||
_settings['showTodos'] is List
|
||||
? (_settings['showTodos'] as List)
|
||||
.cast<String>()
|
||||
.map((kind) => kind.toUpperCase())
|
||||
.toSet()
|
||||
: const {};
|
||||
Set<String> get showTodoTypes => _settings['showTodos'] is List
|
||||
? (_settings['showTodos'] as List)
|
||||
.cast<String>()
|
||||
.map((kind) => kind.toUpperCase())
|
||||
.toSet()
|
||||
: const {};
|
||||
}
|
||||
|
||||
/// Wraps the client (editor) configuration for a specific resource.
|
||||
|
||||
@@ -191,10 +191,9 @@ lsp.CompletionItem? toLspCompletionItem(
|
||||
//
|
||||
// In the case of show combinators, the parens will still be shown to indicate
|
||||
// functions but they should not be included in the completions.
|
||||
var element =
|
||||
suggestion is ElementBasedSuggestion
|
||||
? (suggestion as ElementBasedSuggestion).element
|
||||
: null;
|
||||
var element = suggestion is ElementBasedSuggestion
|
||||
? (suggestion as ElementBasedSuggestion).element
|
||||
: null;
|
||||
var isCallable =
|
||||
element != null &&
|
||||
(element is ConstructorElement ||
|
||||
@@ -238,10 +237,9 @@ lsp.CompletionItem? toLspCompletionItem(
|
||||
|
||||
// TODO(dantup): Consider including more of these raw fields in the original
|
||||
// suggestion to avoid needing to manipulate them in this way here.
|
||||
var filterText =
|
||||
!label.startsWith(completionFilterTextSplitPattern)
|
||||
? label.split(completionFilterTextSplitPattern).first.trim()
|
||||
: label;
|
||||
var filterText = !label.startsWith(completionFilterTextSplitPattern)
|
||||
? label.split(completionFilterTextSplitPattern).first.trim()
|
||||
: label;
|
||||
|
||||
// If we're using label details, we also don't want the label to include any
|
||||
// additional symbols as noted above, because they will appear in the extra
|
||||
@@ -266,18 +264,17 @@ lsp.CompletionItem? toLspCompletionItem(
|
||||
|
||||
var colorPreviewHex =
|
||||
capabilities.completionItemKinds.contains(lsp.CompletionItemKind.Color) &&
|
||||
suggestion is ElementBasedSuggestion
|
||||
? server.getColorHexString(element)
|
||||
: null;
|
||||
suggestion is ElementBasedSuggestion
|
||||
? server.getColorHexString(element)
|
||||
: null;
|
||||
|
||||
var completionKind =
|
||||
colorPreviewHex != null
|
||||
? lsp.CompletionItemKind.Color
|
||||
: _candidateToCompletionItemKind(
|
||||
capabilities.completionItemKinds,
|
||||
suggestion,
|
||||
label,
|
||||
);
|
||||
var completionKind = colorPreviewHex != null
|
||||
? lsp.CompletionItemKind.Color
|
||||
: _candidateToCompletionItemKind(
|
||||
capabilities.completionItemKinds,
|
||||
suggestion,
|
||||
label,
|
||||
);
|
||||
|
||||
var labelDetails = _getCompletionDetail(
|
||||
suggestion,
|
||||
@@ -305,10 +302,9 @@ lsp.CompletionItem? toLspCompletionItem(
|
||||
var element = (suggestion as ElementBasedSuggestion).element;
|
||||
|
||||
if (element is ExecutableElement && element is! PropertyAccessorElement) {
|
||||
parameterNames =
|
||||
element.formalParameters.map((parameter) {
|
||||
return parameter.displayName;
|
||||
}).toList();
|
||||
parameterNames = element.formalParameters.map((parameter) {
|
||||
return parameter.displayName;
|
||||
}).toList();
|
||||
|
||||
var requiredParameters = element.formalParameters.where(
|
||||
(FormalParameterElement param) => param.isRequiredPositional,
|
||||
@@ -328,10 +324,9 @@ lsp.CompletionItem? toLspCompletionItem(
|
||||
}
|
||||
|
||||
var completion = suggestion.completion;
|
||||
var selectionOffset =
|
||||
(suggestion is KeywordSuggestion)
|
||||
? suggestion.selectionOffset
|
||||
: completion.length;
|
||||
var selectionOffset = (suggestion is KeywordSuggestion)
|
||||
? suggestion.selectionOffset
|
||||
: completion.length;
|
||||
var selectionLength = 0;
|
||||
|
||||
if (suggestion is SuggestionData) {
|
||||
@@ -361,10 +356,9 @@ lsp.CompletionItem? toLspCompletionItem(
|
||||
// To improve the display of some items (like pubspec version numbers),
|
||||
// short labels in the format `_foo_` in docComplete are "upgraded" to the
|
||||
// detail field.
|
||||
var labelMatch =
|
||||
cleanedDoc != null
|
||||
? upgradableDocCompletePattern.firstMatch(cleanedDoc)
|
||||
: null;
|
||||
var labelMatch = cleanedDoc != null
|
||||
? upgradableDocCompletePattern.firstMatch(cleanedDoc)
|
||||
: null;
|
||||
if (labelMatch != null) {
|
||||
cleanedDoc = null;
|
||||
labelDetails = (
|
||||
@@ -398,50 +392,46 @@ lsp.CompletionItem? toLspCompletionItem(
|
||||
]),
|
||||
data: resolutionData,
|
||||
detail: labelDetails.detail.nullIfEmpty,
|
||||
labelDetails:
|
||||
useLabelDetails
|
||||
? lsp.CompletionItemLabelDetails(
|
||||
detail: labelDetails.truncatedSignature.nullIfEmpty,
|
||||
description: getCompletionDisplayUriString(
|
||||
uriConverter: uriConverter,
|
||||
pathContext: pathContext,
|
||||
elementLibraryUri: labelDetails.autoImportUri,
|
||||
completionFilePath: completionFilePath,
|
||||
),
|
||||
).nullIfEmpty
|
||||
: null,
|
||||
documentation:
|
||||
cleanedDoc != null
|
||||
? asMarkupContentOrString(formats, cleanedDoc)
|
||||
: null,
|
||||
labelDetails: useLabelDetails
|
||||
? lsp.CompletionItemLabelDetails(
|
||||
detail: labelDetails.truncatedSignature.nullIfEmpty,
|
||||
description: getCompletionDisplayUriString(
|
||||
uriConverter: uriConverter,
|
||||
pathContext: pathContext,
|
||||
elementLibraryUri: labelDetails.autoImportUri,
|
||||
completionFilePath: completionFilePath,
|
||||
),
|
||||
).nullIfEmpty
|
||||
: null,
|
||||
documentation: cleanedDoc != null
|
||||
? asMarkupContentOrString(formats, cleanedDoc)
|
||||
: null,
|
||||
deprecated: supportsCompletionDeprecatedFlag && isDeprecated ? true : null,
|
||||
sortText: relevanceToSortText(suggestion.relevanceScore),
|
||||
filterText: filterText.orNullIfSameAs(
|
||||
label,
|
||||
), // filterText uses label if not set
|
||||
insertTextFormat:
|
||||
insertTextFormat != lsp.InsertTextFormat.PlainText
|
||||
? insertTextFormat
|
||||
: null, // Defaults to PlainText if not supplied
|
||||
insertTextFormat: insertTextFormat != lsp.InsertTextFormat.PlainText
|
||||
? insertTextFormat
|
||||
: null, // Defaults to PlainText if not supplied
|
||||
insertTextMode:
|
||||
!hasDefaultTextMode && supportsAsIsInsertMode && isMultilineCompletion
|
||||
? lsp.InsertTextMode.asIs
|
||||
: null,
|
||||
? lsp.InsertTextMode.asIs
|
||||
: null,
|
||||
// When using defaults for edit range, don't use textEdit.
|
||||
textEdit:
|
||||
hasDefaultEditRange
|
||||
? null
|
||||
: supportsInsertReplace && insertionRange != replacementRange
|
||||
? lsp.Either2<lsp.InsertReplaceEdit, lsp.TextEdit>.t1(
|
||||
lsp.InsertReplaceEdit(
|
||||
insert: insertionRange,
|
||||
replace: replacementRange,
|
||||
newText: insertText,
|
||||
),
|
||||
)
|
||||
: lsp.Either2<lsp.InsertReplaceEdit, lsp.TextEdit>.t2(
|
||||
lsp.TextEdit(range: replacementRange, newText: insertText),
|
||||
textEdit: hasDefaultEditRange
|
||||
? null
|
||||
: supportsInsertReplace && insertionRange != replacementRange
|
||||
? lsp.Either2<lsp.InsertReplaceEdit, lsp.TextEdit>.t1(
|
||||
lsp.InsertReplaceEdit(
|
||||
insert: insertionRange,
|
||||
replace: replacementRange,
|
||||
newText: insertText,
|
||||
),
|
||||
)
|
||||
: lsp.Either2<lsp.InsertReplaceEdit, lsp.TextEdit>.t2(
|
||||
lsp.TextEdit(range: replacementRange, newText: insertText),
|
||||
),
|
||||
// When using defaults for edit range, use textEditText.
|
||||
textEditText: hasDefaultEditRange ? insertText.orNullIfSameAs(label) : null,
|
||||
);
|
||||
@@ -490,13 +480,13 @@ lsp.CompletionItemKind? _candidateToCompletionItemKind(
|
||||
if (!label.startsWith('dart:')) {
|
||||
return label.endsWith('.dart')
|
||||
? const [
|
||||
lsp.CompletionItemKind.File,
|
||||
lsp.CompletionItemKind.Module,
|
||||
]
|
||||
lsp.CompletionItemKind.File,
|
||||
lsp.CompletionItemKind.Module,
|
||||
]
|
||||
: const [
|
||||
lsp.CompletionItemKind.Folder,
|
||||
lsp.CompletionItemKind.Module,
|
||||
];
|
||||
lsp.CompletionItemKind.Folder,
|
||||
lsp.CompletionItemKind.Module,
|
||||
];
|
||||
}
|
||||
return const [lsp.CompletionItemKind.Module];
|
||||
default:
|
||||
@@ -603,10 +593,9 @@ CompletionDetail _getCompletionDetail(
|
||||
} else if (suggestion is RecordFieldSuggestion) {
|
||||
returnType = suggestion.field.type.getDisplayString();
|
||||
}
|
||||
var element =
|
||||
suggestion is ElementBasedSuggestion
|
||||
? (suggestion as ElementBasedSuggestion).element
|
||||
: null;
|
||||
var element = suggestion is ElementBasedSuggestion
|
||||
? (suggestion as ElementBasedSuggestion).element
|
||||
: null;
|
||||
|
||||
// Usually getter/setters look the same in completion because they insert the
|
||||
// same text. This is not the case for overrides because they will insert
|
||||
@@ -702,8 +691,9 @@ CompletionDetail _getCompletionDetail(
|
||||
isNotImported = importData.isNotImported;
|
||||
}
|
||||
}
|
||||
var autoImportUri =
|
||||
isNotImported && libraryUri.isNotEmpty ? Uri.parse(libraryUri) : null;
|
||||
var autoImportUri = isNotImported && libraryUri.isNotEmpty
|
||||
? Uri.parse(libraryUri)
|
||||
: null;
|
||||
|
||||
return (
|
||||
detail: detail,
|
||||
@@ -757,43 +747,41 @@ String? _getDocumentation(
|
||||
var docs = _getDocsFromComputer(element, request);
|
||||
|
||||
var doc = removeDartDocDelimiters(docs?.full);
|
||||
var rawDoc =
|
||||
includeDocumentation == DocumentationPreference.full
|
||||
? doc
|
||||
: includeDocumentation == DocumentationPreference.summary
|
||||
? getDartDocSummary(docs?.summary)
|
||||
: null;
|
||||
var rawDoc = includeDocumentation == DocumentationPreference.full
|
||||
? doc
|
||||
: includeDocumentation == DocumentationPreference.summary
|
||||
? getDartDocSummary(docs?.summary)
|
||||
: null;
|
||||
return cleanDartdoc(rawDoc);
|
||||
}
|
||||
|
||||
/// Additional details about a completion that may be formatted differently
|
||||
/// depending on the client capabilities.
|
||||
typedef CompletionDetail =
|
||||
({
|
||||
/// Additional details to go in the details popup.
|
||||
///
|
||||
/// This is usually a full signature (with full parameters) and may also
|
||||
/// include whether the item is deprecated if the client did not support the
|
||||
/// native deprecated tag.
|
||||
String detail,
|
||||
typedef CompletionDetail = ({
|
||||
/// Additional details to go in the details popup.
|
||||
///
|
||||
/// This is usually a full signature (with full parameters) and may also
|
||||
/// include whether the item is deprecated if the client did not support the
|
||||
/// native deprecated tag.
|
||||
String detail,
|
||||
|
||||
/// Truncated parameters. Similar to [truncatedSignature] but does not
|
||||
/// include return types. Used in clients that cannot format signatures
|
||||
/// differently and is appended immediately after the completion label. The
|
||||
/// return type is omitted to reduce noise because this text is not subtle.
|
||||
String truncatedParams,
|
||||
/// Truncated parameters. Similar to [truncatedSignature] but does not
|
||||
/// include return types. Used in clients that cannot format signatures
|
||||
/// differently and is appended immediately after the completion label. The
|
||||
/// return type is omitted to reduce noise because this text is not subtle.
|
||||
String truncatedParams,
|
||||
|
||||
/// A signature with truncated params. Used for showing immediately after
|
||||
/// the completion label when it can be formatted differently.
|
||||
///
|
||||
/// () → String
|
||||
String truncatedSignature,
|
||||
/// A signature with truncated params. Used for showing immediately after
|
||||
/// the completion label when it can be formatted differently.
|
||||
///
|
||||
/// () → String
|
||||
String truncatedSignature,
|
||||
|
||||
/// The URI that will be auto-imported if this item is selected in a
|
||||
/// user-friendly string format (for example a relative path if for a `file:/`
|
||||
/// URI).
|
||||
Uri? autoImportUri,
|
||||
});
|
||||
/// The URI that will be auto-imported if this item is selected in a
|
||||
/// user-friendly string format (for example a relative path if for a `file:/`
|
||||
/// URI).
|
||||
Uri? autoImportUri,
|
||||
});
|
||||
|
||||
class _ElementDocumentation {
|
||||
final String full;
|
||||
|
||||
+5
-2
@@ -27,8 +27,11 @@ import 'package:meta/meta.dart';
|
||||
|
||||
typedef CodeActionWithPriority = ({CodeAction action, int priority});
|
||||
|
||||
typedef CodeActionWithPriorityAndIndex =
|
||||
({CodeAction action, int priority, int index});
|
||||
typedef CodeActionWithPriorityAndIndex = ({
|
||||
CodeAction action,
|
||||
int priority,
|
||||
int index,
|
||||
});
|
||||
|
||||
/// A base for classes that produce [CodeAction]s for the LSP handler.
|
||||
abstract class AbstractCodeActionsProducer
|
||||
|
||||
@@ -78,8 +78,9 @@ class AnalysisOptionsCodeActionsProducer extends AbstractCodeActionsProducer {
|
||||
|
||||
var contextRoot = session.analysisContext.contextRoot;
|
||||
var package = contextRoot.workspace.findPackageFor(optionsFile.path);
|
||||
var sdkVersionConstraint =
|
||||
(package is PubPackage) ? package.sdkVersionConstraint : null;
|
||||
var sdkVersionConstraint = (package is PubPackage)
|
||||
? package.sdkVersionConstraint
|
||||
: null;
|
||||
|
||||
var errors = analyzeAnalysisOptions(
|
||||
FileSource(optionsFile),
|
||||
|
||||
@@ -366,15 +366,10 @@ class _CodeActionSorter {
|
||||
var dedupedActions = _dedupeActions(actions, range.start);
|
||||
|
||||
// Add each index so we can do a stable sort on priority.
|
||||
var dedupedActionsWithIndex =
|
||||
dedupedActions.indexed.map((item) {
|
||||
var (index, action) = item;
|
||||
return (
|
||||
action: action.action,
|
||||
priority: action.priority,
|
||||
index: index,
|
||||
);
|
||||
}).toList();
|
||||
var dedupedActionsWithIndex = dedupedActions.indexed.map((item) {
|
||||
var (index, action) = item;
|
||||
return (action: action.action, priority: action.priority, index: index);
|
||||
}).toList();
|
||||
dedupedActionsWithIndex.sort(_compareCodeActions);
|
||||
|
||||
return dedupedActionsWithIndex.map((action) => action.action).toList();
|
||||
@@ -488,7 +483,7 @@ class _CodeActionSorter {
|
||||
return firstLiteral.edit != null
|
||||
? firstLiteral.edit == other.edit
|
||||
: firstLiteral.command != null &&
|
||||
firstLiteral.command == other.command;
|
||||
firstLiteral.command == other.command;
|
||||
});
|
||||
|
||||
// Build a new CodeAction that merges the diagnostics from each same
|
||||
|
||||
@@ -208,8 +208,9 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer {
|
||||
try {
|
||||
// If deduplicating the result only do the expensive "fix all in file"
|
||||
// calculation when we haven't before.
|
||||
Set<String>? skipAlreadyCalculatedIfNonNull =
|
||||
willBeDeduplicated ? {} : null;
|
||||
Set<String>? skipAlreadyCalculatedIfNonNull = willBeDeduplicated
|
||||
? {}
|
||||
: null;
|
||||
var workspace = DartChangeWorkspace(await server.currentSessions);
|
||||
CorrectionUtils? correctionUtils;
|
||||
for (var error in unitResult.diagnostics) {
|
||||
@@ -546,8 +547,12 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer {
|
||||
) {
|
||||
return allowCodeActionLiterals
|
||||
? CodeAction.t1(
|
||||
CodeActionLiteral(title: command.title, kind: kind, command: command),
|
||||
)
|
||||
CodeActionLiteral(
|
||||
title: command.title,
|
||||
kind: kind,
|
||||
command: command,
|
||||
),
|
||||
)
|
||||
: CodeAction.t2(command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,8 +106,9 @@ abstract class AbstractRefactorCommandHandler
|
||||
// inject their own user-provided names until LSP has some native
|
||||
// support:
|
||||
// https://github.com/microsoft/language-server-protocol/issues/764
|
||||
refactor.name =
|
||||
options != null ? options['name'] as String : 'NewWidget';
|
||||
refactor.name = options != null
|
||||
? options['name'] as String
|
||||
: 'NewWidget';
|
||||
return success(refactor);
|
||||
|
||||
case RefactoringKind.INLINE_LOCAL_VARIABLE:
|
||||
|
||||
@@ -76,10 +76,9 @@ abstract class AbstractFixAllInWorkspaceCommandHandler
|
||||
server,
|
||||
clientCapabilities,
|
||||
change,
|
||||
annotateChanges:
|
||||
requireConfirmation
|
||||
? ChangeAnnotations.requireConfirmation
|
||||
: ChangeAnnotations.include,
|
||||
annotateChanges: requireConfirmation
|
||||
? ChangeAnnotations.requireConfirmation
|
||||
: ChangeAnnotations.include,
|
||||
);
|
||||
return sendWorkspaceEditToClient(edit);
|
||||
}
|
||||
|
||||
+14
-16
@@ -12,18 +12,17 @@ import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/flutter.dart';
|
||||
|
||||
/// Information about the arguments and parameters for an invocation.
|
||||
typedef EditableInvocationInfo =
|
||||
({
|
||||
AstNode invocation,
|
||||
String? widgetName,
|
||||
String? widgetDocumentation,
|
||||
List<FormalParameterElement> parameters,
|
||||
Map<FormalParameterElement, Expression> parameterArguments,
|
||||
Map<FormalParameterElement, int> positionalParameterIndexes,
|
||||
ArgumentList argumentList,
|
||||
int numPositionals,
|
||||
int numSuppliedPositionals,
|
||||
});
|
||||
typedef EditableInvocationInfo = ({
|
||||
AstNode invocation,
|
||||
String? widgetName,
|
||||
String? widgetDocumentation,
|
||||
List<FormalParameterElement> parameters,
|
||||
Map<FormalParameterElement, Expression> parameterArguments,
|
||||
Map<FormalParameterElement, int> positionalParameterIndexes,
|
||||
ArgumentList argumentList,
|
||||
int numPositionals,
|
||||
int numSuppliedPositionals,
|
||||
});
|
||||
|
||||
mixin EditableArgumentsMixin {
|
||||
DartdocDirectiveInfo getDartdocDirectiveInfoFor(ResolvedUnitResult result);
|
||||
@@ -115,10 +114,9 @@ mixin EditableArgumentsMixin {
|
||||
}
|
||||
|
||||
var numPositionals = parameters.where((p) => p.isPositional).length;
|
||||
var numSuppliedPositionals =
|
||||
argumentList.arguments
|
||||
.where((argument) => argument is! NamedExpression)
|
||||
.length;
|
||||
var numSuppliedPositionals = argumentList.arguments
|
||||
.where((argument) => argument is! NamedExpression)
|
||||
.length;
|
||||
|
||||
// Build a map of parameters to their positional index so we can tell
|
||||
// whether a parameter that doesn't already have an argument will be
|
||||
|
||||
+19
-19
@@ -116,8 +116,9 @@ class EditArgumentHandler extends SharedMessageHandler<EditArgumentParams, Null>
|
||||
}
|
||||
|
||||
var argument = parameterArguments[parameter];
|
||||
var valueExpression =
|
||||
argument is NamedExpression ? argument.expression : argument;
|
||||
var valueExpression = argument is NamedExpression
|
||||
? argument.expression
|
||||
: argument;
|
||||
|
||||
// Determine whether a value for this parameter is editable.
|
||||
var notEditableReason = getNotEditableReason(
|
||||
@@ -179,10 +180,9 @@ class EditArgumentHandler extends SharedMessageHandler<EditArgumentParams, Null>
|
||||
currentArgument is SimpleIdentifier ||
|
||||
currentArgument == null;
|
||||
|
||||
var enumValue =
|
||||
preferDotShorthand
|
||||
? getDotShorthandEnumConstantName(enumConstant) ?? requestValue
|
||||
: requestValue;
|
||||
var enumValue = preferDotShorthand
|
||||
? getDotShorthandEnumConstantName(enumConstant) ?? requestValue
|
||||
: requestValue;
|
||||
|
||||
return enumValue.toString();
|
||||
}
|
||||
@@ -294,11 +294,10 @@ class EditArgumentHandler extends SharedMessageHandler<EditArgumentParams, Null>
|
||||
// It is a bug if we produced edits in some file other than the one we
|
||||
// expect.
|
||||
var fileEdits = changeBuilder.sourceChange.edits;
|
||||
var otherFilesEdited =
|
||||
fileEdits
|
||||
.map((edit) => edit.file)
|
||||
.where((file) => file != result.path)
|
||||
.toSet();
|
||||
var otherFilesEdited = fileEdits
|
||||
.map((edit) => edit.file)
|
||||
.where((file) => file != result.path)
|
||||
.toSet();
|
||||
if (otherFilesEdited.isNotEmpty) {
|
||||
var otherNames = otherFilesEdited.join(', ');
|
||||
throw 'Argument edit for ${result.path} unexpectedly produced edits for $otherNames';
|
||||
@@ -405,8 +404,9 @@ class EditArgumentHandler extends SharedMessageHandler<EditArgumentParams, Null>
|
||||
// If this parameter is positional, we need to first ensure arguments for
|
||||
// any earlier positional parameters are present.
|
||||
if (parameter.isPositional) {
|
||||
var existingPositionalArguments =
|
||||
argumentList.arguments.where((a) => a is! NamedExpression).length;
|
||||
var existingPositionalArguments = argumentList.arguments
|
||||
.where((a) => a is! NamedExpression)
|
||||
.length;
|
||||
var unspecifiedPositionals = parameters
|
||||
.where((p) => p.isPositional)
|
||||
.skip(existingPositionalArguments)
|
||||
@@ -422,8 +422,9 @@ class EditArgumentHandler extends SharedMessageHandler<EditArgumentParams, Null>
|
||||
}
|
||||
|
||||
var parameterName = parameter.name;
|
||||
var argumentNamePrefix =
|
||||
parameter.isNamed && parameterName != null ? '$parameterName: ' : '';
|
||||
var argumentNamePrefix = parameter.isNamed && parameterName != null
|
||||
? '$parameterName: '
|
||||
: '';
|
||||
var argumentCode = '$argumentNamePrefix$newValueCode';
|
||||
|
||||
// Usually we insert at the end (after the last argument), but if the last
|
||||
@@ -447,10 +448,9 @@ class EditArgumentHandler extends SharedMessageHandler<EditArgumentParams, Null>
|
||||
lineInfo.getLocation(argumentList.rightParenthesis.offset).lineNumber;
|
||||
|
||||
// If we are multiline, indent one level more than the invocation.
|
||||
var indent =
|
||||
isMultiline
|
||||
? '${utils.getLinePrefix(argumentList.leftParenthesis.offset)} '
|
||||
: '';
|
||||
var indent = isMultiline
|
||||
? '${utils.getLinePrefix(argumentList.leftParenthesis.offset)} '
|
||||
: '';
|
||||
|
||||
// The prefix we need depends on whether there is an argument before us
|
||||
// and whether we are multiline.
|
||||
|
||||
+3
-2
@@ -161,8 +161,9 @@ class EditableArgumentsHandler
|
||||
required int numPositionals,
|
||||
required int numSuppliedPositionals,
|
||||
}) {
|
||||
var valueExpression =
|
||||
argument is NamedExpression ? argument.expression : argument;
|
||||
var valueExpression = argument is NamedExpression
|
||||
? argument.expression
|
||||
: argument;
|
||||
|
||||
// Lazily compute the values if we will use this parameter/argument.
|
||||
late var values = _getValues(parameter, valueExpression);
|
||||
|
||||
@@ -40,10 +40,9 @@ class AugmentationHandler
|
||||
|
||||
return (unit, offset).mapResultsSync((unit, offset) {
|
||||
// Find the nearest node that could have fragments.
|
||||
var node =
|
||||
unit.unit
|
||||
.nodeCovering(offset: offset)
|
||||
?.thisOrAncestorOfType<ast.Declaration>();
|
||||
var node = unit.unit
|
||||
.nodeCovering(offset: offset)
|
||||
?.thisOrAncestorOfType<ast.Declaration>();
|
||||
|
||||
var location = fragmentToLocation(
|
||||
uriConverter,
|
||||
|
||||
@@ -40,10 +40,9 @@ class AugmentedHandler
|
||||
|
||||
return (unit, offset).mapResultsSync((unit, offset) {
|
||||
// Find the nearest node that could have fragments.
|
||||
var node =
|
||||
unit.unit
|
||||
.nodeCovering(offset: offset)
|
||||
?.thisOrAncestorOfType<ast.Declaration>();
|
||||
var node = unit.unit
|
||||
.nodeCovering(offset: offset)
|
||||
?.thisOrAncestorOfType<ast.Declaration>();
|
||||
|
||||
var location = fragmentToLocation(
|
||||
uriConverter,
|
||||
|
||||
+3
-4
@@ -39,10 +39,9 @@ class DartTextDocumentContentProviderHandler
|
||||
var uri = params.uri;
|
||||
|
||||
if (!allowedSchemes.contains(uri.scheme)) {
|
||||
var supportedSchemesString =
|
||||
allowedSchemes.isEmpty
|
||||
? '(none)'
|
||||
: allowedSchemes.map((scheme) => "'$scheme'").join(', ');
|
||||
var supportedSchemesString = allowedSchemes.isEmpty
|
||||
? '(none)'
|
||||
: allowedSchemes.map((scheme) => "'$scheme'").join(', ');
|
||||
return error(
|
||||
ErrorCodes.InvalidParams,
|
||||
"Fetching content for scheme '${uri.scheme}' is not supported. "
|
||||
|
||||
@@ -49,9 +49,9 @@ class ImportsHandler
|
||||
return unit != null
|
||||
? success(unit)
|
||||
: error(
|
||||
ErrorCodes.InternalError,
|
||||
'The library containing a path did not contain the path.',
|
||||
);
|
||||
ErrorCodes.InternalError,
|
||||
'The library containing a path did not contain the path.',
|
||||
);
|
||||
});
|
||||
var offset = unit.mapResultSync(
|
||||
(unit) => toOffset(unit.unit.lineInfo, pos),
|
||||
@@ -143,15 +143,13 @@ class ImportsHandler
|
||||
var importPrefix = directive.prefix?.name;
|
||||
if (importPrefix != prefix) continue;
|
||||
|
||||
var importedElement =
|
||||
prefix == null
|
||||
? import.namespace.get2(elementName)
|
||||
: import.namespace.getPrefixed2(prefix, elementName);
|
||||
var importedElement = prefix == null
|
||||
? import.namespace.get2(elementName)
|
||||
: import.namespace.getPrefixed2(prefix, elementName);
|
||||
|
||||
var isMatch =
|
||||
element is MultiplyDefinedElement
|
||||
? element.conflictingElements.contains(importedElement)
|
||||
: element == importedElement;
|
||||
var isMatch = element is MultiplyDefinedElement
|
||||
? element.conflictingElements.contains(importedElement)
|
||||
: element == importedElement;
|
||||
|
||||
if (isMatch) {
|
||||
var uri = uriConverter.toClientUri(
|
||||
|
||||
@@ -540,7 +540,8 @@ extension on DirectiveUri {
|
||||
DirectiveUriWithLibrary(:var source) => source.uri.toString(),
|
||||
DirectiveUriWithRelativeUriString(:var relativeUriString) =>
|
||||
relativeUriString,
|
||||
DirectiveUri() =>
|
||||
throw UnimplementedError('Unhandled instance of type $runtimeType'),
|
||||
DirectiveUri() => throw UnimplementedError(
|
||||
'Unhandled instance of type $runtimeType',
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -101,13 +101,12 @@ class IncomingCallHierarchyHandler
|
||||
itemLineInfo,
|
||||
supportedSymbolKinds: supportedSymbolKinds,
|
||||
),
|
||||
fromRanges:
|
||||
calls.ranges
|
||||
// For incoming calls, ranges are in the referenced item so we use
|
||||
// itemLineInfo and not localLineInfo (which is for the original
|
||||
// target we're collecting calls to).
|
||||
.map((call) => sourceRangeToRange(itemLineInfo, call))
|
||||
.toList(),
|
||||
fromRanges: calls.ranges
|
||||
// For incoming calls, ranges are in the referenced item so we use
|
||||
// itemLineInfo and not localLineInfo (which is for the original
|
||||
// target we're collecting calls to).
|
||||
.map((call) => sourceRangeToRange(itemLineInfo, call))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -174,13 +173,12 @@ class OutgoingCallHierarchyHandler
|
||||
itemLineInfo,
|
||||
supportedSymbolKinds: supportedSymbolKinds,
|
||||
),
|
||||
fromRanges:
|
||||
calls.ranges
|
||||
// For incoming calls, ranges are in original target so we use
|
||||
// localLineInfo and not itemLineInfo (which is for call target
|
||||
// the outbound call points to).
|
||||
.map((call) => sourceRangeToRange(localLineInfo, call))
|
||||
.toList(),
|
||||
fromRanges: calls.ranges
|
||||
// For incoming calls, ranges are in original target so we use
|
||||
// localLineInfo and not itemLineInfo (which is for call target
|
||||
// the outbound call points to).
|
||||
.map((call) => sourceRangeToRange(localLineInfo, call))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,9 @@ class CodeActionHandler
|
||||
}
|
||||
|
||||
var supportsLiterals = callerCapabilities.literalCodeActions;
|
||||
var supportedKinds =
|
||||
supportsLiterals ? callerCapabilities.codeActionKinds : null;
|
||||
var supportedKinds = supportsLiterals
|
||||
? callerCapabilities.codeActionKinds
|
||||
: null;
|
||||
|
||||
var computer = CodeActionComputer(
|
||||
server,
|
||||
@@ -86,12 +87,12 @@ class CodeActionRegistrations extends FeatureRegistration
|
||||
// signals code action literal support via the property
|
||||
// `textDocument.codeAction.codeActionLiteralSupport`."
|
||||
codeActionLiteralSupport
|
||||
? Either2.t2(
|
||||
CodeActionOptions(
|
||||
codeActionKinds: DartCodeActionKind.serverSupportedKinds,
|
||||
),
|
||||
)
|
||||
: Either2.t1(true);
|
||||
? Either2.t2(
|
||||
CodeActionOptions(
|
||||
codeActionKinds: DartCodeActionKind.serverSupportedKinds,
|
||||
),
|
||||
)
|
||||
: Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.codeActions;
|
||||
|
||||
@@ -71,10 +71,9 @@ class CompletionHandler
|
||||
: suggestFromUnimportedLibraries =
|
||||
server.initializationOptions?.suggestFromUnimportedLibraries ?? true {
|
||||
var budgetMs = server.initializationOptions?.completionBudgetMilliseconds;
|
||||
completionBudgetDuration =
|
||||
budgetMs != null
|
||||
? Duration(milliseconds: budgetMs)
|
||||
: CompletionBudget.defaultDuration;
|
||||
completionBudgetDuration = budgetMs != null
|
||||
? Duration(milliseconds: budgetMs)
|
||||
: CompletionBudget.defaultDuration;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -148,8 +147,9 @@ class CompletionHandler
|
||||
offset,
|
||||
) async {
|
||||
var fileExtension = pathContext.extension(path);
|
||||
var maxResults =
|
||||
server.lspClientConfiguration.forResource(path).maxCompletionItems;
|
||||
var maxResults = server.lspClientConfiguration
|
||||
.forResource(path)
|
||||
.maxCompletionItems;
|
||||
CompletionPerformance? completionPerformance;
|
||||
Future<ErrorOr<_CompletionResults>>? serverResultsFuture;
|
||||
if (fileExtension == '.dart') {
|
||||
@@ -216,18 +216,17 @@ class CompletionHandler
|
||||
var maxRankedItems = math.max(maxResults - unrankedItems.length, 0);
|
||||
var truncatedRankedItems =
|
||||
untruncatedRankedItems.length <= maxRankedItems
|
||||
? untruncatedRankedItems
|
||||
: _truncateResults(
|
||||
untruncatedRankedItems,
|
||||
serverResults.targetPrefix,
|
||||
maxRankedItems,
|
||||
);
|
||||
? untruncatedRankedItems
|
||||
: _truncateResults(
|
||||
untruncatedRankedItems,
|
||||
serverResults.targetPrefix,
|
||||
maxRankedItems,
|
||||
);
|
||||
|
||||
var truncatedItems =
|
||||
truncatedRankedItems
|
||||
.map((item) => item.item)
|
||||
.followedBy(unrankedItems)
|
||||
.toList();
|
||||
var truncatedItems = truncatedRankedItems
|
||||
.map((item) => item.item)
|
||||
.followedBy(unrankedItems)
|
||||
.toList();
|
||||
|
||||
// If we're tracing performance (only Dart), record the number of results
|
||||
// after truncation.
|
||||
@@ -263,8 +262,9 @@ class CompletionHandler
|
||||
}
|
||||
|
||||
return CompletionItemDefaults(
|
||||
insertTextMode:
|
||||
capabilities.completionDefaultTextMode ? InsertTextMode.asIs : null,
|
||||
insertTextMode: capabilities.completionDefaultTextMode
|
||||
? InsertTextMode.asIs
|
||||
: null,
|
||||
editRange: _computeDefaultEditRange(
|
||||
capabilities,
|
||||
insertionRange,
|
||||
@@ -541,10 +541,9 @@ class CompletionHandler
|
||||
resolutionData: resolutionInfo,
|
||||
// Exclude docs if we will be providing them via
|
||||
// `completionItem/resolve`, otherwise use users preference.
|
||||
includeDocumentation:
|
||||
resolutionInfo != null
|
||||
? DocumentationPreference.none
|
||||
: server.lspClientConfiguration.global.preferredDocumentation,
|
||||
includeDocumentation: resolutionInfo != null
|
||||
? DocumentationPreference.none
|
||||
: server.lspClientConfiguration.global.preferredDocumentation,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -562,8 +561,9 @@ class CompletionHandler
|
||||
});
|
||||
|
||||
// Add in any snippets.
|
||||
var snippetsEnabled =
|
||||
server.lspClientConfiguration.forResource(unit.path).enableSnippets;
|
||||
var snippetsEnabled = server.lspClientConfiguration
|
||||
.forResource(unit.path)
|
||||
.enableSnippets;
|
||||
// We can only produce edits with edit builders for files inside
|
||||
// the root, so skip snippets entirely if not.
|
||||
var isEditableFile = unit.session.analysisContext.contextRoot.isAnalyzed(
|
||||
@@ -658,47 +658,41 @@ class CompletionHandler
|
||||
var fuzzyPattern = suggestions.targetPrefix;
|
||||
var fuzzyMatcher = FuzzyMatcher(fuzzyPattern);
|
||||
|
||||
var completionItems =
|
||||
suggestions.suggestions
|
||||
.where(
|
||||
(item) =>
|
||||
fuzzyMatcher.score(item.displayText ?? item.completion) > 0,
|
||||
)
|
||||
.map((item) {
|
||||
var resolutionInfo =
|
||||
item.kind == CompletionSuggestionKind.PACKAGE_NAME
|
||||
? PubPackageCompletionItemResolutionInfo(
|
||||
// The completion for package names may contain a trailing
|
||||
// ': ' for convenience, so if it's there, trim it off.
|
||||
packageName: item.completion.split(':').first,
|
||||
)
|
||||
: null;
|
||||
return toCompletionItem(
|
||||
capabilities,
|
||||
lineInfo,
|
||||
item,
|
||||
uriConverter: uriConverter,
|
||||
pathContext: pathContext,
|
||||
completionFilePath: filePath,
|
||||
replacementRange: replacementRange,
|
||||
insertionRange: insertionRange,
|
||||
commitCharactersEnabled: false,
|
||||
completeFunctionCalls: false,
|
||||
// Exclude docs if we could provide them via
|
||||
// `completionItem/resolve`, otherwise use users preference.
|
||||
includeDocumentation:
|
||||
resolutionInfo != null
|
||||
? DocumentationPreference.none
|
||||
: server
|
||||
.lspClientConfiguration
|
||||
.global
|
||||
.preferredDocumentation,
|
||||
// Add on any completion-kind-specific resolution data that will be
|
||||
// used during resolve() calls to provide additional information.
|
||||
resolutionData: resolutionInfo,
|
||||
);
|
||||
})
|
||||
.toList();
|
||||
var completionItems = suggestions.suggestions
|
||||
.where(
|
||||
(item) => fuzzyMatcher.score(item.displayText ?? item.completion) > 0,
|
||||
)
|
||||
.map((item) {
|
||||
var resolutionInfo =
|
||||
item.kind == CompletionSuggestionKind.PACKAGE_NAME
|
||||
? PubPackageCompletionItemResolutionInfo(
|
||||
// The completion for package names may contain a trailing
|
||||
// ': ' for convenience, so if it's there, trim it off.
|
||||
packageName: item.completion.split(':').first,
|
||||
)
|
||||
: null;
|
||||
return toCompletionItem(
|
||||
capabilities,
|
||||
lineInfo,
|
||||
item,
|
||||
uriConverter: uriConverter,
|
||||
pathContext: pathContext,
|
||||
completionFilePath: filePath,
|
||||
replacementRange: replacementRange,
|
||||
insertionRange: insertionRange,
|
||||
commitCharactersEnabled: false,
|
||||
completeFunctionCalls: false,
|
||||
// Exclude docs if we could provide them via
|
||||
// `completionItem/resolve`, otherwise use users preference.
|
||||
includeDocumentation: resolutionInfo != null
|
||||
? DocumentationPreference.none
|
||||
: server.lspClientConfiguration.global.preferredDocumentation,
|
||||
// Add on any completion-kind-specific resolution data that will be
|
||||
// used during resolve() calls to provide additional information.
|
||||
resolutionData: resolutionInfo,
|
||||
);
|
||||
})
|
||||
.toList();
|
||||
return success(
|
||||
_CompletionResults.unranked(completionItems, isIncomplete: false),
|
||||
);
|
||||
@@ -784,12 +778,10 @@ class CompletionHandler
|
||||
|
||||
// Skip the text comparisons if we don't have a prefix (plugin results, or
|
||||
// just no prefix when completion was invoked).
|
||||
var shouldInclude =
|
||||
prefixLower.isEmpty
|
||||
? (int index, _ScoredCompletionItem item) =>
|
||||
index < maxCompletionCount
|
||||
: (int index, _ScoredCompletionItem item) =>
|
||||
index < maxCompletionCount || isExactMatch(item.item);
|
||||
var shouldInclude = prefixLower.isEmpty
|
||||
? (int index, _ScoredCompletionItem item) => index < maxCompletionCount
|
||||
: (int index, _ScoredCompletionItem item) =>
|
||||
index < maxCompletionCount || isExactMatch(item.item);
|
||||
|
||||
return items.whereIndexed(shouldInclude);
|
||||
}
|
||||
@@ -851,8 +843,9 @@ class CompletionRegistrations extends FeatureRegistration
|
||||
CompletionRegistrationOptions(
|
||||
documentSelector: dartFiles,
|
||||
triggerCharacters: dartCompletionTriggerCharacters,
|
||||
allCommitCharacters:
|
||||
previewCommitCharacters ? dartCompletionCommitCharacters : null,
|
||||
allCommitCharacters: previewCommitCharacters
|
||||
? dartCompletionCommitCharacters
|
||||
: null,
|
||||
resolveProvider: true,
|
||||
completionItem: ServerCompletionItemOptions(
|
||||
labelDetailsSupport: true,
|
||||
@@ -892,8 +885,9 @@ class CompletionRegistrations extends FeatureRegistration
|
||||
@override
|
||||
CompletionOptions get staticOptions => CompletionOptions(
|
||||
triggerCharacters: dartCompletionTriggerCharacters,
|
||||
allCommitCharacters:
|
||||
previewCommitCharacters ? dartCompletionCommitCharacters : null,
|
||||
allCommitCharacters: previewCommitCharacters
|
||||
? dartCompletionCommitCharacters
|
||||
: null,
|
||||
resolveProvider: true,
|
||||
completionItem: ServerCompletionItemOptions(labelDetailsSupport: true),
|
||||
);
|
||||
|
||||
@@ -87,12 +87,9 @@ class CompletionResolveHandler
|
||||
return cancelled(token);
|
||||
}
|
||||
|
||||
var element =
|
||||
elementReference != null
|
||||
? await ElementLocation.decode(
|
||||
elementReference,
|
||||
).locateIn(session)
|
||||
: null;
|
||||
var element = elementReference != null
|
||||
? await ElementLocation.decode(elementReference).locateIn(session)
|
||||
: null;
|
||||
|
||||
var showName = element?.name;
|
||||
if (element?.enclosingElement case InstanceElement(:var name)) {
|
||||
@@ -111,10 +108,12 @@ class CompletionResolveHandler
|
||||
}
|
||||
|
||||
var changes = builder.sourceChange;
|
||||
var thisFilesChanges =
|
||||
changes.edits.where((e) => e.file == file).toList();
|
||||
var otherFilesChanges =
|
||||
changes.edits.where((e) => e.file != file).toList();
|
||||
var thisFilesChanges = changes.edits
|
||||
.where((e) => e.file == file)
|
||||
.toList();
|
||||
var otherFilesChanges = changes.edits
|
||||
.where((e) => e.file != file)
|
||||
.toList();
|
||||
|
||||
// If this completion involves editing other files, we'll need to build
|
||||
// a command that the client will call to apply those edits later.
|
||||
@@ -145,10 +144,9 @@ class CompletionResolveHandler
|
||||
server.lspClientConfiguration.global.preferredDocumentation,
|
||||
);
|
||||
// `dartDoc` can be both null or empty.
|
||||
documentation =
|
||||
dartDoc != null && dartDoc.isNotEmpty
|
||||
? asMarkupContentOrString(formats, dartDoc)
|
||||
: null;
|
||||
documentation = dartDoc != null && dartDoc.isNotEmpty
|
||||
? asMarkupContentOrString(formats, dartDoc)
|
||||
: null;
|
||||
}
|
||||
|
||||
String? detail = item.detail;
|
||||
@@ -185,14 +183,13 @@ class CompletionResolveHandler
|
||||
insertTextFormat: item.insertTextFormat,
|
||||
insertTextMode: item.insertTextMode,
|
||||
textEdit: item.textEdit,
|
||||
additionalTextEdits:
|
||||
thisFilesChanges
|
||||
.expand(
|
||||
(change) => sortSourceEditsForLsp(
|
||||
change.edits,
|
||||
).map((edit) => toTextEdit(result.lineInfo, edit)),
|
||||
)
|
||||
.toList(),
|
||||
additionalTextEdits: thisFilesChanges
|
||||
.expand(
|
||||
(change) => sortSourceEditsForLsp(
|
||||
change.edits,
|
||||
).map((edit) => toTextEdit(result.lineInfo, edit)),
|
||||
)
|
||||
.toList(),
|
||||
commitCharacters: item.commitCharacters,
|
||||
command: command ?? item.command,
|
||||
data: item.data,
|
||||
@@ -233,10 +230,9 @@ class CompletionResolveHandler
|
||||
kind: item.kind,
|
||||
tags: item.tags,
|
||||
detail: item.detail,
|
||||
documentation:
|
||||
description != null
|
||||
? Either2<MarkupContent, String>.t2(description)
|
||||
: null,
|
||||
documentation: description != null
|
||||
? Either2<MarkupContent, String>.t2(description)
|
||||
: null,
|
||||
deprecated: item.deprecated,
|
||||
preselect: item.preselect,
|
||||
sortText: item.sortText,
|
||||
|
||||
@@ -156,12 +156,11 @@ class DefinitionHandler
|
||||
// Convert and filter the results using the correct type of Location class
|
||||
// depending on the client capabilities.
|
||||
if (supportsLocationLink) {
|
||||
var convertedResults =
|
||||
convert(
|
||||
mergedTargets,
|
||||
(NavigationTarget target) =>
|
||||
_toLocationLink(mergedResults, lineInfo, target),
|
||||
).nonNulls.toList();
|
||||
var convertedResults = convert(
|
||||
mergedTargets,
|
||||
(NavigationTarget target) =>
|
||||
_toLocationLink(mergedResults, lineInfo, target),
|
||||
).nonNulls.toList();
|
||||
|
||||
var results = _filterResults(
|
||||
convertedResults,
|
||||
@@ -173,11 +172,10 @@ class DefinitionHandler
|
||||
|
||||
return success(TextDocumentDefinitionResult.t2(results));
|
||||
} else {
|
||||
var convertedResults =
|
||||
convert(
|
||||
mergedTargets,
|
||||
(NavigationTarget target) => _toLocation(mergedResults, target),
|
||||
).nonNulls.toList();
|
||||
var convertedResults = convert(
|
||||
mergedTargets,
|
||||
(NavigationTarget target) => _toLocation(mergedResults, target),
|
||||
).nonNulls.toList();
|
||||
|
||||
var results = _filterResults(
|
||||
convertedResults,
|
||||
@@ -210,14 +208,13 @@ class DefinitionHandler
|
||||
// adjacent to the var keyword, so providing navigation to it is not useful).
|
||||
// To prevent this, filter the list to only those on different lines (or
|
||||
// different files).
|
||||
var otherResults =
|
||||
results
|
||||
.where(
|
||||
(element) =>
|
||||
uriSelector(element) != sourceUri ||
|
||||
rangeSelector(element).start.line != sourceLineNumber,
|
||||
)
|
||||
.toList();
|
||||
var otherResults = results
|
||||
.where(
|
||||
(element) =>
|
||||
uriSelector(element) != sourceUri ||
|
||||
rangeSelector(element).start.line != sourceLineNumber,
|
||||
)
|
||||
.toList();
|
||||
|
||||
return otherResults.isNotEmpty ? otherResults : results;
|
||||
}
|
||||
@@ -306,12 +303,12 @@ class DefinitionHandler
|
||||
|
||||
return targetLineInfo != null
|
||||
? navigationTargetToLocationLink(
|
||||
region,
|
||||
sourceLineInfo,
|
||||
targetFileUri,
|
||||
target,
|
||||
targetLineInfo,
|
||||
)
|
||||
region,
|
||||
sourceLineInfo,
|
||||
targetFileUri,
|
||||
target,
|
||||
targetLineInfo,
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,10 @@ class DocumentColorPresentationHandler
|
||||
// We can only apply changes to the same file, so filter any change from the
|
||||
// builder to only include this file, otherwise we may corrupt the users
|
||||
// source (although hopefully we don't produce edits for other files).
|
||||
var editsForThisFile =
|
||||
builder.sourceChange.edits
|
||||
.where((edit) => edit.file == unit.path)
|
||||
.expand((edit) => edit.edits)
|
||||
.toList();
|
||||
var editsForThisFile = builder.sourceChange.edits
|
||||
.where((edit) => edit.file == unit.path)
|
||||
.expand((edit) => edit.edits)
|
||||
.toList();
|
||||
|
||||
// LSP requires that we separate the main edit (changing the color code)
|
||||
// from anything else (imports).
|
||||
@@ -107,12 +106,9 @@ class DocumentColorPresentationHandler
|
||||
return ColorPresentation(
|
||||
label: '$typeName$invocationString',
|
||||
textEdit: toTextEdit(unit.lineInfo, mainEdit),
|
||||
additionalTextEdits:
|
||||
otherEdits.isNotEmpty
|
||||
? otherEdits
|
||||
.map((edit) => toTextEdit(unit.lineInfo, edit))
|
||||
.toList()
|
||||
: null,
|
||||
additionalTextEdits: otherEdits.isNotEmpty
|
||||
? otherEdits.map((edit) => toTextEdit(unit.lineInfo, edit)).toList()
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -245,8 +241,9 @@ class DocumentColorPresentationHandler
|
||||
return node.isConst;
|
||||
} else if (node is SimpleIdentifier) {
|
||||
var parent = node.parent;
|
||||
var element =
|
||||
parent is PrefixedIdentifier ? parent.element : node.element;
|
||||
var element = parent is PrefixedIdentifier
|
||||
? parent.element
|
||||
: node.element;
|
||||
|
||||
return switch (element) {
|
||||
PropertyAccessorElement(:var variable) => variable.isConst,
|
||||
|
||||
@@ -71,14 +71,13 @@ class DocumentHighlightsHandler
|
||||
|
||||
// No matches will return an empty list (not null) because that prevents
|
||||
// the editor falling back to a text search.
|
||||
var highlights =
|
||||
matchingSet
|
||||
.map(
|
||||
(token) => DocumentHighlight(
|
||||
range: toRange(unit.lineInfo, token.offset, token.length),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
var highlights = matchingSet
|
||||
.map(
|
||||
(token) => DocumentHighlight(
|
||||
range: toRange(unit.lineInfo, token.offset, token.length),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
return success(highlights);
|
||||
});
|
||||
|
||||
@@ -57,10 +57,9 @@ class DocumentSymbolHandler
|
||||
) {
|
||||
var codeRange = toRange(lineInfo, outline.codeOffset, outline.codeLength);
|
||||
var nameLocation = outline.element.location;
|
||||
var nameRange =
|
||||
nameLocation != null
|
||||
? toRange(lineInfo, nameLocation.offset, nameLocation.length)
|
||||
: null;
|
||||
var nameRange = nameLocation != null
|
||||
? toRange(lineInfo, nameLocation.offset, nameLocation.length)
|
||||
: null;
|
||||
return DocumentSymbol(
|
||||
name: toElementName(outline.element),
|
||||
detail: outline.element.parameters,
|
||||
@@ -68,12 +67,9 @@ class DocumentSymbolHandler
|
||||
deprecated: outline.element.isDeprecated,
|
||||
range: codeRange,
|
||||
selectionRange: nameRange ?? codeRange,
|
||||
children:
|
||||
outline.children
|
||||
?.map(
|
||||
(child) => _asDocumentSymbol(supportedKinds, lineInfo, child),
|
||||
)
|
||||
.toList(),
|
||||
children: outline.children
|
||||
?.map((child) => _asDocumentSymbol(supportedKinds, lineInfo, child))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,14 +98,13 @@ class ExecuteCommandHandler
|
||||
var workDoneToken = params.workDoneToken;
|
||||
ProgressReporter progress = ProgressReporter.noop;
|
||||
if (server case LspAnalysisServer server) {
|
||||
progress =
|
||||
workDoneToken != null
|
||||
? ProgressReporter.clientProvided(server, workDoneToken)
|
||||
// Use editor client capabilities, as that's who gets progress
|
||||
// notifications, not the caller.
|
||||
: server.editorClientCapabilities?.workDoneProgress ?? false
|
||||
? ProgressReporter.serverCreated(server)
|
||||
: ProgressReporter.noop;
|
||||
progress = workDoneToken != null
|
||||
? ProgressReporter.clientProvided(server, workDoneToken)
|
||||
// Use editor client capabilities, as that's who gets progress
|
||||
// notifications, not the caller.
|
||||
: server.editorClientCapabilities?.workDoneProgress ?? false
|
||||
? ProgressReporter.serverCreated(server)
|
||||
: ProgressReporter.noop;
|
||||
}
|
||||
|
||||
// To make passing arguments easier in commands, instead of a
|
||||
|
||||
@@ -73,16 +73,12 @@ class FoldingHandler
|
||||
// line mode below.
|
||||
regions.sort((r1, r2) => r1.offset.compareTo(r2.offset));
|
||||
|
||||
var foldingRanges =
|
||||
regions
|
||||
.map(
|
||||
(region) => _toFoldingRange(
|
||||
lineInfo!,
|
||||
region,
|
||||
lineOnly: lineFoldingOnly,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
var foldingRanges = regions
|
||||
.map(
|
||||
(region) =>
|
||||
_toFoldingRange(lineInfo!, region, lineOnly: lineFoldingOnly),
|
||||
)
|
||||
.toList();
|
||||
|
||||
// When in line-only mode, ranges that end on the same line that another
|
||||
// ranges starts should be truncated to be on the line before (and if this
|
||||
|
||||
@@ -88,13 +88,12 @@ class FormatOnTypeRegistrations extends FeatureRegistration
|
||||
Method get registrationMethod => Method.textDocument_onTypeFormatting;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions =>
|
||||
enableFormatter
|
||||
? DocumentOnTypeFormattingOptions(
|
||||
firstTriggerCharacter: dartTypeFormattingCharacters.first,
|
||||
moreTriggerCharacter: dartTypeFormattingCharacters.skip(1).toList(),
|
||||
)
|
||||
: null;
|
||||
StaticOptions get staticOptions => enableFormatter
|
||||
? DocumentOnTypeFormattingOptions(
|
||||
firstTriggerCharacter: dartTypeFormattingCharacters.first,
|
||||
moreTriggerCharacter: dartTypeFormattingCharacters.skip(1).toList(),
|
||||
)
|
||||
: null;
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => enableFormatter && clientDynamic.typeFormatting;
|
||||
|
||||
@@ -87,44 +87,37 @@ class ImplementationHandler
|
||||
|
||||
var locations = performance.run(
|
||||
'filter and get location',
|
||||
(_) =>
|
||||
allSubtypes
|
||||
.map((element) {
|
||||
return needsMember
|
||||
// Filter based on type, so when searching for members we don't
|
||||
// include any intermediate classes that don't have
|
||||
// implementations for the method.
|
||||
? helper.findMemberElement(element)?.nonSynthetic
|
||||
: element;
|
||||
})
|
||||
.nonNulls
|
||||
.toSet()
|
||||
.map((element) {
|
||||
var firstFragment = element.firstFragment;
|
||||
var libraryFragment = firstFragment.libraryFragment;
|
||||
if (libraryFragment == null) {
|
||||
return null;
|
||||
}
|
||||
(_) => allSubtypes
|
||||
.map((element) {
|
||||
return needsMember
|
||||
// Filter based on type, so when searching for members we don't
|
||||
// include any intermediate classes that don't have
|
||||
// implementations for the method.
|
||||
? helper.findMemberElement(element)?.nonSynthetic
|
||||
: element;
|
||||
})
|
||||
.nonNulls
|
||||
.toSet()
|
||||
.map((element) {
|
||||
var firstFragment = element.firstFragment;
|
||||
var libraryFragment = firstFragment.libraryFragment;
|
||||
if (libraryFragment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var nameOffset = firstFragment.nameOffset;
|
||||
var name = firstFragment.name;
|
||||
if (nameOffset == null || name == null) {
|
||||
return null;
|
||||
}
|
||||
var nameOffset = firstFragment.nameOffset;
|
||||
var name = firstFragment.name;
|
||||
if (nameOffset == null || name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Location(
|
||||
uri: uriConverter.toClientUri(
|
||||
libraryFragment.source.fullName,
|
||||
),
|
||||
range: toRange(
|
||||
libraryFragment.lineInfo,
|
||||
nameOffset,
|
||||
name.length,
|
||||
),
|
||||
);
|
||||
})
|
||||
.nonNulls
|
||||
.toList(),
|
||||
return Location(
|
||||
uri: uriConverter.toClientUri(libraryFragment.source.fullName),
|
||||
range: toRange(libraryFragment.lineInfo, nameOffset, name.length),
|
||||
);
|
||||
})
|
||||
.nonNulls
|
||||
.toList(),
|
||||
);
|
||||
|
||||
return success(locations);
|
||||
|
||||
@@ -24,8 +24,8 @@ class InitializedMessageHandler
|
||||
MessageInfo message,
|
||||
CancellationToken token,
|
||||
) async {
|
||||
var initializedHandler =
|
||||
server.messageHandler = InitializedLspStateMessageHandler(server);
|
||||
var initializedHandler = server.messageHandler =
|
||||
InitializedLspStateMessageHandler(server);
|
||||
|
||||
server.analyticsManager.initialized(openWorkspacePaths: openWorkspacePaths);
|
||||
|
||||
|
||||
@@ -274,13 +274,12 @@ class RenameHandler extends LspMessageHandler<RenameParams, WorkspaceEdit?> {
|
||||
_isClassRename(refactoring)) {
|
||||
// The rename must always be performed on the file that defines the
|
||||
// class which is not necessarily the one where the rename was invoked.
|
||||
var declaringFile =
|
||||
(refactoring as RenameUnitMemberRefactoringImpl)
|
||||
.element
|
||||
.firstFragment
|
||||
.libraryFragment
|
||||
?.source
|
||||
.fullName;
|
||||
var declaringFile = (refactoring as RenameUnitMemberRefactoringImpl)
|
||||
.element
|
||||
.firstFragment
|
||||
.libraryFragment
|
||||
?.source
|
||||
.fullName;
|
||||
if (declaringFile != null) {
|
||||
var folder = pathContext.dirname(declaringFile);
|
||||
var actualFilename = pathContext.basename(declaringFile);
|
||||
@@ -358,12 +357,9 @@ class RenameRegistrations extends FeatureRegistration
|
||||
Method get registrationMethod => Method.textDocument_rename;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions =>
|
||||
clientCapabilities.renameValidation
|
||||
? Either2<bool, RenameOptions>.t2(
|
||||
RenameOptions(prepareProvider: true),
|
||||
)
|
||||
: Either2<bool, RenameOptions>.t1(true);
|
||||
StaticOptions get staticOptions => clientCapabilities.renameValidation
|
||||
? Either2<bool, RenameOptions>.t2(RenameOptions(prepareProvider: true))
|
||||
: Either2<bool, RenameOptions>.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.rename;
|
||||
|
||||
@@ -40,8 +40,9 @@ class SelectionRangeHandler
|
||||
var unit = await requireUnresolvedUnit(path);
|
||||
return unit.mapResultSync((unit) {
|
||||
var positions = params.positions;
|
||||
var offsets =
|
||||
positions.map((pos) => toOffset(unit.lineInfo, pos)).errorOrResults;
|
||||
var offsets = positions
|
||||
.map((pos) => toOffset(unit.lineInfo, pos))
|
||||
.errorOrResults;
|
||||
var allRanges = offsets.mapResultSync(
|
||||
(offsets) => success(_getSelectionRangesForOffsets(offsets, unit)),
|
||||
);
|
||||
|
||||
@@ -73,10 +73,9 @@ abstract class AbstractSemanticTokensHandler<T>
|
||||
}
|
||||
|
||||
return toSourceRangeNullable(lineInfo, range).mapResult((range) async {
|
||||
var serverTokens =
|
||||
resolvedUnit != null
|
||||
? await getServerResult(resolvedUnit.unit, range)
|
||||
: <SemanticTokenInfo>[];
|
||||
var serverTokens = resolvedUnit != null
|
||||
? await getServerResult(resolvedUnit.unit, range)
|
||||
: <SemanticTokenInfo>[];
|
||||
var pluginHighlightRegions = getPluginResults(path).flattenedToList;
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
@@ -102,8 +101,8 @@ abstract class AbstractSemanticTokensHandler<T>
|
||||
// Some of the translation operations and the final encoding require
|
||||
// the tokens to be sorted. Do it once here to avoid each method needing
|
||||
// to do it itself (resulting in multiple sorts).
|
||||
tokens =
|
||||
tokens.toList()..sort(SemanticTokenInfo.offsetLengthPrioritySort);
|
||||
tokens = tokens.toList()
|
||||
..sort(SemanticTokenInfo.offsetLengthPrioritySort);
|
||||
|
||||
if (!allowOverlappingTokens) {
|
||||
tokens = encoder.splitOverlappingTokens(tokens);
|
||||
|
||||
@@ -180,10 +180,9 @@ class TypeDefinitionHandler
|
||||
_ => (null, null),
|
||||
};
|
||||
|
||||
var codeRange =
|
||||
codeOffset != null && codeLength != null
|
||||
? toRange(targetUnit.lineInfo, codeOffset, codeLength)
|
||||
: targetNameRange;
|
||||
var codeRange = codeOffset != null && codeLength != null
|
||||
? toRange(targetUnit.lineInfo, codeOffset, codeLength)
|
||||
: targetNameRange;
|
||||
|
||||
return LocationLink(
|
||||
originSelectionRange: toRange(
|
||||
|
||||
@@ -49,11 +49,10 @@ class WorkspaceSymbolHandler
|
||||
}
|
||||
|
||||
var supportedSymbolKinds = clientCapabilities.workspaceSymbolKinds;
|
||||
var searchOnlyAnalyzed =
|
||||
!server
|
||||
.lspClientConfiguration
|
||||
.global
|
||||
.includeDependenciesInWorkspaceSymbols;
|
||||
var searchOnlyAnalyzed = !server
|
||||
.lspClientConfiguration
|
||||
.global
|
||||
.includeDependenciesInWorkspaceSymbols;
|
||||
|
||||
// Cap the number of results we'll return because short queries may match
|
||||
// huge numbers on large projects.
|
||||
|
||||
@@ -191,10 +191,9 @@ mixin HandlerHelperMixin<S extends AnalysisServer> {
|
||||
var supportedSchemes = server.uriConverter.supportedSchemes;
|
||||
var isValidScheme = supportedSchemes.contains(uri.scheme);
|
||||
if (!isValidScheme) {
|
||||
var supportedSchemesString =
|
||||
supportedSchemes.isEmpty
|
||||
? '(none)'
|
||||
: supportedSchemes.map((scheme) => "'$scheme'").join(', ');
|
||||
var supportedSchemesString = supportedSchemes.isEmpty
|
||||
? '(none)'
|
||||
: supportedSchemes.map((scheme) => "'$scheme'").join(', ');
|
||||
return ErrorOr<String>.error(
|
||||
ResponseError(
|
||||
code: ServerErrorCodes.InvalidFilePath,
|
||||
@@ -428,8 +427,9 @@ abstract class MessageHandler<P, R, S extends AnalysisServer>
|
||||
);
|
||||
}
|
||||
|
||||
var params =
|
||||
paramsJson != null ? jsonHandler.convertParams(paramsJson) : null as P;
|
||||
var params = paramsJson != null
|
||||
? jsonHandler.convertParams(paramsJson)
|
||||
: null as P;
|
||||
return handle(params, messageInfo, token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,10 +374,8 @@ class LspAnalysisServer extends AnalysisServer {
|
||||
) {
|
||||
_clientCapabilities = LspClientCapabilities(capabilities);
|
||||
_clientInfo = clientInfo;
|
||||
var initializationOptions =
|
||||
_initializationOptions = LspInitializationOptions(
|
||||
rawInitializationOptions,
|
||||
);
|
||||
var initializationOptions = _initializationOptions =
|
||||
LspInitializationOptions(rawInitializationOptions);
|
||||
|
||||
/// Enable virtual file support.
|
||||
var supportsVirtualFiles =
|
||||
@@ -533,14 +531,13 @@ class LspAnalysisServer extends AnalysisServer {
|
||||
);
|
||||
completer?.setComplete();
|
||||
} catch (error, stackTrace) {
|
||||
var errorMessage =
|
||||
message is ResponseMessage
|
||||
? 'An error occurred while handling the response to request ${message.id}'
|
||||
: message is RequestMessage
|
||||
? 'An error occurred while handling ${message.method} request'
|
||||
: message is NotificationMessage
|
||||
? 'An error occurred while handling ${message.method} notification'
|
||||
: 'Unknown message type';
|
||||
var errorMessage = message is ResponseMessage
|
||||
? 'An error occurred while handling the response to request ${message.id}'
|
||||
: message is RequestMessage
|
||||
? 'An error occurred while handling ${message.method} request'
|
||||
: message is NotificationMessage
|
||||
? 'An error occurred while handling ${message.method} notification'
|
||||
: 'Unknown message type';
|
||||
sendErrorResponse(
|
||||
message,
|
||||
ResponseError(
|
||||
@@ -579,8 +576,9 @@ class LspAnalysisServer extends AnalysisServer {
|
||||
fullMessage = '$fullMessage: $exception';
|
||||
}
|
||||
|
||||
var fullError =
|
||||
stackTrace == null ? fullMessage : '$fullMessage\n$stackTrace';
|
||||
var fullError = stackTrace == null
|
||||
? fullMessage
|
||||
: '$fullMessage\n$stackTrace';
|
||||
stackTrace ??= StackTrace.current;
|
||||
|
||||
// Log the full message since showMessage above may be truncated or
|
||||
@@ -1027,12 +1025,11 @@ class LspAnalysisServer extends AnalysisServer {
|
||||
var packages = <String>{};
|
||||
var additionalFiles = <String>[];
|
||||
for (var file in openFiles) {
|
||||
var package =
|
||||
roots
|
||||
.where((root) => root.isAnalyzed(file))
|
||||
.map((root) => root.workspace.findPackageFor(file)?.root)
|
||||
.nonNulls
|
||||
.firstOrNull;
|
||||
var package = roots
|
||||
.where((root) => root.isAnalyzed(file))
|
||||
.map((root) => root.workspace.findPackageFor(file)?.root)
|
||||
.nonNulls
|
||||
.firstOrNull;
|
||||
if (package != null && !package.isRoot) {
|
||||
packages.add(package.path);
|
||||
} else {
|
||||
@@ -1101,30 +1098,25 @@ class LspAnalysisServer extends AnalysisServer {
|
||||
// When there are open folders, they are always the roots. If there are no
|
||||
// open workspace folders, then we use the open (priority) files to compute
|
||||
// roots.
|
||||
var includedPaths =
|
||||
_workspaceFolders.isNotEmpty
|
||||
? _workspaceFolders.toSet()
|
||||
: _getRootsForOpenFiles();
|
||||
var includedPaths = _workspaceFolders.isNotEmpty
|
||||
? _workspaceFolders.toSet()
|
||||
: _getRootsForOpenFiles();
|
||||
|
||||
var excludedPaths =
|
||||
lspClientConfiguration.global.analysisExcludedFolders
|
||||
.expand(
|
||||
(excludePath) =>
|
||||
resourceProvider.pathContext.isAbsolute(excludePath)
|
||||
? [excludePath]
|
||||
// Apply the relative path to each open workspace folder.
|
||||
// TODO(dantup): Consider supporting per-workspace config by
|
||||
// calling workspace/configuration whenever workspace folders change
|
||||
// and caching the config for each one.
|
||||
: _workspaceFolders.map(
|
||||
(root) => resourceProvider.pathContext.join(
|
||||
root,
|
||||
excludePath,
|
||||
),
|
||||
),
|
||||
)
|
||||
.map(pathContext.normalize)
|
||||
.toSet();
|
||||
var excludedPaths = lspClientConfiguration.global.analysisExcludedFolders
|
||||
.expand(
|
||||
(excludePath) => resourceProvider.pathContext.isAbsolute(excludePath)
|
||||
? [excludePath]
|
||||
// Apply the relative path to each open workspace folder.
|
||||
// TODO(dantup): Consider supporting per-workspace config by
|
||||
// calling workspace/configuration whenever workspace folders change
|
||||
// and caching the config for each one.
|
||||
: _workspaceFolders.map(
|
||||
(root) =>
|
||||
resourceProvider.pathContext.join(root, excludePath),
|
||||
),
|
||||
)
|
||||
.map(pathContext.normalize)
|
||||
.toSet();
|
||||
|
||||
var completer = analysisContextRebuildCompleter = Completer();
|
||||
try {
|
||||
@@ -1252,17 +1244,18 @@ class LspServerContextManagerCallbacks
|
||||
|
||||
var unit = result.unit;
|
||||
if (analysisServer.shouldSendClosingLabelsFor(path)) {
|
||||
var labels =
|
||||
DartUnitClosingLabelsComputer(
|
||||
result.lineInfo,
|
||||
unit,
|
||||
).compute().map((l) => toClosingLabel(result.lineInfo, l)).toList();
|
||||
var labels = DartUnitClosingLabelsComputer(
|
||||
result.lineInfo,
|
||||
unit,
|
||||
).compute().map((l) => toClosingLabel(result.lineInfo, l)).toList();
|
||||
|
||||
analysisServer.publishClosingLabels(path, labels);
|
||||
}
|
||||
if (analysisServer.shouldSendOutlineFor(path)) {
|
||||
var outline =
|
||||
DartUnitOutlineComputer(result, withBasicFlutter: true).compute();
|
||||
var outline = DartUnitOutlineComputer(
|
||||
result,
|
||||
withBasicFlutter: true,
|
||||
).compute();
|
||||
var lspOutline = toOutline(result.lineInfo, outline);
|
||||
analysisServer.publishOutline(path, lspOutline);
|
||||
}
|
||||
|
||||
@@ -38,53 +38,54 @@ class LspPacketTransformer extends StreamTransformerBase<List<int>, String> {
|
||||
Stream<String> bind(Stream<List<int>> stream) {
|
||||
LspHeaders? headersState;
|
||||
var buffer = <int>[];
|
||||
var controller = MoreTypedStreamController<
|
||||
String,
|
||||
_LspPacketTransformerListenData,
|
||||
_LspPacketTransformerPauseData
|
||||
>(
|
||||
onListen: (controller) {
|
||||
var input = stream
|
||||
.expand((b) => b)
|
||||
.listen(
|
||||
(codeUnit) {
|
||||
buffer.add(codeUnit);
|
||||
var headers = headersState;
|
||||
if (headers == null && _endsWithCrLfCrLf(buffer)) {
|
||||
headersState = _parseHeaders(buffer);
|
||||
buffer.clear();
|
||||
} else if (headers != null &&
|
||||
buffer.length >= headers.contentLength) {
|
||||
// UTF-8 is the default - and only supported - encoding for LSP.
|
||||
// The string 'utf8' is valid since it was published in the original spec.
|
||||
// Any other encodings should be rejected with an error.
|
||||
if ([
|
||||
null,
|
||||
'utf-8',
|
||||
'utf8',
|
||||
].contains(headers.encoding?.toLowerCase())) {
|
||||
controller.add(utf8.decode(buffer));
|
||||
} else {
|
||||
controller.addError(
|
||||
InvalidEncodingError(headers.rawHeaders),
|
||||
);
|
||||
}
|
||||
buffer.clear();
|
||||
headersState = null;
|
||||
}
|
||||
},
|
||||
onError: controller.addError,
|
||||
onDone: controller.close,
|
||||
);
|
||||
return _LspPacketTransformerListenData(input);
|
||||
},
|
||||
onPause: (listenData) {
|
||||
listenData.input.pause();
|
||||
return _LspPacketTransformerPauseData();
|
||||
},
|
||||
onResume: (listenData, pauseData) => listenData.input.resume(),
|
||||
onCancel: (listenData) => listenData.input.cancel(),
|
||||
);
|
||||
var controller =
|
||||
MoreTypedStreamController<
|
||||
String,
|
||||
_LspPacketTransformerListenData,
|
||||
_LspPacketTransformerPauseData
|
||||
>(
|
||||
onListen: (controller) {
|
||||
var input = stream
|
||||
.expand((b) => b)
|
||||
.listen(
|
||||
(codeUnit) {
|
||||
buffer.add(codeUnit);
|
||||
var headers = headersState;
|
||||
if (headers == null && _endsWithCrLfCrLf(buffer)) {
|
||||
headersState = _parseHeaders(buffer);
|
||||
buffer.clear();
|
||||
} else if (headers != null &&
|
||||
buffer.length >= headers.contentLength) {
|
||||
// UTF-8 is the default - and only supported - encoding for LSP.
|
||||
// The string 'utf8' is valid since it was published in the original spec.
|
||||
// Any other encodings should be rejected with an error.
|
||||
if ([
|
||||
null,
|
||||
'utf-8',
|
||||
'utf8',
|
||||
].contains(headers.encoding?.toLowerCase())) {
|
||||
controller.add(utf8.decode(buffer));
|
||||
} else {
|
||||
controller.addError(
|
||||
InvalidEncodingError(headers.rawHeaders),
|
||||
);
|
||||
}
|
||||
buffer.clear();
|
||||
headersState = null;
|
||||
}
|
||||
},
|
||||
onError: controller.addError,
|
||||
onDone: controller.close,
|
||||
);
|
||||
return _LspPacketTransformerListenData(input);
|
||||
},
|
||||
onPause: (listenData) {
|
||||
listenData.input.pause();
|
||||
return _LspPacketTransformerPauseData();
|
||||
},
|
||||
onResume: (listenData, pauseData) => listenData.input.resume(),
|
||||
onCancel: (listenData) => listenData.input.cancel(),
|
||||
);
|
||||
return controller.controller.stream;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,19 +89,18 @@ class LspSocketServer implements AbstractSocketServer {
|
||||
stateLocation: analysisServerOptions.cacheFolder,
|
||||
);
|
||||
|
||||
var server =
|
||||
analysisServer = LspAnalysisServer(
|
||||
serverChannel,
|
||||
resourceProvider,
|
||||
analysisServerOptions,
|
||||
sdkManager,
|
||||
analyticsManager,
|
||||
CrashReportingAttachmentsBuilder.empty,
|
||||
instrumentationService,
|
||||
diagnosticServer: diagnosticServer,
|
||||
detachableFileSystemManager: detachableFileSystemManager,
|
||||
enableBlazeWatcher: true,
|
||||
);
|
||||
var server = analysisServer = LspAnalysisServer(
|
||||
serverChannel,
|
||||
resourceProvider,
|
||||
analysisServerOptions,
|
||||
sdkManager,
|
||||
analyticsManager,
|
||||
CrashReportingAttachmentsBuilder.empty,
|
||||
instrumentationService,
|
||||
diagnosticServer: diagnosticServer,
|
||||
detachableFileSystemManager: detachableFileSystemManager,
|
||||
enableBlazeWatcher: true,
|
||||
);
|
||||
detachableFileSystemManager?.setAnalysisServer(server);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ lsp.Either2<lsp.MarkupContent, String> asMarkupContentOrString(
|
||||
) {
|
||||
return preferredFormats != null
|
||||
? lsp.Either2<lsp.MarkupContent, String>.t1(
|
||||
_asMarkup(preferredFormats, content),
|
||||
)
|
||||
_asMarkup(preferredFormats, content),
|
||||
)
|
||||
: lsp.Either2<lsp.MarkupContent, String>.t2(content);
|
||||
}
|
||||
|
||||
@@ -126,15 +126,15 @@ lsp.Either2<lsp.MarkupContent, String> asMarkupContentOrString(
|
||||
requiredArgumentListTextRanges?.isNotEmpty ?? false;
|
||||
var functionCallSuffix =
|
||||
hasRequiredParameters && requiredArgumentListString != null
|
||||
? buildSnippetStringWithTabStops(
|
||||
requiredArgumentListString,
|
||||
requiredArgumentListTextRanges,
|
||||
)
|
||||
// Optional params still gets a final tab stop in the parens.
|
||||
: hasOptionalParameters
|
||||
? SnippetBuilder.finalTabStop
|
||||
// And no parameters at all we skip the tabstop in the parens.
|
||||
: '';
|
||||
? buildSnippetStringWithTabStops(
|
||||
requiredArgumentListString,
|
||||
requiredArgumentListTextRanges,
|
||||
)
|
||||
// Optional params still gets a final tab stop in the parens.
|
||||
: hasOptionalParameters
|
||||
? SnippetBuilder.finalTabStop
|
||||
// And no parameters at all we skip the tabstop in the parens.
|
||||
: '';
|
||||
insertText =
|
||||
'${SnippetBuilder.escapeSnippetPlainText(insertText)}($functionCallSuffix)';
|
||||
} else if (selectionOffset != 0 &&
|
||||
@@ -288,25 +288,26 @@ lsp.WorkspaceEdit createWorkspaceEdit(
|
||||
// Compile the edits into a TextDocumentEdit for this file.
|
||||
var textDocumentEdit = lsp.TextDocumentEdit(
|
||||
textDocument: analysisServer.getVersionedDocumentIdentifier(fileEdit.file),
|
||||
edits:
|
||||
snippetEdits
|
||||
.map(
|
||||
(e) => Either3<
|
||||
edits: snippetEdits
|
||||
.map(
|
||||
(e) =>
|
||||
Either3<
|
||||
lsp.AnnotatedTextEdit,
|
||||
lsp.SnippetTextEdit,
|
||||
lsp.TextEdit
|
||||
>.t2(e),
|
||||
)
|
||||
.toList(),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
// Convert to the union that documentChanges require.
|
||||
var textDocumentEditsAsUnion = Either4<
|
||||
lsp.CreateFile,
|
||||
lsp.DeleteFile,
|
||||
lsp.RenameFile,
|
||||
lsp.TextDocumentEdit
|
||||
>.t4(textDocumentEdit);
|
||||
var textDocumentEditsAsUnion =
|
||||
Either4<
|
||||
lsp.CreateFile,
|
||||
lsp.DeleteFile,
|
||||
lsp.RenameFile,
|
||||
lsp.TextDocumentEdit
|
||||
>.t4(textDocumentEdit);
|
||||
|
||||
/// Add the textDocumentEdit to a WorkspaceEdit.
|
||||
return lsp.WorkspaceEdit(documentChanges: [textDocumentEditsAsUnion]);
|
||||
@@ -606,10 +607,9 @@ CompletionDetail getCompletionDetail(
|
||||
}
|
||||
|
||||
var libraryUri = suggestion.libraryUri;
|
||||
var autoImportUri =
|
||||
(suggestion.isNotImported ?? false) && libraryUri != null
|
||||
? Uri.parse(libraryUri)
|
||||
: null;
|
||||
var autoImportUri = (suggestion.isNotImported ?? false) && libraryUri != null
|
||||
? Uri.parse(libraryUri)
|
||||
: null;
|
||||
|
||||
return (
|
||||
detail: detail,
|
||||
@@ -638,13 +638,13 @@ String? getCompletionDisplayUriString({
|
||||
// Compute the relative path and then put into a URI so the display
|
||||
// always uses forward slashes (as a URI) regardless of platform.
|
||||
? uriConverter
|
||||
.toClientUri(
|
||||
pathContext.relative(
|
||||
uriConverter.fromClientUri(elementLibraryUri),
|
||||
from: pathContext.dirname(completionFilePath),
|
||||
),
|
||||
)
|
||||
.toString()
|
||||
.toClientUri(
|
||||
pathContext.relative(
|
||||
uriConverter.fromClientUri(elementLibraryUri),
|
||||
from: pathContext.dirname(completionFilePath),
|
||||
),
|
||||
)
|
||||
.toString()
|
||||
: elementLibraryUri.toString();
|
||||
}
|
||||
|
||||
@@ -656,10 +656,9 @@ List<lsp.DiagnosticTag>? getDiagnosticTags(
|
||||
return null;
|
||||
}
|
||||
|
||||
var tags =
|
||||
diagnosticTagsForErrorCode[error.code]
|
||||
?.where(supportedTags.contains)
|
||||
.toList();
|
||||
var tags = diagnosticTagsForErrorCode[error.code]
|
||||
?.where(supportedTags.contains)
|
||||
.toList();
|
||||
|
||||
return tags != null && tags.isNotEmpty ? tags : null;
|
||||
}
|
||||
@@ -737,10 +736,9 @@ lsp.LocationLink? navigationTargetToLocationLink(
|
||||
var nameRange = toRange(targetLineInfo, target.offset, target.length);
|
||||
var codeOffset = target.codeOffset;
|
||||
var codeLength = target.codeLength;
|
||||
var codeRange =
|
||||
codeOffset != null && codeLength != null
|
||||
? toRange(targetLineInfo, codeOffset, codeLength)
|
||||
: nameRange;
|
||||
var codeRange = codeOffset != null && codeLength != null
|
||||
? toRange(targetLineInfo, codeOffset, codeLength)
|
||||
: nameRange;
|
||||
|
||||
return lsp.LocationLink(
|
||||
originSelectionRange: toRange(regionLineInfo, region.offset, region.length),
|
||||
@@ -760,17 +758,16 @@ lsp.Diagnostic pluginToDiagnostic(
|
||||
List<lsp.DiagnosticRelatedInformation>? relatedInformation;
|
||||
var contextMessages = error.contextMessages;
|
||||
if (contextMessages != null && contextMessages.isNotEmpty) {
|
||||
relatedInformation =
|
||||
contextMessages
|
||||
.map(
|
||||
(message) => pluginToDiagnosticRelatedInformation(
|
||||
uriConverter,
|
||||
getLineInfo,
|
||||
message,
|
||||
),
|
||||
)
|
||||
.nonNulls
|
||||
.toList();
|
||||
relatedInformation = contextMessages
|
||||
.map(
|
||||
(message) => pluginToDiagnosticRelatedInformation(
|
||||
uriConverter,
|
||||
getLineInfo,
|
||||
message,
|
||||
),
|
||||
)
|
||||
.nonNulls
|
||||
.toList();
|
||||
}
|
||||
|
||||
var message = error.message;
|
||||
@@ -800,10 +797,9 @@ lsp.Diagnostic pluginToDiagnostic(
|
||||
relatedInformation: relatedInformation,
|
||||
// Only include codeDescription if the client explicitly supports it
|
||||
// (a minor optimization to avoid unnecessary payload/(de)serialization).
|
||||
codeDescription:
|
||||
clientSupportsCodeDescription && documentationUrl != null
|
||||
? CodeDescription(href: Uri.parse(documentationUrl))
|
||||
: null,
|
||||
codeDescription: clientSupportsCodeDescription && documentationUrl != null
|
||||
? CodeDescription(href: Uri.parse(documentationUrl))
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -991,10 +987,12 @@ lsp.CompletionItem snippetToCompletionItem(
|
||||
thisFilesChange,
|
||||
changes.linkedEditGroups,
|
||||
lineInfo,
|
||||
selectionOffset:
|
||||
changes.selection?.file == file ? changes.selection?.offset : null,
|
||||
selectionLength:
|
||||
changes.selection?.file == file ? changes.selectionLength : null,
|
||||
selectionOffset: changes.selection?.file == file
|
||||
? changes.selection?.offset
|
||||
: null,
|
||||
selectionLength: changes.selection?.file == file
|
||||
? changes.selectionLength
|
||||
: null,
|
||||
);
|
||||
|
||||
// For LSP, we need to provide the main edit and other edits separately. The
|
||||
@@ -1021,10 +1019,9 @@ lsp.CompletionItem snippetToCompletionItem(
|
||||
filterText: snippet.prefix.orNullIfSameAs(snippet.label),
|
||||
kind: lsp.CompletionItemKind.Snippet,
|
||||
command: command,
|
||||
documentation:
|
||||
documentation != null
|
||||
? asMarkupContentOrString(formats, documentation)
|
||||
: null,
|
||||
documentation: documentation != null
|
||||
? asMarkupContentOrString(formats, documentation)
|
||||
: null,
|
||||
// Force snippets to be sorted at the bottom of the list.
|
||||
// TODO(dantup): Consider if we can rank these better. Client-side
|
||||
// snippets have always been forced to the bottom partly because they
|
||||
@@ -1034,14 +1031,12 @@ lsp.CompletionItem snippetToCompletionItem(
|
||||
insertTextMode: supportsAsIsInsertMode ? InsertTextMode.asIs : null,
|
||||
// Set textEdit or textEditText depending on whether we need to specify
|
||||
// a range or not.
|
||||
textEdit:
|
||||
hasDefaultEditRange
|
||||
? null
|
||||
: Either2<InsertReplaceEdit, TextEdit>.t2(mainEdit),
|
||||
textEditText:
|
||||
hasDefaultEditRange
|
||||
? mainEdit.newText.orNullIfSameAs(snippet.label)
|
||||
: null,
|
||||
textEdit: hasDefaultEditRange
|
||||
? null
|
||||
: Either2<InsertReplaceEdit, TextEdit>.t2(mainEdit),
|
||||
textEditText: hasDefaultEditRange
|
||||
? mainEdit.newText.orNullIfSameAs(snippet.label)
|
||||
: null,
|
||||
additionalTextEdits: nonMainEdits.nullIfEmpty,
|
||||
);
|
||||
}
|
||||
@@ -1075,13 +1070,13 @@ lsp.CompletionItemKind? suggestionKindToCompletionItemKind(
|
||||
if (!label.startsWith('dart:')) {
|
||||
return label.endsWith('.dart')
|
||||
? const [
|
||||
lsp.CompletionItemKind.File,
|
||||
lsp.CompletionItemKind.Module,
|
||||
]
|
||||
lsp.CompletionItemKind.File,
|
||||
lsp.CompletionItemKind.Module,
|
||||
]
|
||||
: const [
|
||||
lsp.CompletionItemKind.Folder,
|
||||
lsp.CompletionItemKind.Module,
|
||||
];
|
||||
lsp.CompletionItemKind.Folder,
|
||||
lsp.CompletionItemKind.Module,
|
||||
];
|
||||
}
|
||||
return const [lsp.CompletionItemKind.Module];
|
||||
case server.CompletionSuggestionKind.IDENTIFIER:
|
||||
@@ -1207,10 +1202,9 @@ lsp.CompletionItem toCompletionItem(
|
||||
|
||||
// TODO(dantup): Consider including more of these raw fields in the original
|
||||
// suggestion to avoid needing to manipulate them in this way here.
|
||||
var filterText =
|
||||
!label.startsWith(completionFilterTextSplitPattern)
|
||||
? label.split(completionFilterTextSplitPattern).first.trim()
|
||||
: label;
|
||||
var filterText = !label.startsWith(completionFilterTextSplitPattern)
|
||||
? label.split(completionFilterTextSplitPattern).first.trim()
|
||||
: label;
|
||||
|
||||
// If we're using label details, we also don't want the label to include any
|
||||
// additional symbols as noted above, because they will appear in the extra
|
||||
@@ -1227,22 +1221,21 @@ lsp.CompletionItem toCompletionItem(
|
||||
var element = suggestion.element;
|
||||
var colorPreviewHex =
|
||||
capabilities.completionItemKinds.contains(CompletionItemKind.Color) &&
|
||||
suggestion is DartCompletionSuggestion
|
||||
? suggestion.colorHex
|
||||
: null;
|
||||
var completionKind =
|
||||
colorPreviewHex != null
|
||||
? CompletionItemKind.Color
|
||||
: element != null
|
||||
? elementKindToCompletionItemKind(
|
||||
capabilities.completionItemKinds,
|
||||
element.kind,
|
||||
)
|
||||
: suggestionKindToCompletionItemKind(
|
||||
capabilities.completionItemKinds,
|
||||
suggestion.kind,
|
||||
label,
|
||||
);
|
||||
suggestion is DartCompletionSuggestion
|
||||
? suggestion.colorHex
|
||||
: null;
|
||||
var completionKind = colorPreviewHex != null
|
||||
? CompletionItemKind.Color
|
||||
: element != null
|
||||
? elementKindToCompletionItemKind(
|
||||
capabilities.completionItemKinds,
|
||||
element.kind,
|
||||
)
|
||||
: suggestionKindToCompletionItemKind(
|
||||
capabilities.completionItemKinds,
|
||||
suggestion.kind,
|
||||
label,
|
||||
);
|
||||
|
||||
var labelDetails = getCompletionDetail(
|
||||
suggestion,
|
||||
@@ -1272,21 +1265,19 @@ lsp.CompletionItem toCompletionItem(
|
||||
var insertTextFormat = insertTextInfo.format;
|
||||
var isMultilineCompletion = insertText.contains('\n');
|
||||
|
||||
var rawDoc =
|
||||
includeDocumentation == DocumentationPreference.full
|
||||
? suggestion.docComplete
|
||||
: includeDocumentation == DocumentationPreference.summary
|
||||
? suggestion.docSummary
|
||||
: null;
|
||||
var rawDoc = includeDocumentation == DocumentationPreference.full
|
||||
? suggestion.docComplete
|
||||
: includeDocumentation == DocumentationPreference.summary
|
||||
? suggestion.docSummary
|
||||
: null;
|
||||
var cleanedDoc = cleanDartdoc(rawDoc);
|
||||
|
||||
// To improve the display of some items (like pubspec version numbers),
|
||||
// short labels in the format `_foo_` in docComplete are "upgraded" to the
|
||||
// detail field.
|
||||
var labelMatch =
|
||||
cleanedDoc != null
|
||||
? upgradableDocCompletePattern.firstMatch(cleanedDoc)
|
||||
: null;
|
||||
var labelMatch = cleanedDoc != null
|
||||
? upgradableDocCompletePattern.firstMatch(cleanedDoc)
|
||||
: null;
|
||||
if (labelMatch != null) {
|
||||
cleanedDoc = null;
|
||||
labelDetails = (
|
||||
@@ -1316,53 +1307,48 @@ lsp.CompletionItem toCompletionItem(
|
||||
]),
|
||||
data: resolutionData,
|
||||
detail: labelDetails.detail.nullIfEmpty,
|
||||
labelDetails:
|
||||
useLabelDetails
|
||||
? CompletionItemLabelDetails(
|
||||
detail: labelDetails.truncatedSignature.nullIfEmpty,
|
||||
description: getCompletionDisplayUriString(
|
||||
uriConverter: uriConverter,
|
||||
pathContext: pathContext,
|
||||
elementLibraryUri: labelDetails.autoImportUri,
|
||||
completionFilePath: completionFilePath,
|
||||
),
|
||||
).nullIfEmpty
|
||||
: null,
|
||||
documentation:
|
||||
cleanedDoc != null
|
||||
? asMarkupContentOrString(formats, cleanedDoc)
|
||||
: null,
|
||||
deprecated:
|
||||
supportsCompletionDeprecatedFlag && suggestion.isDeprecated
|
||||
? true
|
||||
: null,
|
||||
labelDetails: useLabelDetails
|
||||
? CompletionItemLabelDetails(
|
||||
detail: labelDetails.truncatedSignature.nullIfEmpty,
|
||||
description: getCompletionDisplayUriString(
|
||||
uriConverter: uriConverter,
|
||||
pathContext: pathContext,
|
||||
elementLibraryUri: labelDetails.autoImportUri,
|
||||
completionFilePath: completionFilePath,
|
||||
),
|
||||
).nullIfEmpty
|
||||
: null,
|
||||
documentation: cleanedDoc != null
|
||||
? asMarkupContentOrString(formats, cleanedDoc)
|
||||
: null,
|
||||
deprecated: supportsCompletionDeprecatedFlag && suggestion.isDeprecated
|
||||
? true
|
||||
: null,
|
||||
sortText: relevanceToSortText(suggestion.relevance),
|
||||
filterText: filterText.orNullIfSameAs(
|
||||
label,
|
||||
), // filterText uses label if not set
|
||||
insertTextFormat:
|
||||
insertTextFormat != lsp.InsertTextFormat.PlainText
|
||||
? insertTextFormat
|
||||
: null, // Defaults to PlainText if not supplied
|
||||
insertTextFormat: insertTextFormat != lsp.InsertTextFormat.PlainText
|
||||
? insertTextFormat
|
||||
: null, // Defaults to PlainText if not supplied
|
||||
insertTextMode:
|
||||
!hasDefaultTextMode && supportsAsIsInsertMode && isMultilineCompletion
|
||||
? InsertTextMode.asIs
|
||||
: null,
|
||||
? InsertTextMode.asIs
|
||||
: null,
|
||||
// When using defaults for edit range, don't use textEdit.
|
||||
textEdit:
|
||||
hasDefaultEditRange
|
||||
? null
|
||||
: supportsInsertReplace && insertionRange != replacementRange
|
||||
? Either2<InsertReplaceEdit, TextEdit>.t1(
|
||||
InsertReplaceEdit(
|
||||
insert: insertionRange,
|
||||
replace: replacementRange,
|
||||
newText: insertText,
|
||||
),
|
||||
)
|
||||
: Either2<InsertReplaceEdit, TextEdit>.t2(
|
||||
TextEdit(range: replacementRange, newText: insertText),
|
||||
textEdit: hasDefaultEditRange
|
||||
? null
|
||||
: supportsInsertReplace && insertionRange != replacementRange
|
||||
? Either2<InsertReplaceEdit, TextEdit>.t1(
|
||||
InsertReplaceEdit(
|
||||
insert: insertionRange,
|
||||
replace: replacementRange,
|
||||
newText: insertText,
|
||||
),
|
||||
)
|
||||
: Either2<InsertReplaceEdit, TextEdit>.t2(
|
||||
TextEdit(range: replacementRange, newText: insertText),
|
||||
),
|
||||
// When using defaults for edit range, use textEditText.
|
||||
textEditText: hasDefaultEditRange ? insertText.orNullIfSameAs(label) : null,
|
||||
);
|
||||
@@ -1387,10 +1373,9 @@ lsp.Diagnostic toDiagnostic(
|
||||
lsp.Element toElement(server.LineInfo lineInfo, server.Element element) {
|
||||
var location = element.location;
|
||||
return lsp.Element(
|
||||
range:
|
||||
location != null
|
||||
? toRange(lineInfo, location.offset, location.length)
|
||||
: null,
|
||||
range: location != null
|
||||
? toRange(lineInfo, location.offset, location.length)
|
||||
: null,
|
||||
name: toElementName(element),
|
||||
kind: element.kind.name,
|
||||
parameters: element.parameters,
|
||||
@@ -1403,8 +1388,8 @@ String toElementName(server.Element element) {
|
||||
return element.name.isNotEmpty
|
||||
? element.name
|
||||
: (element.kind == server.ElementKind.EXTENSION
|
||||
? '<unnamed extension>'
|
||||
: '<unnamed>');
|
||||
? '<unnamed extension>'
|
||||
: '<unnamed>');
|
||||
}
|
||||
|
||||
lsp.FlutterOutline toFlutterOutline(
|
||||
@@ -1420,10 +1405,9 @@ lsp.FlutterOutline toFlutterOutline(
|
||||
label: outline.label,
|
||||
className: outline.className,
|
||||
variableName: outline.variableName,
|
||||
attributes:
|
||||
attributes
|
||||
?.map((attribute) => toFlutterOutlineAttribute(lineInfo, attribute))
|
||||
.toList(),
|
||||
attributes: attributes
|
||||
?.map((attribute) => toFlutterOutlineAttribute(lineInfo, attribute))
|
||||
.toList(),
|
||||
dartElement: dartElement != null ? toElement(lineInfo, dartElement) : null,
|
||||
range: toRange(lineInfo, outline.offset, outline.length),
|
||||
codeRange: toRange(lineInfo, outline.codeOffset, outline.codeLength),
|
||||
@@ -1439,10 +1423,9 @@ lsp.FlutterOutlineAttribute toFlutterOutlineAttribute(
|
||||
return lsp.FlutterOutlineAttribute(
|
||||
name: attribute.name,
|
||||
label: attribute.label,
|
||||
valueRange:
|
||||
valueLocation != null
|
||||
? toRange(lineInfo, valueLocation.offset, valueLocation.length)
|
||||
: null,
|
||||
valueRange: valueLocation != null
|
||||
? toRange(lineInfo, valueLocation.offset, valueLocation.length)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1480,10 +1463,9 @@ ErrorOr<int> toOffset(
|
||||
if (pos.line >= lineInfo.lineCount) {
|
||||
return ErrorOr<int>.error(
|
||||
lsp.ResponseError(
|
||||
code:
|
||||
failureIsCritical
|
||||
? lsp.ServerErrorCodes.ClientServerInconsistentState
|
||||
: lsp.ServerErrorCodes.InvalidFileLineCol,
|
||||
code: failureIsCritical
|
||||
? lsp.ServerErrorCodes.ClientServerInconsistentState
|
||||
: lsp.ServerErrorCodes.InvalidFileLineCol,
|
||||
message: 'Invalid line number',
|
||||
data: pos.line.toString(),
|
||||
),
|
||||
@@ -1535,8 +1517,9 @@ lsp.SignatureHelp toSignatureHelp(
|
||||
/// Gets the label for an individual parameter in the form
|
||||
/// String s = 'foo'
|
||||
String getParamLabel(FormalParameterElement p) {
|
||||
var defaultCodeSuffix =
|
||||
p.defaultValueCode != null ? ' = ${p.defaultValueCode}' : '';
|
||||
var defaultCodeSuffix = p.defaultValueCode != null
|
||||
? ' = ${p.defaultValueCode}'
|
||||
: '';
|
||||
var requiredPrefix = p.isRequiredNamed ? 'required ' : '';
|
||||
return '$requiredPrefix${p.type} ${p.displayName}$defaultCodeSuffix';
|
||||
}
|
||||
@@ -1544,10 +1527,12 @@ lsp.SignatureHelp toSignatureHelp(
|
||||
/// Gets the full signature label in the form
|
||||
/// foo(String s, int i, bool a = true)
|
||||
String getSignatureLabel(server.SignatureInformation resp) {
|
||||
var positionalRequired =
|
||||
signature.parameters.where((p) => p.isRequiredPositional).toList();
|
||||
var positionalOptional =
|
||||
signature.parameters.where((p) => p.isOptionalPositional).toList();
|
||||
var positionalRequired = signature.parameters
|
||||
.where((p) => p.isRequiredPositional)
|
||||
.toList();
|
||||
var positionalOptional = signature.parameters
|
||||
.where((p) => p.isOptionalPositional)
|
||||
.toList();
|
||||
var named = signature.parameters.where((p) => p.isNamed).toList();
|
||||
var params = [
|
||||
if (positionalRequired.isNotEmpty)
|
||||
@@ -1573,10 +1558,9 @@ lsp.SignatureHelp toSignatureHelp(
|
||||
signatures: [
|
||||
lsp.SignatureInformation(
|
||||
label: getSignatureLabel(signature),
|
||||
documentation:
|
||||
cleanedDoc != null
|
||||
? asMarkupContentOrString(preferredFormats, cleanedDoc)
|
||||
: null,
|
||||
documentation: cleanedDoc != null
|
||||
? asMarkupContentOrString(preferredFormats, cleanedDoc)
|
||||
: null,
|
||||
parameters: signature.parameters.map(toParameterInfo).toList(),
|
||||
),
|
||||
],
|
||||
@@ -1665,23 +1649,22 @@ lsp.TextDocumentEdit toTextDocumentEdit(
|
||||
);
|
||||
return lsp.TextDocumentEdit(
|
||||
textDocument: fileEdit.doc,
|
||||
edits:
|
||||
sortSourceEditsForLsp(fileEdit.edits).map((edit) {
|
||||
var annotation = recordEditAnnotation(
|
||||
fileEdit.doc.uri,
|
||||
edit,
|
||||
annotateChanges: annotateChanges,
|
||||
changeAnnotations: changeAnnotations,
|
||||
);
|
||||
return toTextDocumentEditEdit(
|
||||
capabilities,
|
||||
fileEdit.lineInfo,
|
||||
edit,
|
||||
selectionOffsetRelative: fileEdit.selectionOffsetRelative,
|
||||
selectionLength: fileEdit.selectionLength,
|
||||
annotationIdentifier: annotation?.label,
|
||||
);
|
||||
}).toList(),
|
||||
edits: sortSourceEditsForLsp(fileEdit.edits).map((edit) {
|
||||
var annotation = recordEditAnnotation(
|
||||
fileEdit.doc.uri,
|
||||
edit,
|
||||
annotateChanges: annotateChanges,
|
||||
changeAnnotations: changeAnnotations,
|
||||
);
|
||||
return toTextDocumentEditEdit(
|
||||
capabilities,
|
||||
fileEdit.lineInfo,
|
||||
edit,
|
||||
selectionOffsetRelative: fileEdit.selectionOffsetRelative,
|
||||
selectionLength: fileEdit.selectionLength,
|
||||
annotationIdentifier: annotation?.label,
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1726,14 +1709,14 @@ lsp.TextEdit toTextEdit(
|
||||
}) {
|
||||
return annotation != null
|
||||
? lsp.AnnotatedTextEdit(
|
||||
range: toRange(lineInfo, edit.offset, edit.length),
|
||||
newText: edit.replacement,
|
||||
annotationId: annotation.label,
|
||||
)
|
||||
range: toRange(lineInfo, edit.offset, edit.length),
|
||||
newText: edit.replacement,
|
||||
annotationId: annotation.label,
|
||||
)
|
||||
: lsp.TextEdit(
|
||||
range: toRange(lineInfo, edit.offset, edit.length),
|
||||
newText: edit.replacement,
|
||||
);
|
||||
range: toRange(lineInfo, edit.offset, edit.length),
|
||||
newText: edit.replacement,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates an [lsp.WorkspaceEdit] for [edits].
|
||||
@@ -1751,10 +1734,9 @@ lsp.WorkspaceEdit toWorkspaceEdit(
|
||||
ChangeAnnotations annotateChanges = ChangeAnnotations.none,
|
||||
}) {
|
||||
var supportsDocumentChanges = clientCapabilities.documentChanges;
|
||||
var changeAnnotations =
|
||||
annotateChanges != ChangeAnnotations.none
|
||||
? <lsp.ChangeAnnotationIdentifier, ChangeAnnotation>{}
|
||||
: null;
|
||||
var changeAnnotations = annotateChanges != ChangeAnnotations.none
|
||||
? <lsp.ChangeAnnotationIdentifier, ChangeAnnotation>{}
|
||||
: null;
|
||||
|
||||
if (supportsDocumentChanges) {
|
||||
var supportsCreate = clientCapabilities.createResourceOperations;
|
||||
@@ -1774,12 +1756,13 @@ lsp.WorkspaceEdit toWorkspaceEdit(
|
||||
for (var fileEdit in edits) {
|
||||
if (supportsCreate && fileEdit.newFile) {
|
||||
var create = lsp.CreateFile(uri: fileEdit.doc.uri);
|
||||
var createUnion = Either4<
|
||||
lsp.CreateFile,
|
||||
lsp.DeleteFile,
|
||||
lsp.RenameFile,
|
||||
lsp.TextDocumentEdit
|
||||
>.t1(create);
|
||||
var createUnion =
|
||||
Either4<
|
||||
lsp.CreateFile,
|
||||
lsp.DeleteFile,
|
||||
lsp.RenameFile,
|
||||
lsp.TextDocumentEdit
|
||||
>.t1(create);
|
||||
changes.add(createUnion);
|
||||
}
|
||||
|
||||
@@ -1789,12 +1772,13 @@ lsp.WorkspaceEdit toWorkspaceEdit(
|
||||
annotateChanges: annotateChanges,
|
||||
changeAnnotations: changeAnnotations,
|
||||
);
|
||||
var textDocEditUnion = Either4<
|
||||
lsp.CreateFile,
|
||||
lsp.DeleteFile,
|
||||
lsp.RenameFile,
|
||||
lsp.TextDocumentEdit
|
||||
>.t4(textDocEdit);
|
||||
var textDocEditUnion =
|
||||
Either4<
|
||||
lsp.CreateFile,
|
||||
lsp.DeleteFile,
|
||||
lsp.RenameFile,
|
||||
lsp.TextDocumentEdit
|
||||
>.t4(textDocEdit);
|
||||
changes.add(textDocEditUnion);
|
||||
}
|
||||
|
||||
@@ -1820,16 +1804,15 @@ Map<Uri, List<lsp.TextEdit>> toWorkspaceEditChanges(
|
||||
Map<ChangeAnnotationIdentifier, ChangeAnnotation>? changeAnnotations,
|
||||
}) {
|
||||
MapEntry<Uri, List<lsp.TextEdit>> createEdit(FileEditInformation file) {
|
||||
var edits =
|
||||
sortSourceEditsForLsp(file.edits).map((edit) {
|
||||
var annotation = recordEditAnnotation(
|
||||
file.doc.uri,
|
||||
edit,
|
||||
annotateChanges: annotateChanges,
|
||||
changeAnnotations: changeAnnotations,
|
||||
);
|
||||
return toTextEdit(file.lineInfo, edit, annotation: annotation);
|
||||
}).toList();
|
||||
var edits = sortSourceEditsForLsp(file.edits).map((edit) {
|
||||
var annotation = recordEditAnnotation(
|
||||
file.doc.uri,
|
||||
edit,
|
||||
annotateChanges: annotateChanges,
|
||||
changeAnnotations: changeAnnotations,
|
||||
);
|
||||
return toTextEdit(file.lineInfo, edit, annotation: annotation);
|
||||
}).toList();
|
||||
return MapEntry(file.doc.uri, edits);
|
||||
}
|
||||
|
||||
@@ -1848,10 +1831,9 @@ lsp.MarkupContent _asMarkup(
|
||||
var supportsPlain = preferredFormats.contains(lsp.MarkupKind.PlainText);
|
||||
// Since our PlainText version is actually just Markdown, only advertise it
|
||||
// as PlainText if the client explicitly supports PlainText and not Markdown.
|
||||
var format =
|
||||
supportsPlain && !supportsMarkdown
|
||||
? lsp.MarkupKind.PlainText
|
||||
: lsp.MarkupKind.Markdown;
|
||||
var format = supportsPlain && !supportsMarkdown
|
||||
? lsp.MarkupKind.PlainText
|
||||
: lsp.MarkupKind.Markdown;
|
||||
|
||||
return lsp.MarkupContent(kind: format, value: content);
|
||||
}
|
||||
@@ -1860,32 +1842,31 @@ String _diagnosticCode(server.DiagnosticCode code) => code.name.toLowerCase();
|
||||
|
||||
/// Additional details about a completion that may be formatted differently
|
||||
/// depending on the client capabilities.
|
||||
typedef CompletionDetail =
|
||||
({
|
||||
/// Additional details to go in the details popup.
|
||||
///
|
||||
/// This is usually a full signature (with full parameters) and may also
|
||||
/// include whether the item is deprecated if the client did not support the
|
||||
/// native deprecated tag.
|
||||
String detail,
|
||||
typedef CompletionDetail = ({
|
||||
/// Additional details to go in the details popup.
|
||||
///
|
||||
/// This is usually a full signature (with full parameters) and may also
|
||||
/// include whether the item is deprecated if the client did not support the
|
||||
/// native deprecated tag.
|
||||
String detail,
|
||||
|
||||
/// Truncated parameters. Similar to [truncatedSignature] but does not
|
||||
/// include return types. Used in clients that cannot format signatures
|
||||
/// differently and is appended immediately after the completion label. The
|
||||
/// return type is omitted to reduce noise because this text is not subtle.
|
||||
String truncatedParams,
|
||||
/// Truncated parameters. Similar to [truncatedSignature] but does not
|
||||
/// include return types. Used in clients that cannot format signatures
|
||||
/// differently and is appended immediately after the completion label. The
|
||||
/// return type is omitted to reduce noise because this text is not subtle.
|
||||
String truncatedParams,
|
||||
|
||||
/// A signature with truncated params. Used for showing immediately after
|
||||
/// the completion label when it can be formatted differently.
|
||||
///
|
||||
/// () → String
|
||||
String truncatedSignature,
|
||||
/// A signature with truncated params. Used for showing immediately after
|
||||
/// the completion label when it can be formatted differently.
|
||||
///
|
||||
/// () → String
|
||||
String truncatedSignature,
|
||||
|
||||
/// The URI that will be auto-imported if this item is selected in a
|
||||
/// user-friendly string format (for example a relative path if for a `file:/`
|
||||
/// URI).
|
||||
Uri? autoImportUri,
|
||||
});
|
||||
/// The URI that will be auto-imported if this item is selected in a
|
||||
/// user-friendly string format (for example a relative path if for a `file:/`
|
||||
/// URI).
|
||||
Uri? autoImportUri,
|
||||
});
|
||||
|
||||
extension CompletionLabelExtension on CompletionItemLabelDetails {
|
||||
/// Returns `null` if no fields are set, otherwise `this`.
|
||||
|
||||
@@ -25,19 +25,18 @@ class LspNotificationManager extends AbstractNotificationManager {
|
||||
// Currently these diagnostics are always sent to the editor client, so
|
||||
// use those client capabilities.
|
||||
var clientCapabilities = server.editorClientCapabilities;
|
||||
var diagnostics =
|
||||
errors
|
||||
.map(
|
||||
(error) => pluginToDiagnostic(
|
||||
server.uriConverter,
|
||||
(path) => server.getLineInfo(path),
|
||||
error,
|
||||
supportedTags: clientCapabilities?.diagnosticTags,
|
||||
clientSupportsCodeDescription:
|
||||
clientCapabilities?.diagnosticCodeDescription ?? false,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
var diagnostics = errors
|
||||
.map(
|
||||
(error) => pluginToDiagnostic(
|
||||
server.uriConverter,
|
||||
(path) => server.getLineInfo(path),
|
||||
error,
|
||||
supportedTags: clientCapabilities?.diagnosticTags,
|
||||
clientSupportsCodeDescription:
|
||||
clientCapabilities?.diagnosticCodeDescription ?? false,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
server.publishDiagnostics(filePath, diagnostics);
|
||||
}
|
||||
|
||||
@@ -65,8 +65,9 @@ class SemanticTokenEncoder {
|
||||
|
||||
var relativeLine = tokenLine - lastLine;
|
||||
// Column is relative to last only if on the same line.
|
||||
var relativeColumn =
|
||||
relativeLine == 0 ? tokenColumn - lastColumn : tokenColumn;
|
||||
var relativeColumn = relativeLine == 0
|
||||
? tokenColumn - lastColumn
|
||||
: tokenColumn;
|
||||
|
||||
// The resulting array is groups of 5 items as described in the LSP spec:
|
||||
// https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md#textDocument_semanticTokens
|
||||
@@ -106,10 +107,9 @@ class SemanticTokenEncoder {
|
||||
var lineOffset = lineInfo.getOffsetOfLine(lineNumber - 1);
|
||||
|
||||
var startOffset = isFirstLine ? start.columnNumber - 1 : 0;
|
||||
var endOffset =
|
||||
isLastLine
|
||||
? end.columnNumber - 1
|
||||
: lineInfo.getOffsetOfLine(lineNumber) - lineOffset;
|
||||
var endOffset = isLastLine
|
||||
? end.columnNumber - 1
|
||||
: lineInfo.getOffsetOfLine(lineNumber) - lineOffset;
|
||||
var length = endOffset - startOffset;
|
||||
|
||||
yield SemanticTokenInfo(
|
||||
|
||||
@@ -31,28 +31,26 @@ class SemanticTokenLegendLookup {
|
||||
SemanticTokenLegendLookup() {
|
||||
// Build lists of all tokens and modifiers that exist in our mappings or that
|
||||
// we have added as custom types. These will be used to determine the indexes used for communication.
|
||||
_usedTokenTypes =
|
||||
Set.of(
|
||||
highlightRegionTokenTypes.values.followedBy(
|
||||
CustomSemanticTokenTypes.values,
|
||||
),
|
||||
).toList();
|
||||
_usedTokenModifiers =
|
||||
Set.of(
|
||||
highlightRegionTokenModifiers.values.flattenedToList.followedBy(
|
||||
CustomSemanticTokenModifiers.values,
|
||||
),
|
||||
).toList();
|
||||
_usedTokenTypes = Set.of(
|
||||
highlightRegionTokenTypes.values.followedBy(
|
||||
CustomSemanticTokenTypes.values,
|
||||
),
|
||||
).toList();
|
||||
_usedTokenModifiers = Set.of(
|
||||
highlightRegionTokenModifiers.values.flattenedToList.followedBy(
|
||||
CustomSemanticTokenModifiers.values,
|
||||
),
|
||||
).toList();
|
||||
|
||||
// Build the LSP Legend which tells the client all of the tokens and modifiers
|
||||
// we will use in the order they should be accessed by index/bit.
|
||||
lspLegend = SemanticTokensLegend(
|
||||
tokenTypes:
|
||||
_usedTokenTypes.map((tokenType) => tokenType.toString()).toList(),
|
||||
tokenModifiers:
|
||||
_usedTokenModifiers
|
||||
.map((tokenModifier) => tokenModifier.toString())
|
||||
.toList(),
|
||||
tokenTypes: _usedTokenTypes
|
||||
.map((tokenType) => tokenType.toString())
|
||||
.toList(),
|
||||
tokenModifiers: _usedTokenModifiers
|
||||
.map((tokenModifier) => tokenModifier.toString())
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,102 +7,108 @@ import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol_common.dart';
|
||||
|
||||
/// A mapping from [HighlightRegionType] to a set of [SemanticTokenModifiers].
|
||||
final highlightRegionTokenModifiers = <
|
||||
HighlightRegionType,
|
||||
Set<SemanticTokenModifiers>
|
||||
>{
|
||||
HighlightRegionType.COMMENT_DOCUMENTATION: {
|
||||
SemanticTokenModifiers.documentation,
|
||||
},
|
||||
HighlightRegionType.CONSTRUCTOR_TEAR_OFF: {
|
||||
CustomSemanticTokenModifiers.constructor,
|
||||
},
|
||||
HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.IMPORT_PREFIX: {
|
||||
CustomSemanticTokenModifiers.importPrefix,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_FIELD_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_FIELD_REFERENCE: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_GETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_GETTER_REFERENCE: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_METHOD_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_METHOD_REFERENCE: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_METHOD_TEAR_OFF: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_SETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_SETTER_REFERENCE: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.LOCAL_FUNCTION_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.LOCAL_VARIABLE_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.PARAMETER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.STATIC_FIELD_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_GETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_GETTER_REFERENCE: {SemanticTokenModifiers.static},
|
||||
HighlightRegionType.STATIC_METHOD_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_METHOD_REFERENCE: {SemanticTokenModifiers.static},
|
||||
HighlightRegionType.STATIC_METHOD_TEAR_OFF: {SemanticTokenModifiers.static},
|
||||
HighlightRegionType.STATIC_SETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_SETTER_REFERENCE: {SemanticTokenModifiers.static},
|
||||
HighlightRegionType.TOP_LEVEL_FUNCTION_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.TOP_LEVEL_GETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.TOP_LEVEL_SETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.VALID_STRING_ESCAPE: {
|
||||
CustomSemanticTokenModifiers.escape,
|
||||
},
|
||||
};
|
||||
final highlightRegionTokenModifiers =
|
||||
<HighlightRegionType, Set<SemanticTokenModifiers>>{
|
||||
HighlightRegionType.COMMENT_DOCUMENTATION: {
|
||||
SemanticTokenModifiers.documentation,
|
||||
},
|
||||
HighlightRegionType.CONSTRUCTOR_TEAR_OFF: {
|
||||
CustomSemanticTokenModifiers.constructor,
|
||||
},
|
||||
HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.IMPORT_PREFIX: {
|
||||
CustomSemanticTokenModifiers.importPrefix,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_FIELD_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_FIELD_REFERENCE: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_GETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_GETTER_REFERENCE: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_METHOD_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_METHOD_REFERENCE: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_METHOD_TEAR_OFF: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_SETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.INSTANCE_SETTER_REFERENCE: {
|
||||
CustomSemanticTokenModifiers.instance,
|
||||
},
|
||||
HighlightRegionType.LOCAL_FUNCTION_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.LOCAL_VARIABLE_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.PARAMETER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.STATIC_FIELD_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_GETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_GETTER_REFERENCE: {
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_METHOD_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_METHOD_REFERENCE: {
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_METHOD_TEAR_OFF: {
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_SETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.STATIC_SETTER_REFERENCE: {
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.TOP_LEVEL_FUNCTION_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
SemanticTokenModifiers.static,
|
||||
},
|
||||
HighlightRegionType.TOP_LEVEL_GETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.TOP_LEVEL_SETTER_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION: {
|
||||
SemanticTokenModifiers.declaration,
|
||||
},
|
||||
HighlightRegionType.VALID_STRING_ESCAPE: {
|
||||
CustomSemanticTokenModifiers.escape,
|
||||
},
|
||||
};
|
||||
|
||||
/// A mapping from [HighlightRegionType] to [SemanticTokenTypes].
|
||||
///
|
||||
|
||||
@@ -149,20 +149,20 @@ class ServerCapabilitiesComputer {
|
||||
|
||||
ServerCapabilitiesComputer(this._server);
|
||||
|
||||
List<TextDocumentFilterScheme> get pluginTypes =>
|
||||
_server.pluginManager.pluginIsolates
|
||||
.expand(
|
||||
(isolate) =>
|
||||
isolate.currentSession?.interestingFiles ?? const <String>[],
|
||||
)
|
||||
// All published plugins use something like `*.extension` as
|
||||
// interestingFiles. Prefix a `**/` so that the glob matches nested
|
||||
// folders as well.
|
||||
.map(
|
||||
(glob) =>
|
||||
TextDocumentFilterScheme(scheme: 'file', pattern: '**/$glob'),
|
||||
)
|
||||
.toList();
|
||||
List<TextDocumentFilterScheme> get pluginTypes => _server
|
||||
.pluginManager
|
||||
.pluginIsolates
|
||||
.expand(
|
||||
(isolate) =>
|
||||
isolate.currentSession?.interestingFiles ?? const <String>[],
|
||||
)
|
||||
// All published plugins use something like `*.extension` as
|
||||
// interestingFiles. Prefix a `**/` so that the glob matches nested
|
||||
// folders as well.
|
||||
.map(
|
||||
(glob) => TextDocumentFilterScheme(scheme: 'file', pattern: '**/$glob'),
|
||||
)
|
||||
.toList();
|
||||
|
||||
ServerCapabilities computeServerCapabilities(
|
||||
LspClientCapabilities clientCapabilities,
|
||||
@@ -204,12 +204,11 @@ class ServerCapabilitiesComputer {
|
||||
supported: true,
|
||||
changeNotifications: features.changeNotifications.staticRegistration,
|
||||
),
|
||||
fileOperations:
|
||||
!context.clientDynamic.fileOperations
|
||||
? FileOperationOptions(
|
||||
willRename: features.willRename.staticRegistration,
|
||||
)
|
||||
: null,
|
||||
fileOperations: !context.clientDynamic.fileOperations
|
||||
? FileOperationOptions(
|
||||
willRename: features.willRename.staticRegistration,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
experimental: {
|
||||
// 'experimental' is a field we can put any arbitrary data that is not
|
||||
@@ -287,17 +286,15 @@ class ServerCapabilitiesComputer {
|
||||
);
|
||||
var currentRegistrationJsons = currentRegistrationsMap.values.toSet();
|
||||
|
||||
var registrationsToAdd =
|
||||
newRegistrationsMap.entries
|
||||
.where((entry) => !currentRegistrationJsons.contains(entry.value))
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
var registrationsToAdd = newRegistrationsMap.entries
|
||||
.where((entry) => !currentRegistrationJsons.contains(entry.value))
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
|
||||
var registrationsToRemove =
|
||||
currentRegistrationsMap.entries
|
||||
.where((entry) => !newRegistrationsJsons.contains(entry.value))
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
var registrationsToRemove = currentRegistrationsMap.entries
|
||||
.where((entry) => !newRegistrationsJsons.contains(entry.value))
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
|
||||
// Update the current list before we start sending requests since we
|
||||
// go async.
|
||||
@@ -307,10 +304,9 @@ class ServerCapabilitiesComputer {
|
||||
|
||||
Future<void>? unregistrationRequest;
|
||||
if (registrationsToRemove.isNotEmpty) {
|
||||
var unregistrations =
|
||||
registrationsToRemove
|
||||
.map((r) => Unregistration(id: r.id, method: r.method))
|
||||
.toList();
|
||||
var unregistrations = registrationsToRemove
|
||||
.map((r) => Unregistration(id: r.id, method: r.method))
|
||||
.toList();
|
||||
// It's important not to await this request here, as we must ensure
|
||||
// we cannot re-enter this method until we have sent both the unregister
|
||||
// and register requests to the client atomically.
|
||||
|
||||
@@ -28,8 +28,9 @@ String buildSnippetStringForEditGroups(
|
||||
filePath: filePath,
|
||||
editGroups: editGroups,
|
||||
editGroupsOffset: editOffset,
|
||||
selectionOffset:
|
||||
selectionOffset != null ? selectionOffset - editOffset : null,
|
||||
selectionOffset: selectionOffset != null
|
||||
? selectionOffset - editOffset
|
||||
: null,
|
||||
selectionLength: selectionLength,
|
||||
);
|
||||
|
||||
@@ -80,10 +81,9 @@ String _buildSnippetString(
|
||||
// Make the position relative to the supplied text.
|
||||
position.offset - editGroupsOffset,
|
||||
editGroup.length,
|
||||
suggestions:
|
||||
editGroup.suggestions
|
||||
.map((suggestion) => suggestion.value)
|
||||
.toList(),
|
||||
suggestions: editGroup.suggestions
|
||||
.map((suggestion) => suggestion.value)
|
||||
.toList(),
|
||||
// Use the index as an ID to keep all related positions together (so
|
||||
// the remain "linked").
|
||||
linkedGroupId: index,
|
||||
@@ -135,9 +135,8 @@ String _buildSnippetString(
|
||||
/// If there are no edit groups, then placeholders are all simple and
|
||||
/// guaranteed to be in the correct order.
|
||||
var isPreSorted = editGroups.isEmpty;
|
||||
var builder =
|
||||
SnippetBuilder()
|
||||
..appendPlaceholders(text, placeholders, isPreSorted: isPreSorted);
|
||||
var builder = SnippetBuilder()
|
||||
..appendPlaceholders(text, placeholders, isPreSorted: isPreSorted);
|
||||
return builder.value;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,8 +175,9 @@ ErrorOr<List<TextEdit>> generateMinimalEdits(
|
||||
}) {
|
||||
var unformatted = result.content;
|
||||
var lineInfo = result.lineInfo;
|
||||
var rangeStart =
|
||||
range != null ? toOffset(lineInfo, range.start) : success(null);
|
||||
var rangeStart = range != null
|
||||
? toOffset(lineInfo, range.start)
|
||||
: success(null);
|
||||
var rangeEnd = range != null ? toOffset(lineInfo, range.end) : success(null);
|
||||
|
||||
return (rangeStart, rangeEnd).mapResultsSync((rangeStart, rangeEnd) {
|
||||
@@ -328,8 +329,8 @@ class _MinimalEditComputer {
|
||||
|
||||
// Walk through the token streams computing edits for the differences.
|
||||
bool unformattedHasMore, formattedHasMore;
|
||||
while ((unformattedHasMore =
|
||||
unformattedTokens.moveNext()) & // Don't short-circuit.
|
||||
while ((unformattedHasMore = unformattedTokens
|
||||
.moveNext()) & // Don't short-circuit.
|
||||
(formattedHasMore = formattedTokens.moveNext())) {
|
||||
var unformattedToken = unformattedTokens.current;
|
||||
var formattedToken = formattedTokens.current;
|
||||
@@ -675,14 +676,15 @@ class _MinimalEditComputer {
|
||||
/// be parsed.
|
||||
static Token? _parse(String s, FeatureSet featureSet) {
|
||||
try {
|
||||
var scanner = Scanner(
|
||||
_SourceMock.instance,
|
||||
CharSequenceReader(s),
|
||||
DiagnosticListener.nullListener,
|
||||
)..configureFeatures(
|
||||
featureSetForOverriding: featureSet,
|
||||
featureSet: featureSet,
|
||||
);
|
||||
var scanner =
|
||||
Scanner(
|
||||
_SourceMock.instance,
|
||||
CharSequenceReader(s),
|
||||
DiagnosticListener.nullListener,
|
||||
)..configureFeatures(
|
||||
featureSetForOverriding: featureSet,
|
||||
featureSet: featureSet,
|
||||
);
|
||||
return scanner.tokenize();
|
||||
} catch (e) {
|
||||
return null;
|
||||
|
||||
@@ -50,12 +50,11 @@ Future<void> scheduleImplementedNotification(
|
||||
|
||||
void sendAnalysisNotificationAnalyzedFiles(LegacyAnalysisServer server) {
|
||||
_sendNotification(server, () {
|
||||
var analyzedFiles =
|
||||
server.driverMap.values
|
||||
.map((driver) => driver.knownFiles)
|
||||
.flattenedToList
|
||||
.map((file) => file.path)
|
||||
.toSet();
|
||||
var analyzedFiles = server.driverMap.values
|
||||
.map((driver) => driver.knownFiles)
|
||||
.flattenedToList
|
||||
.map((file) => file.path)
|
||||
.toSet();
|
||||
|
||||
// Exclude *.yaml files because IDEA Dart plugin attempts to index
|
||||
// all the files in folders which contain analyzed files.
|
||||
@@ -138,8 +137,10 @@ void sendAnalysisNotificationOutline(
|
||||
var libraryName = _computeLibraryName(unit);
|
||||
|
||||
// compute Outline
|
||||
var outline =
|
||||
DartUnitOutlineComputer(resolvedUnit, withBasicFlutter: true).compute();
|
||||
var outline = DartUnitOutlineComputer(
|
||||
resolvedUnit,
|
||||
withBasicFlutter: true,
|
||||
).compute();
|
||||
|
||||
// send notification
|
||||
var params = protocol.AnalysisOutlineParams(
|
||||
|
||||
@@ -646,11 +646,10 @@ class PluginManager {
|
||||
var uri = Uri.parse('package:$packageName/$packageName.dart');
|
||||
var packageSource = packageUriResolver.resolveAbsolute(uri);
|
||||
if (packageSource != null) {
|
||||
var packageRoot =
|
||||
_resourceProvider
|
||||
.getFile(packageSource.fullName)
|
||||
.parent
|
||||
.parent;
|
||||
var packageRoot = _resourceProvider
|
||||
.getFile(packageSource.fullName)
|
||||
.parent
|
||||
.parent;
|
||||
packages.add(_Package(packageName, packageRoot));
|
||||
pubspecFiles.add(
|
||||
packageRoot.getChildAssumingFile(file_paths.pubspecYaml),
|
||||
|
||||
@@ -16,13 +16,12 @@ class ResultConverter {
|
||||
server.AnalysisErrorFixes convertAnalysisErrorFixes(
|
||||
plugin.AnalysisErrorFixes fixes,
|
||||
) {
|
||||
var changes =
|
||||
fixes.fixes
|
||||
.map(
|
||||
(plugin.PrioritizedSourceChange change) =>
|
||||
convertPrioritizedSourceChange(change),
|
||||
)
|
||||
.toList();
|
||||
var changes = fixes.fixes
|
||||
.map(
|
||||
(plugin.PrioritizedSourceChange change) =>
|
||||
convertPrioritizedSourceChange(change),
|
||||
)
|
||||
.toList();
|
||||
return server.AnalysisErrorFixes(fixes.error, fixes: changes);
|
||||
}
|
||||
|
||||
|
||||
@@ -302,11 +302,10 @@ class ResultMerger {
|
||||
//
|
||||
for (var j = 0; j < regions.length; j++) {
|
||||
var region = regions[j];
|
||||
var newTargets =
|
||||
region.targets
|
||||
.map((int oldTarget) => targetMap[oldTarget])
|
||||
.toList()
|
||||
.cast<int>();
|
||||
var newTargets = region.targets
|
||||
.map((int oldTarget) => targetMap[oldTarget])
|
||||
.toList()
|
||||
.cast<int>();
|
||||
if (region.targets != newTargets) {
|
||||
region = NavigationRegion(region.offset, region.length, newTargets);
|
||||
}
|
||||
@@ -496,8 +495,9 @@ class ResultMerger {
|
||||
if (currentChildren == null || currentChildren.isEmpty) {
|
||||
return outline;
|
||||
}
|
||||
var updatedChildren =
|
||||
currentChildren.map((Outline child) => traverse(child)).toList();
|
||||
var updatedChildren = currentChildren
|
||||
.map((Outline child) => traverse(child))
|
||||
.toList();
|
||||
if (currentChildren != updatedChildren) {
|
||||
if (!isCopied) {
|
||||
return Outline(
|
||||
@@ -604,14 +604,12 @@ class ResultMerger {
|
||||
names.toList(),
|
||||
offsets,
|
||||
lengths,
|
||||
coveringExpressionOffsets:
|
||||
coveringExpressionOffsets.isEmpty
|
||||
? null
|
||||
: coveringExpressionOffsets,
|
||||
coveringExpressionLengths:
|
||||
coveringExpressionLengths.isEmpty
|
||||
? null
|
||||
: coveringExpressionLengths,
|
||||
coveringExpressionOffsets: coveringExpressionOffsets.isEmpty
|
||||
? null
|
||||
: coveringExpressionOffsets,
|
||||
coveringExpressionLengths: coveringExpressionLengths.isEmpty
|
||||
? null
|
||||
: coveringExpressionLengths,
|
||||
);
|
||||
} else if (first is ExtractMethodFeedback) {
|
||||
var offset = first.offset;
|
||||
|
||||
@@ -186,10 +186,9 @@ AnalysisError newAnalysisError_fromEngine(
|
||||
var code = diagnosticCode.name.toLowerCase();
|
||||
List<DiagnosticMessage>? contextMessages;
|
||||
if (diagnostic.contextMessages.isNotEmpty) {
|
||||
contextMessages =
|
||||
diagnostic.contextMessages
|
||||
.map((message) => newDiagnosticMessage(result, message))
|
||||
.toList();
|
||||
contextMessages = diagnostic.contextMessages
|
||||
.map((message) => newDiagnosticMessage(result, message))
|
||||
.toList();
|
||||
}
|
||||
var correction = diagnostic.correctionMessage;
|
||||
var url = diagnosticCode.url;
|
||||
|
||||
@@ -94,11 +94,10 @@ final class MessageScheduler {
|
||||
var request = message.request;
|
||||
var method = request.method;
|
||||
if (method == legacy.SERVER_REQUEST_CANCEL_REQUEST) {
|
||||
var id =
|
||||
legacy.ServerCancelRequestParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).id;
|
||||
var id = legacy.ServerCancelRequestParams.fromRequest(
|
||||
request,
|
||||
clientUriConverter: server.uriConverter,
|
||||
).id;
|
||||
listener?.addActiveMessage(message);
|
||||
(server as LegacyAnalysisServer).cancelRequest(id);
|
||||
// The message needs to be added to the queue of pending messages, but
|
||||
@@ -154,10 +153,9 @@ final class MessageScheduler {
|
||||
// Cancel in progress completion and refactoring requests.
|
||||
var incomingMsgMethod = msg.method;
|
||||
if (_isCancelableRequest(msg)) {
|
||||
var reason =
|
||||
incomingMsgMethod == lsp.Method.workspace_executeCommand
|
||||
? 'Another workspace/executeCommand request for a refactor was started'
|
||||
: 'Another textDocument/completion request was started';
|
||||
var reason = incomingMsgMethod == lsp.Method.workspace_executeCommand
|
||||
? 'Another workspace/executeCommand request for a refactor was started'
|
||||
: 'Another textDocument/completion request was started';
|
||||
for (var activeMessage in _activeMessages) {
|
||||
if (activeMessage is LspMessage && activeMessage.isRequest) {
|
||||
var message = activeMessage.message as lsp.RequestMessage;
|
||||
|
||||
@@ -71,10 +71,9 @@ class TypeHierarchyComputer {
|
||||
var subMemberElementDeclared = subMemberElement?.nonSynthetic;
|
||||
subItem = TypeHierarchyItem(
|
||||
convertElement(subElement),
|
||||
memberElement:
|
||||
subMemberElementDeclared != null
|
||||
? convertElement(subMemberElementDeclared)
|
||||
: null,
|
||||
memberElement: subMemberElementDeclared != null
|
||||
? convertElement(subMemberElementDeclared)
|
||||
: null,
|
||||
superclass: itemId,
|
||||
);
|
||||
var subItemId = _items.length;
|
||||
@@ -124,10 +123,9 @@ class TypeHierarchyComputer {
|
||||
item = TypeHierarchyItem(
|
||||
convertElement(classElement),
|
||||
displayName: displayName,
|
||||
memberElement:
|
||||
memberElementDeclared != null
|
||||
? convertElement(memberElementDeclared)
|
||||
: null,
|
||||
memberElement: memberElementDeclared != null
|
||||
? convertElement(memberElementDeclared)
|
||||
: null,
|
||||
);
|
||||
_elementItemMap[classElement] = item;
|
||||
itemId = _items.length;
|
||||
|
||||
@@ -20,13 +20,12 @@ class CrashReportingInstrumentation extends NoopInstrumentationService {
|
||||
StackTrace? stackTrace,
|
||||
List<InstrumentationServiceAttachment>? attachments,
|
||||
]) {
|
||||
var crashReportAttachments =
|
||||
(attachments ?? []).map((e) {
|
||||
return CrashReportAttachment.string(
|
||||
field: 'attachment_${e.id}',
|
||||
value: e.stringValue,
|
||||
);
|
||||
}).toList();
|
||||
var crashReportAttachments = (attachments ?? []).map((e) {
|
||||
return CrashReportAttachment.string(
|
||||
field: 'attachment_${e.id}',
|
||||
value: e.stringValue,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
if (exception is CaughtException) {
|
||||
// Get the root CaughtException, which matters most for debugging.
|
||||
|
||||
@@ -142,8 +142,9 @@ class DevAnalysisServer {
|
||||
}),
|
||||
);
|
||||
|
||||
directories =
|
||||
directories.map((dir) => path.normalize(path.absolute(dir))).toList();
|
||||
directories = directories
|
||||
.map((dir) => path.normalize(path.absolute(dir)))
|
||||
.toList();
|
||||
|
||||
await _channel.simulateRequestFromClient(
|
||||
Request('${_nextId++}', 'analysis.setAnalysisRoots', {
|
||||
|
||||
@@ -377,10 +377,9 @@ class Driver implements ServerStarter {
|
||||
ErrorNotifier errorNotifier,
|
||||
SendPort? sendPort,
|
||||
) {
|
||||
var capture =
|
||||
results.flag(DISABLE_SERVER_EXCEPTION_HANDLING)
|
||||
? (_, Function f, {void Function(String)? print}) => f()
|
||||
: _captureExceptions;
|
||||
var capture = results.flag(DISABLE_SERVER_EXCEPTION_HANDLING)
|
||||
? (_, Function f, {void Function(String)? print}) => f()
|
||||
: _captureExceptions;
|
||||
var trainDirectory = results.option(TRAIN_USING);
|
||||
if (trainDirectory != null) {
|
||||
if (!FileSystemEntity.isDirectorySync(trainDirectory)) {
|
||||
@@ -479,10 +478,9 @@ class Driver implements ServerStarter {
|
||||
if (sendPort == null) exit(0);
|
||||
});
|
||||
},
|
||||
print:
|
||||
results.flag(INTERNAL_PRINT_TO_CONSOLE)
|
||||
? null
|
||||
: diagnosticServer.httpServer.recordPrint,
|
||||
print: results.flag(INTERNAL_PRINT_TO_CONSOLE)
|
||||
? null
|
||||
: diagnosticServer.httpServer.recordPrint,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -496,10 +494,9 @@ class Driver implements ServerStarter {
|
||||
int? diagnosticServerPort,
|
||||
ErrorNotifier errorNotifier,
|
||||
) {
|
||||
var capture =
|
||||
args.flag(DISABLE_SERVER_EXCEPTION_HANDLING)
|
||||
? (_, Function f, {void Function(String)? print}) => f()
|
||||
: _captureExceptions;
|
||||
var capture = args.flag(DISABLE_SERVER_EXCEPTION_HANDLING)
|
||||
? (_, Function f, {void Function(String)? print}) => f()
|
||||
: _captureExceptions;
|
||||
|
||||
linter.registerLintRules();
|
||||
registerBuiltInAssistGenerators();
|
||||
@@ -555,14 +552,13 @@ class Driver implements ServerStarter {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
var printFunction =
|
||||
print == null
|
||||
? null
|
||||
: (Zone self, ZoneDelegate parent, Zone zone, String line) {
|
||||
// Note: we don't pass the line on to stdout, because that is
|
||||
// reserved for communication to the client.
|
||||
print(line);
|
||||
};
|
||||
var printFunction = print == null
|
||||
? null
|
||||
: (Zone self, ZoneDelegate parent, Zone zone, String line) {
|
||||
// Note: we don't pass the line on to stdout, because that is
|
||||
// reserved for communication to the client.
|
||||
print(line);
|
||||
};
|
||||
var zoneSpecification = ZoneSpecification(
|
||||
handleUncaughtError: errorFunction,
|
||||
print: printFunction,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user