コード例 #1
0
 internal void GetProjectData(ProjectId projectId, out IVisualStudioHostProject hostProject, out IVsHierarchy hierarchy, out EnvDTE.Project project)
 {
     if (!TryGetProjectData(projectId, out hostProject, out hierarchy, out project))
     {
         throw new ArgumentException(string.Format(ServicesVSResources.CouldNotFindProject, projectId));
     }
 }
コード例 #2
0
        private ProjectItem AddDocumentToProjectItems(
            IVisualStudioHostProject hostProject,
            ProjectItems projectItems,
            DocumentId documentId,
            string folderPath,
            string documentName,
            SourceCodeKind sourceCodeKind,
            SourceText initialText,
            string filePath,
            bool isAdditionalDocument)
        {
            if (filePath == null)
            {
                var baseName   = Path.GetFileNameWithoutExtension(documentName);
                var extension  = isAdditionalDocument ? Path.GetExtension(documentName) : GetPreferredExtension(hostProject, sourceCodeKind);
                var uniqueName = projectItems.GetUniqueName(baseName, extension);
                filePath = Path.Combine(folderPath, uniqueName);
            }

            if (initialText != null)
            {
                using (var writer = new StreamWriter(filePath, append: false, encoding: initialText.Encoding ?? Encoding.UTF8))
                {
                    initialText.Write(writer);
                }
            }

            using (var documentIdHint = _projectTracker.DocumentProvider.ProvideDocumentIdHint(filePath, documentId))
            {
                return(projectItems.AddFromFile(filePath));
            }
        }
コード例 #3
0
        void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project)
        {
            AssertIsForeground();

            var abstractProject = (AbstractProject)project;

            StartPushingToWorkspaceAndNotifyOfOpenDocuments(SpecializedCollections.SingletonEnumerable(abstractProject));
        }
コード例 #4
0
        public DocumentKey(IVisualStudioHostProject hostProject, string moniker)
        {
            Contract.ThrowIfNull(hostProject);
            Contract.ThrowIfNull(moniker);

            _hostProject = hostProject;
            _moniker     = moniker;
        }
コード例 #5
0
            public StandardTextDocument(
                DocumentProvider documentProvider,
                IVisualStudioHostProject project,
                DocumentKey documentKey,
                IReadOnlyList<string> folderNames,
                SourceCodeKind sourceCodeKind,
                ITextUndoHistoryRegistry textUndoHistoryRegistry,
                IVsFileChangeEx fileChangeService,
                ITextBuffer openTextBuffer,
                DocumentId id,
                EventHandler updatedOnDiskHandler,
                EventHandler<bool> openedHandler,
                EventHandler<bool> closingHandler)
            {
                Contract.ThrowIfNull(documentProvider);

                this.Project = project;
                this.Id = id ?? DocumentId.CreateNewId(project.Id, documentKey.Moniker);
                this.Folders = folderNames;

                _documentProvider = documentProvider;

                this.Key = documentKey;
                this.SourceCodeKind = sourceCodeKind;
                _itemMoniker = documentKey.Moniker;
                _textUndoHistoryRegistry = textUndoHistoryRegistry;
                _fileChangeTracker = new FileChangeTracker(fileChangeService, this.FilePath);
                _fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;

                _openTextBuffer = openTextBuffer;
                _snapshotTracker = new ReiteratedVersionSnapshotTracker(openTextBuffer);

                // The project system does not tell us the CodePage specified in the proj file, so
                // we use null to auto-detect.
                _doNotAccessDirectlyLoader = new FileTextLoader(documentKey.Moniker, defaultEncoding: null);

                // If we aren't already open in the editor, then we should create a file change notification
                if (openTextBuffer == null)
                {
                    _fileChangeTracker.StartFileChangeListeningAsync();
                }

                if (updatedOnDiskHandler != null)
                {
                    UpdatedOnDisk += updatedOnDiskHandler;
                }

                if (openedHandler != null)
                {
                    Opened += openedHandler;
                }

                if (closingHandler != null)
                {
                    Closing += closingHandler;
                }
            }
