Version 2.19.0-2.0.dev

Merge commit '1a69106f2675528b61dc78bc47d2443b5eedf967' into 'dev'
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 64db45c..92511cc 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -307,6 +307,8 @@
   @visibleForTesting
   Duration pendingFilesRemoveOverlayDelay = const Duration(seconds: 10);
 
+  /// An optional manager to handle file systems which may not always be
+  /// available.
   final DetachableFileSystemManager? detachableFileSystemManager;
 
   /// The broadcast stream of requests that were discarded because there
diff --git a/pkg/analysis_server/lib/src/handler/legacy/analysis_set_analysis_roots.dart b/pkg/analysis_server/lib/src/handler/legacy/analysis_set_analysis_roots.dart
index d01a068..70aee15 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/analysis_set_analysis_roots.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/analysis_set_analysis_roots.dart
@@ -44,9 +44,8 @@
 
     var detachableFileSystemManager = server.detachableFileSystemManager;
     if (detachableFileSystemManager != null) {
-      // TODO(scheglov) remove the last argument
-      detachableFileSystemManager
-          .setAnalysisRoots(request.id, includedPathList, excludedPathList, {});
+      detachableFileSystemManager.setAnalysisRoots(
+          request.id, includedPathList, excludedPathList);
     } else {
       await server.setAnalysisRoots(
           request.id, includedPathList, excludedPathList);
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 5d42f49..fb5c39c 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -433,12 +433,7 @@
           item,
           replacementRange: replacementRange,
           insertionRange: insertionRange,
-          // TODO(dantup): Move commit characters to the main response
-          // and remove from each individual item (to reduce payload size)
-          // once the following change ships (and the Dart VS Code
-          // extension is updated to use it).
-          // https://github.com/microsoft/vscode-languageserver-node/issues/673
-          includeCommitCharacters:
+          commitCharactersEnabled:
               server.clientConfiguration.global.previewCommitCharacters,
           completeFunctionCalls: completeFunctionCalls,
           resolutionData: resolutionInfo,
@@ -555,12 +550,7 @@
                       completionRequest.replacementOffset,
                       insertLength,
                       completionRequest.replacementLength,
-                      // TODO(dantup): Move commit characters to the main response
-                      // and remove from each individual item (to reduce payload size)
-                      // once the following change ships (and the Dart VS Code
-                      // extension is updated to use it).
-                      // https://github.com/microsoft/vscode-languageserver-node/issues/673
-                      includeCommitCharacters: server
+                      commitCharactersEnabled: server
                           .clientConfiguration.global.previewCommitCharacters,
                       completeFunctionCalls: completeFunctionCalls,
                     ));
@@ -645,7 +635,7 @@
             item,
             replacementRange: replacementRange,
             insertionRange: insertionRange,
-            includeCommitCharacters: false,
+            commitCharactersEnabled: false,
             completeFunctionCalls: false,
             // Add on any completion-kind-specific resolution data that will be
             // used during resolve() calls to provide additional information.
@@ -714,7 +704,7 @@
           // Plugins cannot currently contribute commit characters and we should
           // not assume that the Dart ones would be correct for all of their
           // completions.
-          includeCommitCharacters: false,
+          commitCharactersEnabled: false,
           completeFunctionCalls: false,
         ),
       );
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 442bfe4..f28d646 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -26,6 +26,7 @@
 import 'package:analysis_server/src/plugin/plugin_manager.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
+import 'package:analysis_server/src/server/detachable_filesystem_manager.dart';
 import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/server/error_notifier.dart';
 import 'package:analysis_server/src/server/performance.dart';
@@ -120,6 +121,10 @@
   /// Starts completed and will be replaced each time a context rebuild starts.
   Completer<void> _analysisContextRebuildCompleter = Completer()..complete();
 
