private static async Task <(ImmutableHashSet <string> remoteRootPaths, ImmutableHashSet <string> externalPaths)> GetLocalPathsOfRemoteRootsAsync(CollaborationSession session)
        {
            var roots = await session.ListRootsAsync(CancellationToken.None).ConfigureAwait(false);

            var localPathsOfRemoteRoots = roots.Select(root => session.ConvertSharedUriToLocalPath(root)).ToImmutableArray();

            var remoteRootPaths = ImmutableHashSet.CreateBuilder <string>();
            var externalPaths   = ImmutableHashSet.CreateBuilder <string>();

            foreach (var localRoot in localPathsOfRemoteRoots)
            {
                // The local root is something like tmp\\xxx\\<workspace name>
                // The external root should be tmp\\xxx\\~external, so replace the workspace name with ~external.
#pragma warning disable CS8602 // Dereference of a possibly null reference. (Can localRoot be null here?)
                var splitRoot = localRoot.TrimEnd('\\').Split('\\');
#pragma warning restore CS8602 // Dereference of a possibly null reference.
                splitRoot[splitRoot.Length - 1] = "~external";
                var externalPath = string.Join("\\", splitRoot) + "\\";

                remoteRootPaths.Add(localRoot);
                externalPaths.Add(externalPath);
            }

            return(remoteRootPaths.ToImmutable(), externalPaths.ToImmutable());
        }
        // Today we ensure that all _ViewImports in the shared project exist on the guest because we don't currently track import documents
        // in a manner that would allow us to retrieve/monitor that data across the wire. Once the Razor sub-system is moved to use
        // DocumentSnapshots we'll be able to rely on that API to more properly manage files that impact parsing of Razor documents.
        private async Task EnsureViewImportsCopiedAsync(CollaborationSession sessionContext, CancellationToken cancellationToken)
        {
            var listDirectoryOptions = new ListDirectoryOptions()
            {
                Recursive       = true,
                IncludePatterns = new[] { "*.cshtml" }
            };

            var copyTasks = new List <Task>();

            try
            {
                var roots = await sessionContext.ListRootsAsync(cancellationToken);

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                foreach (var root in roots)
                {
                    var fileUris = await sessionContext.ListDirectoryAsync(root, listDirectoryOptions, cancellationToken);

                    StartViewImportsCopy(fileUris, copyTasks, sessionContext, cancellationToken);
                }

                await Task.WhenAll(copyTasks);
            }
            catch (OperationCanceledException)
            {
                // Swallow task cancellations
            }
        }
        public async Task SetSession(CollaborationSession session)
        {
            _session = session;
            var roots = await session.ListRootsAsync(CancellationToken.None).ConfigureAwait(false);

            _remoteRootPath = session.ConvertSharedUriToLocalPath(roots[0]);
            _remoteRootPath = _remoteRootPath.Substring(0, _remoteRootPath.Length - 1);
            var lastSlash = _remoteRootPath.LastIndexOf('\\');

            _externalPath   = _remoteRootPath.Substring(0, lastSlash + 1);
            _externalPath  += "~external";
            IsRemoteSession = true;
            session.RemoteServicesChanged += (object sender, RemoteServicesChangedEventArgs e) =>
            {
                _remoteDiagnosticListTable.UpdateWorkspaceDiagnosticsPresent(_session.RemoteServiceNames.Contains("workspaceDiagnostics"));
            };
        }
        // Today we ensure that all _ViewImports in the shared project exist on the guest because we don't currently track import documents
        // in a manner that would allow us to retrieve/monitor that data across the wire. Once the Razor sub-system is moved to use
        // DocumentSnapshots we'll be able to rely on that API to more properly manage files that impact parsing of Razor documents.
        private async Task EnsureViewImportsCopiedAsync(CollaborationSession sessionContext, CancellationToken cancellationToken)
        {
            var listDirectoryOptions = new ListDirectoryOptions()
            {
                Recursive       = true,
                IncludePatterns = new[] { "*.cshtml" }
            };

            var copyTasks = new List <Task>();
            var roots     = await sessionContext.ListRootsAsync(cancellationToken);

            foreach (var root in roots)
            {
                var fileUris = await sessionContext.ListDirectoryAsync(root, listDirectoryOptions, cancellationToken);

                StartViewImportsCopy(fileUris, copyTasks, sessionContext, cancellationToken);
            }

            await Task.WhenAll(copyTasks);
        }