コード例 #6
0
        private bool TryGetProjectData(ProjectId projectId, out IVisualStudioHostProject hostProject, out IVsHierarchy hierarchy, out EnvDTE.Project project)
        {
            hierarchy = null;
            project   = null;

            return(this.TryGetHostProject(projectId, out hostProject) &&
                   this.TryGetHierarchy(projectId, out hierarchy) &&
                   hierarchy.TryGetProject(out project));
        }
コード例 #7
0
            public StandardTextDocument(
                DocumentProvider documentProvider,
                IVisualStudioHostProject project,
                DocumentKey documentKey,
                IReadOnlyList <string> folderNames,
                SourceCodeKind sourceCodeKind,
                ITextUndoHistoryRegistry textUndoHistoryRegistry,
                IVsFileChangeEx fileChangeService,
                ITextBuffer openTextBuffer,
                DocumentId id,
                EventHandler updatedOnDiskHandler,
                EventHandler <bool> openedHandler,
                EventHandler <bool> closingHandler)
            {
                Contract.ThrowIfNull(documentProvider);

                this.Project = project;
                this.Id      = id ?? DocumentId.CreateNewId(project.Id, documentKey.Moniker);
                this.Folders = folderNames;

                _documentProvider = documentProvider;

                this.Key                          = documentKey;
                this.SourceCodeKind               = sourceCodeKind;
                _itemMoniker                      = documentKey.Moniker;
                _textUndoHistoryRegistry          = textUndoHistoryRegistry;
                _fileChangeTracker                = new FileChangeTracker(fileChangeService, this.FilePath);
                _fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;

                _openTextBuffer  = openTextBuffer;
                _snapshotTracker = new ReiteratedVersionSnapshotTracker(openTextBuffer);

                // The project system does not tell us the CodePage specified in the proj file, so
                // we use null to auto-detect.
                _doNotAccessDirectlyLoader = new FileTextLoader(documentKey.Moniker, defaultEncoding: null);

                // If we aren't already open in the editor, then we should create a file change notification
                if (openTextBuffer == null)
                {
                    _fileChangeTracker.StartFileChangeListeningAsync();
                }

                if (updatedOnDiskHandler != null)
                {
                    UpdatedOnDisk += updatedOnDiskHandler;
                }

                if (openedHandler != null)
                {
                    Opened += openedHandler;
                }

                if (closingHandler != null)
                {
                    Closing += closingHandler;
                }
            }