+  /// An optional manager to handle file systems which may not always be
+  /// available.
+  final DetachableFileSystemManager? detachableFileSystemManager;
+
   /// Initialize a newly created server to send and receive messages to the
   /// given [channel].
   LspAnalysisServer(
@@ -133,6 +138,7 @@
     http.Client? httpClient,
     ProcessRunner? processRunner,
     DiagnosticServer? diagnosticServer,
+    this.detachableFileSystemManager,
     // Disable to avoid using this in unit tests.
     bool enableBazelWatcher = false,
   }) : super(
@@ -723,6 +729,8 @@
   Future<void> shutdown() {
     super.shutdown();
 
+    detachableFileSystemManager?.dispose();
+
     // Defer closing the channel so that the shutdown response can be sent and
     // logged.
     Future(() {
@@ -852,10 +860,16 @@
 
     final completer = _analysisContextRebuildCompleter = Completer();
     try {
+      var includedPathsList = includedPaths.toList();
+      var excludedPathsList = excludedPaths.toList();
       notificationManager.setAnalysisRoots(
-          includedPaths.toList(), excludedPaths.toList());
-      await contextManager.setRoots(
-          includedPaths.toList(), excludedPaths.toList());
+          includedPathsList, excludedPathsList);
+      if (detachableFileSystemManager != null) {
+        detachableFileSystemManager?.setAnalysisRoots(
+            null, includedPathsList, excludedPathsList);
+      } else {
+        await contextManager.setRoots(includedPathsList, excludedPathsList);
+      }
     } finally {
       completer.complete();
     }
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
index 45e8ba7..bb17ff6 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
+import 'package:analysis_server/src/server/detachable_filesystem_manager.dart';
 import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/socket_server.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
@@ -39,12 +40,17 @@
 
   final InstrumentationService instrumentationService;
 
+  /// An optional manager to handle file systems which may not always be
+  /// available.
+  final DetachableFileSystemManager? detachableFileSystemManager;
+
   LspSocketServer(
     this.analysisServerOptions,
     this.diagnosticServer,
     this.analyticsManager,
     this.sdkManager,
     this.instrumentationService,
+    this.detachableFileSystemManager,
   );
 
   /// Create an analysis server which will communicate with the client using the
@@ -73,7 +79,7 @@
     var resourceProvider = PhysicalResourceProvider(
         stateLocation: analysisServerOptions.cacheFolder);
 
-    analysisServer = LspAnalysisServer(
+    var server = analysisServer = LspAnalysisServer(
       serverChannel,
       resourceProvider,
       analysisServerOptions,
@@ -82,7 +88,9 @@
       CrashReportingAttachmentsBuilder.empty,
       instrumentationService,
       diagnosticServer: diagnosticServer,
+      detachableFileSystemManager: detachableFileSystemManager,
       enableBazelWatcher: true,
     );
+    detachableFileSystemManager?.setAnalysisServer(server);
   }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 284c4ad..d7ada24 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -277,7 +277,7 @@
   int replacementOffset,
   int insertLength,
   int replacementLength, {
-  required bool includeCommitCharacters,
+  required bool commitCharactersEnabled,
   required bool completeFunctionCalls,
 }) {
   final supportsSnippets = capabilities.completionSnippets;
@@ -304,7 +304,7 @@
 
   final insertTextInfo = _buildInsertText(
     supportsSnippets: supportsSnippets,
-    includeCommitCharacters: includeCommitCharacters,
+    commitCharactersEnabled: commitCharactersEnabled,
     completeFunctionCalls: completeFunctionCalls,
     isCallable: isCallable,
     // For SuggestionSets, we don't have a CompletionKind to check if it's
@@ -349,8 +349,6 @@
       if (supportsDeprecatedTag && declaration.isDeprecated)
         lsp.CompletionItemTag.Deprecated
     ]),
-    commitCharacters:
-        includeCommitCharacters ? lsp.dartCompletionCommitCharacters : null,
     detail: getDeclarationCompletionDetail(declaration, completionKind,
         supportsDeprecatedFlag || supportsDeprecatedTag),
     deprecated:
@@ -1109,7 +1107,7 @@
   required Range replacementRange,
   required Range insertionRange,
   bool includeDocs = true,
-  required bool includeCommitCharacters,
+  required bool commitCharactersEnabled,
   required bool completeFunctionCalls,
   CompletionItemResolutionInfo? resolutionData,
 }) {
@@ -1163,7 +1161,7 @@
 
   final insertTextInfo = _buildInsertText(
     supportsSnippets: supportsSnippets,
-    includeCommitCharacters: includeCommitCharacters,
+    commitCharactersEnabled: commitCharactersEnabled,
     completeFunctionCalls: completeFunctionCalls,
     isCallable: isCallable,
     isInvocation: isInvocation,
@@ -1203,8 +1201,6 @@
       if (supportsDeprecatedTag && suggestion.isDeprecated)
         lsp.CompletionItemTag.Deprecated
     ]),
-    commitCharacters:
-        includeCommitCharacters ? dartCompletionCommitCharacters : null,
     data: resolutionData,
     detail: detail,
     documentation: cleanedDoc != null && includeDocs
