<commit_before>﻿// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using EnvDTE;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Extensions;
using Microsoft.VisualStudio.LanguageServices.Implementation.Venus;
using Microsoft.VisualStudio.LanguageServices.Utilities;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Projection;
using Roslyn.Utilities;
using VSLangProj;
using VSLangProj140;
using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider;
using OleInterop = Microsoft.VisualStudio.OLE.Interop;

namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
    /// <summary>
    /// The Workspace for running inside Visual Studio.
    /// </summary>
    internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspace
    {
        private static readonly IntPtr s_docDataExisting_Unknown = new IntPtr(-1);
        private const string AppCodeFolderName = "App_Code";

        private readonly IThreadingContext _threadingContext;
        private readonly ITextBufferFactoryService _textBufferFactoryService;
        private readonly IProjectionBufferFactoryService _projectionBufferFactoryService;

        [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")]
        private readonly Lazy<VisualStudioProjectFactory> _projectFactory;

        private readonly ITextBufferCloneService _textBufferCloneService;

        // document worker coordinator
        private ISolutionCrawlerRegistrationService _registrationService;

        /// <summary>
        /// A <see cref="ForegroundThreadAffinitizedObject"/> to make assertions that stuff is on the right thread.
        /// </summary>
        private readonly ForegroundThreadAffinitizedObject _foregroundObject;

        private ImmutableDictionary<ProjectId, IVsHierarchy> _projectToHierarchyMap = ImmutableDictionary<ProjectId, IVsHierarchy>.Empty;
        private ImmutableDictionary<ProjectId, Guid> _projectToGuidMap = ImmutableDictionary<ProjectId, Guid>.Empty;
        private ImmutableDictionary<string, VisualStudioProject> _projectUniqueNameToProjectMap = ImmutableDictionary<string, VisualStudioProject>.Empty;

        /// <summary>
        /// A set of documents that were added by <see cref="VisualStudioProject.AddSourceTextContainer"/>, and aren't otherwise
        /// tracked for opening/closing.
        /// </summary>
        private ImmutableHashSet<DocumentId> _documentsNotFromFiles = ImmutableHashSet<DocumentId>.Empty;

        internal VisualStudioProjectTracker _projectTracker;

        private OpenFileTracker _openFileTrackerOpt;
        internal FileChangeWatcher FileChangeWatcher { get; }

        public VisualStudioWorkspaceImpl(ExportProvider exportProvider, IAsyncServiceProvider asyncServiceProvider)
            : base(VisualStudioMefHostServices.Create(exportProvider))
        {
            _threadingContext = exportProvider.GetExportedValue<IThreadingContext>();
            _textBufferCloneService = exportProvider.GetExportedValue<ITextBufferCloneService>();
            _textBufferFactoryService = exportProvider.GetExportedValue<ITextBufferFactoryService>();
            _projectionBufferFactoryService = exportProvider.GetExportedValue<IProjectionBufferFactoryService>();

            // We fetch this lazily because VisualStudioProjectFactory depends on VisualStudioWorkspaceImpl -- we have a circularity. Since this
            // exists right now as a compat shim, we'll just do this.
#pragma warning disable CS0618 // Type or member is obsolete
            _projectFactory = exportProvider.GetExport<VisualStudioProjectFactory>();
#pragma warning restore CS0618 // Type or member is obsolete

            _foregroundObject = new ForegroundThreadAffinitizedObject(_threadingContext);

            _textBufferFactoryService.TextBufferCreated += AddTextBufferCloneServiceToBuffer;
            _projectionBufferFactoryService.ProjectionBufferCreated += AddTextBufferCloneServiceToBuffer;
            exportProvider.GetExportedValue<PrimaryWorkspace>().Register(this);

            System.Threading.Tasks.Task.Run(() => ConnectToOpenFileTrackerOnUIThreadAsync(asyncServiceProvider));

            var fileChangeWatcherProvider = exportProvider.GetExportedValue<FileChangeWatcherProvider>();

            FileChangeWatcher = fileChangeWatcherProvider.Watcher;
            _threadingContext.JoinableTaskFactory.RunAsync(async () =>
                {
                    await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync();
                    var fileChangeService = (IVsAsyncFileChangeEx)await asyncServiceProvider.GetServiceAsync(typeof(SVsFileChangeEx)).ConfigureAwait(false);
                    
                    fileChangeWatcherProvider.SetFileChangeService(fileChangeService);
                });
        }

        public async System.Threading.Tasks.Task ConnectToOpenFileTrackerOnUIThreadAsync(IAsyncServiceProvider asyncServiceProvider)
        {
            // Create services that are bound to the UI thread
            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync();

            var openFileTracker = await OpenFileTracker.CreateAsync(this, asyncServiceProvider).ConfigureAwait(true);

            // Update our fields first, so any asynchronous work that needs to use these is able to see the service.
            lock (_gate)
            {
                _openFileTrackerOpt = openFileTracker;
            }

            openFileTracker.CheckForOpenDocumentsByEnumeratingTheRunningDocumentTable();
        }

        public void CheckForOpenDocuments(ImmutableArray<string> newFileNames)
        {
            _openFileTrackerOpt?.CheckForFilesBeingOpen(newFileNames);
        }

        internal void AddProjectToInternalMaps(VisualStudioProject project, IVsHierarchy hierarchy, Guid guid, string projectUniqueName)
        {
            lock (_gate)<commit_msg>Change to use ConfigureAwait(true) following JTF SwitchToMainThread<commit_after>﻿// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using EnvDTE;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Extensions;
using Microsoft.VisualStudio.LanguageServices.Implementation.Venus;
using Microsoft.VisualStudio.LanguageServices.Utilities;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Projection;
using Roslyn.Utilities;
using VSLangProj;
using VSLangProj140;
using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider;
using OleInterop = Microsoft.VisualStudio.OLE.Interop;

namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
    /// <summary>
    /// The Workspace for running inside Visual Studio.
    /// </summary>
    internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspace
    {
        private static readonly IntPtr s_docDataExisting_Unknown = new IntPtr(-1);
        private const string AppCodeFolderName = "App_Code";

        private readonly IThreadingContext _threadingContext;
        private readonly ITextBufferFactoryService _textBufferFactoryService;
        private readonly IProjectionBufferFactoryService _projectionBufferFactoryService;

        [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")]
        private readonly Lazy<VisualStudioProjectFactory> _projectFactory;

        private readonly ITextBufferCloneService _textBufferCloneService;

        // document worker coordinator
        private ISolutionCrawlerRegistrationService _registrationService;

        /// <summary>
        /// A <see cref="ForegroundThreadAffinitizedObject"/> to make assertions that stuff is on the right thread.
        /// </summary>
        private readonly ForegroundThreadAffinitizedObject _foregroundObject;

        private ImmutableDictionary<ProjectId, IVsHierarchy> _projectToHierarchyMap = ImmutableDictionary<ProjectId, IVsHierarchy>.Empty;
        private ImmutableDictionary<ProjectId, Guid> _projectToGuidMap = ImmutableDictionary<ProjectId, Guid>.Empty;
        private ImmutableDictionary<string, VisualStudioProject> _projectUniqueNameToProjectMap = ImmutableDictionary<string, VisualStudioProject>.Empty;

        /// <summary>
        /// A set of documents that were added by <see cref="VisualStudioProject.AddSourceTextContainer"/>, and aren't otherwise
        /// tracked for opening/closing.
        /// </summary>
        private ImmutableHashSet<DocumentId> _documentsNotFromFiles = ImmutableHashSet<DocumentId>.Empty;

        internal VisualStudioProjectTracker _projectTracker;

        private OpenFileTracker _openFileTrackerOpt;
        internal FileChangeWatcher FileChangeWatcher { get; }

        public VisualStudioWorkspaceImpl(ExportProvider exportProvider, IAsyncServiceProvider asyncServiceProvider)
            : base(VisualStudioMefHostServices.Create(exportProvider))
        {
            _threadingContext = exportProvider.GetExportedValue<IThreadingContext>();
            _textBufferCloneService = exportProvider.GetExportedValue<ITextBufferCloneService>();
            _textBufferFactoryService = exportProvider.GetExportedValue<ITextBufferFactoryService>();
            _projectionBufferFactoryService = exportProvider.GetExportedValue<IProjectionBufferFactoryService>();

            // We fetch this lazily because VisualStudioProjectFactory depends on VisualStudioWorkspaceImpl -- we have a circularity. Since this
            // exists right now as a compat shim, we'll just do this.
#pragma warning disable CS0618 // Type or member is obsolete
            _projectFactory = exportProvider.GetExport<VisualStudioProjectFactory>();
#pragma warning restore CS0618 // Type or member is obsolete

            _foregroundObject = new ForegroundThreadAffinitizedObject(_threadingContext);

            _textBufferFactoryService.TextBufferCreated += AddTextBufferCloneServiceToBuffer;
            _projectionBufferFactoryService.ProjectionBufferCreated += AddTextBufferCloneServiceToBuffer;
            exportProvider.GetExportedValue<PrimaryWorkspace>().Register(this);

            System.Threading.Tasks.Task.Run(() => ConnectToOpenFileTrackerOnUIThreadAsync(asyncServiceProvider));

            var fileChangeWatcherProvider = exportProvider.GetExportedValue<FileChangeWatcherProvider>();

            FileChangeWatcher = fileChangeWatcherProvider.Watcher;
            _threadingContext.JoinableTaskFactory.RunAsync(async () =>
                {
                    await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync();
                    var fileChangeService = (IVsAsyncFileChangeEx)await asyncServiceProvider.GetServiceAsync(typeof(SVsFileChangeEx)).ConfigureAwait(true);
                    
                    fileChangeWatcherProvider.SetFileChangeService(fileChangeService);
                });
        }

        public async System.Threading.Tasks.Task ConnectToOpenFileTrackerOnUIThreadAsync(IAsyncServiceProvider asyncServiceProvider)
        {
            // Create services that are bound to the UI thread
            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync();

            var openFileTracker = await OpenFileTracker.CreateAsync(this, asyncServiceProvider).ConfigureAwait(true);

            // Update our fields first, so any asynchronous work that needs to use these is able to see the service.
            lock (_gate)
            {
                _openFileTrackerOpt = openFileTracker;
            }

            openFileTracker.CheckForOpenDocumentsByEnumeratingTheRunningDocumentTable();
        }

        public void CheckForOpenDocuments(ImmutableArray<string> newFileNames)
        {
            _openFileTrackerOpt?.CheckForFilesBeingOpen(newFileNames);
        }

        internal void AddProjectToInternalMaps(VisualStudioProject project, IVsHierarchy hierarchy, Guid guid, string projectUniqueName)
        {
            lock (_gate)
{'fraction_non_alphanumeric': 0.06509440893395048, 'fraction_numerical': 0.0020571596502828595, 'mean_word_length': 3.944424264438794, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6003678', 'n_tokens_mistral': 3305, 'n_tokens_neox': 3181, 'n_words': 741}