コード例 #8
0
        /// <remarks>
        /// <para>The optional project is used to obtain an <see cref="IVsProject"/> 1nstance. When this instance is
        /// provided, Visual Studio will use <see cref="IVsProject.IsDocumentInProject"/> to attempt to locate the
        /// specified file within a project. If no project is specified, Visual Studio falls back to using
        /// <see cref="IVsUIShellOpenDocument4.IsDocumentInAProject2"/>, which performs a much slower query of all
        /// projects in the solution.</para>
        /// </remarks>
        public InvisibleEditor(IServiceProvider serviceProvider, string filePath, IVisualStudioHostProject projectOpt, bool needsSave, bool needsUndoDisabled)
        {
            _serviceProvider = serviceProvider;
            _filePath        = filePath;
            _needsSave       = needsSave;

            var invisibleEditorManager = (IIntPtrReturningVsInvisibleEditorManager)serviceProvider.GetService(typeof(SVsInvisibleEditorManager));
            var vsProject          = TryGetProjectOfHierarchy(projectOpt?.Hierarchy);
            var invisibleEditorPtr = IntPtr.Zero;

            Marshal.ThrowExceptionForHR(invisibleEditorManager.RegisterInvisibleEditor(filePath, vsProject, 0, null, out invisibleEditorPtr));

            try
            {
                _invisibleEditor = (IVsInvisibleEditor)Marshal.GetUniqueObjectForIUnknown(invisibleEditorPtr);

                var docDataPtr = IntPtr.Zero;
                Marshal.ThrowExceptionForHR(_invisibleEditor.GetDocData(fEnsureWritable: needsSave ? 1 : 0, riid: typeof(IVsTextLines).GUID, ppDocData: out docDataPtr));

                try
                {
                    var docData = Marshal.GetObjectForIUnknown(docDataPtr);
                    _vsTextLines = docData as IVsTextLines;
                    var vsTextBuffer = (IVsTextBuffer)docData;
                    var editorAdapterFactoryService = serviceProvider.GetMefService <IVsEditorAdaptersFactoryService>();
                    _buffer = editorAdapterFactoryService.GetDocumentBuffer(vsTextBuffer);
                    if (needsUndoDisabled)
                    {
                        Marshal.ThrowExceptionForHR(vsTextBuffer.GetUndoManager(out _manager));
                        Marshal.ThrowExceptionForHR((_manager as IVsUndoState).IsEnabled(out var isEnabled));
                        _needsUndoRestored = isEnabled != 0;
                        if (_needsUndoRestored)
                        {
                            _manager.DiscardFrom(null); // Discard the undo history for this document
                            _manager.Enable(0);         // Disable Undo for this document
                        }
                    }
                }
                finally
                {
                    Marshal.Release(docDataPtr);
                }
            }
            finally
            {
                // We need to clean up the extra reference we have, now that we have an RCW holding onto the object.
                Marshal.Release(invisibleEditorPtr);
            }
        }
コード例 #9
0
        private static string GetPreferredExtension(IVisualStudioHostProject hostProject, SourceCodeKind sourceCodeKind)
        {
            // No extension was provided.  Pick a good one based on the type of host project.
            switch (hostProject.Language)
            {
            case LanguageNames.CSharp:
                return(sourceCodeKind == SourceCodeKind.Regular ? ".cs" : ".csx");

            case LanguageNames.VisualBasic:
                return(sourceCodeKind == SourceCodeKind.Regular ? ".vb" : ".vbx");

            default:
                throw new InvalidOperationException();
            }
        }
コード例 #10
0
            public StandardTextDocument(
                DocumentProvider documentProvider,
                IVisualStudioHostProject project,
                DocumentKey documentKey,
                uint itemId,
                SourceCodeKind sourceCodeKind,
                ITextBufferFactoryService textBufferFactoryService,
                ITextUndoHistoryRegistry textUndoHistoryRegistry,
                IVsFileChangeEx fileChangeService,
                ITextBuffer openTextBuffer,
                DocumentId id)
            {
                Contract.ThrowIfNull(documentProvider);
                Contract.ThrowIfNull(textBufferFactoryService);

                this.Project = project;
                this.Id = id ?? DocumentId.CreateNewId(project.Id, documentKey.Moniker);
                this.Folders = project.GetFolderNames(itemId);

                // TODO: 
                // this one doesn't work for asynchronous project load situation where shared projects is loaded after one uses shared file. 
                // we need to figure out what to do on those case. but this works for project k case.
                // opened an issue to track this issue - https://github.com/dotnet/roslyn/issues/1859
                this.SharedHierarchy = project.Hierarchy == null ? null : LinkedFileUtilities.GetSharedHierarchyForItem(project.Hierarchy, itemId);
                _documentProvider = documentProvider;

                this.Key = documentKey;
                this.SourceCodeKind = sourceCodeKind;
                _itemMoniker = documentKey.Moniker;
                _textBufferFactoryService = textBufferFactoryService;
                _textUndoHistoryRegistry = textUndoHistoryRegistry;
                _fileChangeTracker = new FileChangeTracker(fileChangeService, this.FilePath);
                _fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;

                _openTextBuffer = openTextBuffer;
                _snapshotTracker = new ReiteratedVersionSnapshotTracker(openTextBuffer);

                // The project system does not tell us the CodePage specified in the proj file, so
                // we use null to auto-detect.
                _doNotAccessDirectlyLoader = new FileTextLoader(documentKey.Moniker, defaultEncoding: null);

                // If we aren't already open in the editor, then we should create a file change notification
                if (openTextBuffer == null)
                {
                    _fileChangeTracker.StartFileChangeListeningAsync();
                }
            }
