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)); } }
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)); } }
void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project) { AssertIsForeground(); var abstractProject = (AbstractProject)project; StartPushingToWorkspaceAndNotifyOfOpenDocuments(SpecializedCollections.SingletonEnumerable(abstractProject)); }
public DocumentKey(IVisualStudioHostProject hostProject, string moniker) { Contract.ThrowIfNull(hostProject); Contract.ThrowIfNull(moniker); _hostProject = hostProject; _moniker = moniker; }
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; } }
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)); }
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; } }
/// <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); } }
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(); } }
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(); } }
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(); }
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(); } }
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)); }
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)); }
public VisualStudioMetadataReference CreateMetadataReference(IVisualStudioHostProject hostProject, string filePath, MetadataReferenceProperties properties) { return(new VisualStudioMetadataReference(this, hostProject, filePath, properties)); }
private bool TryGetHostProject(ProjectId projectId, out IVisualStudioHostProject project) { project = GetHostProject(projectId); return(project != null); }
public VisualStudioMetadataReference CreateMetadataReference(IVisualStudioHostProject hostProject, string filePath, MetadataReferenceProperties properties) { return new VisualStudioMetadataReference(this, hostProject, filePath, properties); }
void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project) { // Since the MiscellaneousFilesWorkspace doesn't do anything lazily, this is a no-op }
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); }
/// <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; }