@@ -1635,7 +1631,7 @@
 
 Pair<String, lsp.InsertTextFormat> _buildInsertText({
   required bool supportsSnippets,
-  required bool includeCommitCharacters,
+  required bool commitCharactersEnabled,
   required bool completeFunctionCalls,
   required bool isCallable,
   required bool isInvocation,
@@ -1662,7 +1658,7 @@
   if (supportsSnippets) {
     // completeFunctionCalls should only work if commit characters are disabled
     // otherwise the editor may insert parens that we're also inserting.
-    if (!includeCommitCharacters &&
+    if (!commitCharactersEnabled &&
         completeFunctionCalls &&
         isCallable &&
         isInvocation) {
diff --git a/pkg/analysis_server/lib/src/server/detachable_filesystem_manager.dart b/pkg/analysis_server/lib/src/server/detachable_filesystem_manager.dart
index d32ca39..d1319ad 100644
--- a/pkg/analysis_server/lib/src/server/detachable_filesystem_manager.dart
+++ b/pkg/analysis_server/lib/src/server/detachable_filesystem_manager.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/analysis_server_abstract.dart';
 
 /// A class that can be used to configure an analysis server instance to better
 /// support intermittent file systems.
@@ -19,9 +19,9 @@
   /// underlying analysis server, it can choose to modify the given
   /// [includedPaths] and other parameters, or it could choose to delays calls
   /// to [setAnalysisRoots].
-  void setAnalysisRoots(String requestId, List<String> includedPaths,
-      List<String> excludedPaths, Map<String, String> packageRoots);
+  void setAnalysisRoots(String? requestId, List<String> includedPaths,
+      List<String> excludedPaths);
 
   /// Called exactly once before any calls to [setAnalysisRoots].
-  void setAnalysisServer(AnalysisServer server);
+  void setAnalysisServer(AbstractAnalysisServer server);
 }
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index f553451..3dbc84e 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -482,12 +482,12 @@
     var diagnosticServer = _DiagnosticServerImpl();
 
     final socketServer = LspSocketServer(
-      analysisServerOptions,
-      diagnosticServer,
-      analyticsManager,
-      dartSdkManager,
-      instrumentationService,
-    );
+        analysisServerOptions,
+        diagnosticServer,
+        analyticsManager,
+        dartSdkManager,
+        instrumentationService,
+        detachableFileSystemManager);
     errorNotifier.server = socketServer.analysisServer;
 
     diagnosticServer.httpServer = httpServer = HttpAnalysisServer(socketServer);
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index e30600c..b32dcd8 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -47,6 +47,8 @@
   /// The object through which analytics are to be sent.
   final AnalyticsManager analyticsManager;
 
+  /// An optional manager to handle file systems which may not always be
+  /// available.
   final DetachableFileSystemManager? detachableFileSystemManager;
 
   /// The analysis server that was created when a client established a
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index 86f2b06..287215b 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -124,32 +124,7 @@
     expect(res, isEmpty);
   }
 
-  Future<void> test_commitCharacter_completionItem() async {
-    await provideConfig(
-      () => initialize(
-        textDocumentCapabilities:
-            withAllSupportedTextDocumentDynamicRegistrations(
-                emptyTextDocumentClientCapabilities),
-        workspaceCapabilities:
-            withConfigurationSupport(emptyWorkspaceClientCapabilities),
-      ),
-      {'previewCommitCharacters': true},
-    );
-
-    final content = '''
-void f() {
-  pri^
-}
-    ''';
-
-    await openFile(mainFileUri, withoutMarkers(content));
-    final res = await getCompletion(mainFileUri, positionFromMarker(content));
-
-    final print = res.singleWhere((c) => c.label == 'print(…)');
-    expect(print.commitCharacters, equals(dartCompletionCommitCharacters));
-  }
-
-  Future<void> test_commitCharacter_config() async {
+  Future<void> test_commitCharacter_dynamicRegistration() async {
     final registrations = <Registration>[];
     // Provide empty config and collect dynamic registrations during
     // initialization.
diff --git a/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
index 89af3ef..7da38f7 100644
--- a/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
+++ b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
@@ -23,6 +23,7 @@
   final bool withKeysGetPut;
 
   String _indent = '';
+  final Set<LibraryCycle> _libraryCyclesWithWrittenDetails = Set.identity();
 
   AnalyzerStatePrinter({
     required this.byteStore,
@@ -509,6 +510,11 @@
   void _writeLibraryCycle(LibraryFileStateKind library) {
     final cycle = library.libraryCycle;
     _writelnWithIndent(idProvider.libraryCycle(cycle));
+
+    if (!_libraryCyclesWithWrittenDetails.add(cycle)) {
+      return;
+    }
+
     _withIndent(() {
       final dependencyIds = cycle.directDependencies
           .map(_stringOfLibraryCycle)
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 2ad78f3..f158a29 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -472,7 +472,6 @@
 
     fileStateFor(a);
 
-    // TODO(scheglov) Write details for a cycle only once.
     assertDriverStateString(testFile, r'''
 files
   /home/test/lib/a.dart
@@ -500,9 +499,6 @@
         exports
           library_0
         cycle_0
-          dependencies: dart:core
-          libraries: library_0 library_1
-          apiSignature_0
       referencingFiles: file_0
       unlinkedKey: k01
 libraryCycles
@@ -558,7 +554,6 @@
 
     fileStateFor(a);
 
-    // TODO(scheglov) Write details for a cycle only once.
     assertDriverStateString(testFile, r'''
 files
   /home/test/lib/a.dart
@@ -584,9 +579,6 @@
           library_0
           library_2 dart:core synthetic
         cycle_0
-          dependencies: dart:core
-          libraries: library_0 library_1
-          apiSignature_0
       referencingFiles: file_0
       unlinkedKey: k01
 libraryCycles
diff --git a/tools/VERSION b/tools/VERSION
index 7bc95cb..7e38b09 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 1
+PRERELEASE 2
 PRERELEASE_PATCH 0
\ No newline at end of file