コード例 #11
0
            public StandardTextDocument(
                DocumentProvider documentProvider,
                IVisualStudioHostProject project,
                DocumentKey documentKey,
                uint itemId,
                SourceCodeKind sourceCodeKind,
                ITextBufferFactoryService textBufferFactoryService,
                ITextUndoHistoryRegistry textUndoHistoryRegistry,
                IVsFileChangeEx fileChangeService,
                ITextBuffer openTextBuffer,
                DocumentId id)
            {
                Contract.ThrowIfNull(documentProvider);
                Contract.ThrowIfNull(textBufferFactoryService);

                this.Project = project;
                this.Id      = id ?? DocumentId.CreateNewId(project.Id, documentKey.Moniker);
                this.Folders = project.GetFolderNames(itemId);

                // TODO:
                // this one doesn't work for asynchronous project load situation where shared projects is loaded after one uses shared file.
                // we need to figure out what to do on those case. but this works for project k case.
                // opened an issue to track this issue - https://github.com/dotnet/roslyn/issues/1859
                this.SharedHierarchy = project.Hierarchy == null ? null : LinkedFileUtilities.GetSharedHierarchyForItem(project.Hierarchy, itemId);
                _documentProvider    = documentProvider;

                this.Key                          = documentKey;
                this.SourceCodeKind               = sourceCodeKind;
                _itemMoniker                      = documentKey.Moniker;
                _textBufferFactoryService         = textBufferFactoryService;
                _textUndoHistoryRegistry          = textUndoHistoryRegistry;
                _fileChangeTracker                = new FileChangeTracker(fileChangeService, this.FilePath);
                _fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;

                _openTextBuffer  = openTextBuffer;
                _snapshotTracker = new ReiteratedVersionSnapshotTracker(openTextBuffer);

                // The project system does not tell us the CodePage specified in the proj file, so
                // we use null to auto-detect.
                _doNotAccessDirectlyLoader = new FileTextLoader(documentKey.Moniker, defaultEncoding: null);

                // If we aren't already open in the editor, then we should create a file change notification
                if (openTextBuffer == null)
                {
                    _fileChangeTracker.StartFileChangeListeningAsync();
                }
            }
コード例 #12
0
        public VisualStudioMetadataReference(
            VisualStudioMetadataReferenceManager provider,
            IVisualStudioHostProject hostProject,
            string filePath,
            MetadataReferenceProperties properties)
        {
            Contract.ThrowIfTrue(properties.Kind != MetadataImageKind.Assembly);

            _provider    = provider;
            _hostProject = hostProject;
            _properties  = properties;

            // We don't track changes to netmodules linked to the assembly.
            // Any legitimate change in a linked module will cause the assembly to change as well.
            _fileChangeTracker = new FileChangeTracker(provider.FileChangeService, filePath);
            _fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;
            _fileChangeTracker.StartFileChangeListeningAsync();
        }
コード例 #13
0
        public VisualStudioMetadataReference(
            VisualStudioMetadataReferenceManager provider,
            IVisualStudioHostProject hostProject,
            string filePath,
            MetadataReferenceProperties properties)
        {
            Contract.ThrowIfTrue(properties.Kind != MetadataImageKind.Assembly);

            _provider = provider;
            _hostProject = hostProject;
            _properties = properties;

            // We don't track changes to netmodules linked to the assembly.
            // Any legitimate change in a linked module will cause the assembly to change as well.
            _fileChangeTracker = new FileChangeTracker(provider.FileChangeService, filePath);
            _fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;
            _fileChangeTracker.StartFileChangeListeningAsync();
        }
