internal FileItem(CommentTaskProvider provider, string fileName) { // Note: The caller should check FileUtility.IsValidPath(fileName) before invoking this constructor. this.provider = provider; this.FileName = fileName; this.hierarchyItems = EmptySet; this.lastModifiedTimeScannedUtc = MinDateTimeUtc; try { this.fileInfo = new FileInfo(fileName); this.scanInfo = ScanInfo.Get(this); } catch (Exception ex) { // We might not have access to the file, or the fileName parameter might contain a non-file name. // The latter condition should be very rare now since the caller is using FileUtility.IsValidPath. // An invalid file name should only get through to here if it's valid per Windows standard naming // rules but invalid on the target file system (e.g., if it's on a Unix system or on a CD). if (!IsAccessException(ex) && !(ex is NotSupportedException || ex is ArgumentException)) { throw; } // Make sure this FileItem is unscannable so nothing will try to use its null this.fileInfo member. this.scanInfo = ScanInfo.Unscannable; } }
internal CommentTask(CommentTaskProvider provider, TaskPriority priority, string project, string fileName, int line, string comment) { this.provider = provider; this.Priority = priority; this.Project = project; this.FilePath = fileName; this.Line = line; this.Comment = comment; }
public FileItemManager(CommentTaskProvider provider, FileMonitor monitor, Options options) { this.provider = provider; this.monitor = monitor; this.options = options; this.options.Applied += this.Options_Applied; this.RefreshExcludePatterns(); }
private void TasksControl_Loaded(object sender, RoutedEventArgs e) { // The Loaded event will be raised again whenever the tool window tab is changed, // so we must make sure this event handler isn't called again. this.Loaded -= this.TasksControl_Loaded; if (this.isLoading) { MainPackage package = this.Package; if (package == null) { throw new InvalidOperationException("The tasks control can't be loaded without its associated package."); } Options options = package.Options; if (options == null) { throw new InvalidOperationException("The tasks control can't be loaded without its associated options."); } CommentTaskProvider provider = package.TaskProvider; if (provider != null) { provider.TasksChanged += this.TaskProvider_TasksChanged; } this.initiallyEnabled = options.EnableCommentScans; this.UpdateWarning(options); options.Applied += (s, a) => { if (this.IsLoaded) { this.UpdateWarning((Options)s); } }; this.resetSort.IsEnabled = false; string statusXml = options.TasksStatusXml; if (!string.IsNullOrEmpty(statusXml)) { SortDescriptionCollection sorting = this.tasks.Items.SortDescriptions; XElement status = XElement.Parse(statusXml); foreach (XElement sortBy in status.Elements("SortBy")) { SortDescription sort = new SortDescription( sortBy.GetAttributeValue("PropertyName"), sortBy.GetAttributeValue("Direction", ListSortDirection.Ascending)); sorting.Add(sort); } } this.isLoading = false; } }
public DocumentMonitor(CommentTaskProvider provider) { this.provider = provider; this.docTable = new RunningDocumentTable(this.provider.ServiceProvider); this.docTable4 = (IVsRunningDocumentTable4)this.provider.ServiceProvider.GetService(typeof(SVsRunningDocumentTable)); this.docTableAdviseCookie = this.docTable.Advise(this); // Creating these components without going through MEF is documented in MSDN under // "Using Visual Studio Editor Services in a Non-MEF Component" in the article "Adapting // Legacy Code to the New Editor" https://msdn.microsoft.com/en-us/library/dd885359.aspx. this.componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel)); this.adapterFactory = this.componentModel.GetService <IVsEditorAdaptersFactoryService>(); this.documentFactory = this.componentModel.GetService <ITextDocumentFactoryService>(); this.documentFactory.TextDocumentCreated += this.DocumentFactory_TextDocumentCreated; this.documentFactory.TextDocumentDisposed += this.DocumentFactory_TextDocumentDisposed; }
private void AddChangedDocument(string filePath, DocumentItem document) { // Ignore file paths that are invalid (e.g., RDT_PROJ_MK::{42D00E44-28B8-4CAA-950E-909D5273945D}), // relative, or too long. We only care about documents that have valid full paths. if (FileUtility.IsValidPath(filePath, ValidPathOptions.None)) { CommentTaskProvider.Debug( "AddChangedDocument: {0}. HasDoc: {1} HasTextDoc: {2}", filePath, document != null, document != null && document.HasTextDocument); lock (this.changedDocuments) { this.changedDocuments[filePath] = document; } } }
public SolutionMonitor(CommentTaskProvider provider) { this.provider = provider; this.solution = (IVsSolution2)this.provider.ServiceProvider.GetService(typeof(SVsSolution)); uint cookie; int hr = this.solution.AdviseSolutionEvents(this, out cookie); ErrorHandler.ThrowOnFailure(hr); this.solutionEventsCookie = cookie; // Note: I tried using IVsHierarchyItemCollectionProvider (via componentModel.GetService<IVsHierarchyItemCollectionProvider>()), // but it had problems. It only worked for the first solution opened, and it caused the nodes to display in a different order in // the VS Solution Explorer! Using IVsTrackProjectDocumentsEvents2 works better. this.projectTracker = (IVsTrackProjectDocuments2)this.provider.ServiceProvider.GetService(typeof(SVsTrackProjectDocuments)); hr = this.projectTracker.AdviseTrackProjectDocumentsEvents(this, out cookie); ErrorHandler.ThrowOnFailure(hr); this.projectEventsCookie = cookie; this.RequireScan(); }
public IReadOnlyDictionary <string, DocumentItem> GetChangedDocuments() { Dictionary <string, DocumentItem> result = CommentTaskProvider.CloneAndClear(this.changedDocuments); return(result); }
public IReadOnlyDictionary <CommentTask, bool> GetChangedTasks() { Dictionary <CommentTask, bool> result = CommentTaskProvider.CloneAndClear(this.changedTasks); return(result); }
private void RequireScan(bool required = true, [CallerMemberName] string caller = null) { this.isScanRequired = required; CommentTaskProvider.Debug("SolutionMonitor.{0} {1} scan.", caller, required ? "enabled" : "disabled"); }
public FileMonitor(CommentTaskProvider provider) { this.provider = provider; this.fileChangeService = (IVsFileChangeEx)this.provider.ServiceProvider.GetService(typeof(SVsFileChangeEx)); }
public bool Refresh(RefreshAction action, out IDictionary <CommentTask, bool> itemChanges) { bool isScannable = action != RefreshAction.Remove && this.scanInfo.IsScannable; if (isScannable) { this.fileInfo.Refresh(); isScannable = this.fileInfo.Exists; } bool result = false; itemChanges = null; if (!isScannable) { if (this.tasks != null) { itemChanges = this.tasks.ToDictionary(t => t, t => false); this.tasks = null; } // Reset to min time so if the file shows up again we'll re-scan it. this.lastModifiedTimeScannedUtc = MinDateTimeUtc; result = true; } else { bool forceRefresh = action == RefreshAction.Always || !this.AreTaskProjectsCurrent; // Make sure that the file has been modified since we last scanned it. // Note: lastModifiedUtc can go backward to before lastModifiedTimeScannedUtc // due to Undo, so we have to check != instead of just >. DateTime lastModifiedUtc = this.Document != null && this.Document.HasTextDocument ? this.Document.LastModifiedUtc.Value : this.fileInfo.LastWriteTimeUtc; if (forceRefresh || lastModifiedUtc != this.lastModifiedTimeScannedUtc) { // Make sure that it's been at least N seconds since the file was last modified. // If someone is making a long sequence of continual edits, then there's no point // in wasting scanning overhead while they're actively changing the file. DateTime latestAllowedTimeUtc = DateTime.UtcNow - this.provider.ScanDelay; if (forceRefresh || latestAllowedTimeUtc >= lastModifiedUtc) { itemChanges = this.Refresh(); result = true; this.lastModifiedTimeScannedUtc = lastModifiedUtc; } } else { // We should only get into this branch of the Refresh method if we got a new file, a document change event, // or a file change event. It's possible to get a "document change" event when a document within the solution // is first opened even though we've already scanned it (from the solution reference). When that happens the // lastModifiedUtc should equal the lastModifiedTimeScannedUtc, so we'll just return true since the file scan // results should already be up-to-date. result = lastModifiedUtc == this.lastModifiedTimeScannedUtc; Debug.Assert(result, "The file's modified time should have changed or been the same as the last modified scanned time."); } } CommentTaskProvider.Debug("FileItem.Refresh: {0}, Result={1} ItemChanges={2}", this.FileName, result, itemChanges != null); return(result); }