コード例 #14
0
            public StandardTextDocument(
                DocumentProvider documentProvider,
                IVisualStudioHostProject project,
                DocumentKey documentKey,
                uint itemId,
                SourceCodeKind sourceCodeKind,
                ITextBufferFactoryService textBufferFactoryService,
                ITextUndoHistoryRegistry textUndoHistoryRegistry,
                IVsFileChangeEx fileChangeService,
                ITextBuffer openTextBuffer,
                DocumentId id)
            {
                Contract.ThrowIfNull(documentProvider);
                Contract.ThrowIfNull(textBufferFactoryService);

                this.Project = project;
                this.Id      = id ?? DocumentId.CreateNewId(project.Id, documentKey.Moniker);
                this.Folders = project.GetFolderNames(itemId);

                this.SharedHierarchy = project.Hierarchy == null ? null : LinkedFileUtilities.GetSharedHierarchyForItem(project.Hierarchy, itemId);
                _documentProvider    = documentProvider;

                this.Key                          = documentKey;
                this.SourceCodeKind               = sourceCodeKind;
                _itemMoniker                      = documentKey.Moniker;
                _textBufferFactoryService         = textBufferFactoryService;
                _textUndoHistoryRegistry          = textUndoHistoryRegistry;
                _fileChangeTracker                = new FileChangeTracker(fileChangeService, this.FilePath);
                _fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;

                _openTextBuffer  = openTextBuffer;
                _snapshotTracker = new ReiteratedVersionSnapshotTracker(openTextBuffer);

                // The project system does not tell us the CodePage specified in the proj file, so
                // we use null to auto-detect.
                _doNotAccessDirectlyLoader = new FileTextLoader(documentKey.Moniker, defaultEncoding: null);

                // If we aren't already open in the editor, then we should create a file change notification
                if (openTextBuffer == null)
                {
                    _fileChangeTracker.StartFileChangeListeningAsync();
                }
            }
コード例 #15
0
        private ProjectItem AddDocumentToProject(
            IVisualStudioHostProject hostProject,
            EnvDTE.Project project,
            DocumentId documentId,
            string documentName,
            SourceCodeKind sourceCodeKind,
            SourceText initialText    = null,
            string filePath           = null,
            bool isAdditionalDocument = false)
        {
            string folderPath;

            if (!project.TryGetFullPath(out folderPath))
            {
                // TODO(cyrusn): Throw an appropriate exception here.
                throw new Exception(ServicesVSResources.CouldNotFindLocationOfFol);
            }

            return(AddDocumentToProjectItems(hostProject, project.ProjectItems, documentId, folderPath, documentName, sourceCodeKind, initialText, filePath, isAdditionalDocument));
        }
コード例 #16
0
ファイル: DocumentProvider.cs プロジェクト: zhxjdwh/roslyn
 public IVisualStudioHostDocument TryGetDocumentForFile(
     IVisualStudioHostProject hostProject,
     string filePath,
     SourceCodeKind sourceCodeKind,
     Func <ITextBuffer, bool> canUseTextBuffer,
     Func <uint, IReadOnlyList <string> > getFolderNames,
     EventHandler updatedOnDiskHandler  = null,
     EventHandler <bool> openedHandler  = null,
     EventHandler <bool> closingHandler = null)
 {
     return(TryGetDocumentForFile(
                (AbstractProject)hostProject,
                filePath,
                sourceCodeKind,
                canUseTextBuffer,
                getFolderNames,
                updatedOnDiskHandler,
                openedHandler,
                closingHandler));
 }
コード例 #17
0
 public VisualStudioMetadataReference CreateMetadataReference(IVisualStudioHostProject hostProject, string filePath, MetadataReferenceProperties properties)
 {
     return(new VisualStudioMetadataReference(this, hostProject, filePath, properties));
 }
コード例 #18
0
 private bool TryGetHostProject(ProjectId projectId, out IVisualStudioHostProject project)
 {
     project = GetHostProject(projectId);
     return(project != null);
 }
コード例 #19
0
 public VisualStudioMetadataReference CreateMetadataReference(IVisualStudioHostProject hostProject, string filePath, MetadataReferenceProperties properties)
 {
     return new VisualStudioMetadataReference(this, hostProject, filePath, properties);
 }
コード例 #20
0
        void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project)
        {
            AssertIsForeground();

            var abstractProject = (AbstractProject)project;
            StartPushingToWorkspaceAndNotifyOfOpenDocuments(SpecializedCollections.SingletonEnumerable(abstractProject));
        }
コード例 #21
0
 void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project)
 {
     // Since the MiscellaneousFilesWorkspace doesn't do anything lazily, this is a no-op
 }
コード例 #22
0
 void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project)
 {
     // Since the MiscellaneousFilesWorkspace doesn't do anything lazily, this is a no-op
 }
コード例 #23
0
        public IVisualStudioHostDocument TryGetDocumentForFile(
            IVisualStudioHostProject hostProject,
            uint itemId,
            string filePath,
            SourceCodeKind sourceCodeKind,
            Func <ITextBuffer, bool> canUseTextBuffer)
        {
            var documentKey = new DocumentKey(hostProject, filePath);
            StandardTextDocument document;

            if (_documentMap.TryGetValue(documentKey, out document))
            {
                return(document);
            }

            ITextBuffer openTextBuffer = null;
            uint        foundCookie    = VSConstants.VSCOOKIE_NIL;

            // If this document is already open in the editor we want to associate the text buffer with it.
            // However, determining if a document is already open is a bit complicated. With the introduction
            // of the lazy tabs feature in Dev12, a document may be open (i.e. it has a tab in the shell) but not
            // actually initialized (no data has been loaded for it because its contents have not actually been
            // viewed or used). We only care about documents that are open AND initialized.
            // That means we can't call IVsRunningDocumentTable::FindAndLockDocument to find the document; if the
            // document is open but not initialized, the call will force initialization. This is bad for two
            // reasons:
            //   1.) It circumvents lazy tabs for any document that is part of a VB or C# project.
            //   2.) Initialization may cause a whole host of other code to run synchronously, such as taggers.
            // Instead, we check if the document is already initialized, and avoid asking for the doc data and
            // hierarchy if it is not.
            if (RunningDocumentTable.TryGetCookieForInitializedDocument(documentKey.Moniker, out foundCookie))
            {
                object foundDocData = RunningDocumentTable.GetDocumentData(foundCookie);
                openTextBuffer = TryGetTextBufferFromDocData(foundDocData);
                if (openTextBuffer == null)
                {
                    // We're open but not open as a normal text buffer. This can happen if the
                    // project system (say in ASP.NET cases) is telling us to add a file which
                    // actually isn't a normal text file at all.
                    return(null);
                }

                if (!canUseTextBuffer(openTextBuffer))
                {
                    return(null);
                }
            }

            // If this is being added through a public call to Workspace.AddDocument (say, ApplyChanges) then we might
            // already have a document ID that we should be using here.
            DocumentId id = null;

            _documentIdHints.TryGetValue(filePath, out id);

            document = new StandardTextDocument(
                this,
                hostProject,
                documentKey,
                itemId,
                sourceCodeKind,
                _textUndoHistoryRegistry,
                _fileChangeService,
                openTextBuffer,
                id);

            // Add this to our document map
            _documentMap.Add(documentKey, document);

            if (openTextBuffer != null)
            {
                AddCookieOpenDocumentPair(foundCookie, documentKey);
            }

            return(document);
        }
コード例 #24
0
ファイル: DocumentProvider.cs プロジェクト: XieShuquan/roslyn
        /// <summary>
        /// Gets the <see cref="IVisualStudioHostDocument"/> for the file at the given filePath.
        /// If we are on the foreground thread and this document is already open in the editor,
        /// then we also attempt to associate the text buffer with it.
        /// Otherwise, if we are on a background thread, then this text buffer association will happen on a scheduled task
        /// whenever <see cref="NotifyDocumentRegisteredToProjectAndStartToRaiseEvents"/> is invoked for the returned document.
        /// </summary>
        public IVisualStudioHostDocument TryGetDocumentForFile(
            IVisualStudioHostProject hostProject,
            string filePath,
            SourceCodeKind sourceCodeKind,
            Func<ITextBuffer, bool> canUseTextBuffer,
            Func<uint, IReadOnlyList<string>> getFolderNames,
            EventHandler updatedOnDiskHandler = null,
            EventHandler<bool> openedHandler = null,
            EventHandler<bool> closingHandler = null)
        {
            var documentKey = new DocumentKey(hostProject, filePath);
            StandardTextDocument document;

            lock (_gate)
            {
                if (_documentMap.TryGetValue(documentKey, out document))
                {
                    return document;
                }
            }

            ITextBuffer openTextBuffer = null;
            uint foundCookie = VSConstants.VSCOOKIE_NIL;

            if (IsForeground())
            {
                // If we are on the foreground thread and this document is already open in the editor we want to associate the text buffer with it.
                // Otherwise, we are on a background thread, and this text buffer association will happen on a scheduled task
                // whenever NotifyDocumentRegisteredToProjectAndStartToRaiseEvents is invoked for the returned document.
                // However, determining if a document is already open is a bit complicated. With the introduction
                // of the lazy tabs feature in Dev12, a document may be open (i.e. it has a tab in the shell) but not
                // actually initialized (no data has been loaded for it because its contents have not actually been
                // viewed or used). We only care about documents that are open AND initialized.
                // That means we can't call IVsRunningDocumentTable::FindAndLockDocument to find the document; if the
                // document is open but not initialized, the call will force initialization. This is bad for two
                // reasons:
                //   1.) It circumvents lazy tabs for any document that is part of a VB or C# project.
                //   2.) Initialization may cause a whole host of other code to run synchronously, such as taggers.
                // Instead, we check if the document is already initialized, and avoid asking for the doc data and
                // hierarchy if it is not.
                if (_runningDocumentTable.TryGetCookieForInitializedDocument(documentKey.Moniker, out foundCookie))
                {
                    object foundDocData = _runningDocumentTable.GetDocumentData(foundCookie);
                    openTextBuffer = TryGetTextBufferFromDocData(foundDocData);
                    if (openTextBuffer == null)
                    {
                        // We're open but not open as a normal text buffer. This can happen if the
                        // project system (say in ASP.NET cases) is telling us to add a file which
                        // actually isn't a normal text file at all.
                        return null;
                    }

                    if (!canUseTextBuffer(openTextBuffer))
                    {
                        return null;
                    }
                }
            }

            lock (_gate)
            {
                // If this is being added through a public call to Workspace.AddDocument (say, ApplyChanges) then we might
                // already have a document ID that we should be using here.
                _documentIdHints.TryGetValue(filePath, out var id);

                document = new StandardTextDocument(
                    this,
                    hostProject,
                    documentKey,
                    getFolderNames,
                    sourceCodeKind,
                    _textUndoHistoryRegistry,
                    _fileChangeService,
                    openTextBuffer,
                    id,
                    updatedOnDiskHandler,
                    openedHandler,
                    closingHandler);

                // Add this to our document map
                _documentMap.Add(documentKey, document);

                if (openTextBuffer != null)
                {
                    AddCookieOpenDocumentPair_NoLock(foundCookie, documentKey);
                }
            }

            return document;
        }