private NodeViewModel CreateNodeViewModel(FileSystemEntry entry, NodeViewModel parent) { Invariants.Assert(entry != null); Invariants.Assert(parent != null); var directoryEntry = entry as DirectoryEntry; var node = directoryEntry != null ? (NodeViewModel) new DirectoryNodeViewModel() : (NodeViewModel) new FileNodeViewModel(); node.Caption = entry.Name; node.Name = entry.Name; if (PathHelpers.IsAbsolutePath(node.Name)) { node.Template = _templateFactory.ProjectTemplate; } else if (directoryEntry != null) { node.Template = _templateFactory.DirectoryTemplate; } else { var extension = Path.GetExtension(entry.Name); Invariants.Assert(extension != null); node.Template = _templateFactory.GetFileTemplate(extension); if (node.Template.Icon == null) { if (!_fileTemplatesToInitialize.ContainsKey(extension)) { _fileTemplatesToInitialize.Add(extension, node.Template); } } } return(node); }
private IIncrementalHierarchyBuilder CreateIncrementalBuilder(FileSystemTree fileSystemTree) { var vsHierarchy = _hierarchy as VsHierarchy; if (vsHierarchy != null) { return(new IncrementalHierarchyBuilder( _nodeTemplateFactory, vsHierarchy, fileSystemTree, _imageSourceFactory)); } var vsHierarchyAggregate = _hierarchy as VsHierarchyAggregate; if (vsHierarchyAggregate != null) { return(new IncrementalHierarchyBuilderAggregate( _nodeTemplateFactory, vsHierarchyAggregate, fileSystemTree, _imageSourceFactory)); } Invariants.Assert(false); return(null); }
private void LoadFileContents(FileSystemEntities entities, FileContentsLoadingContext loadingContext, CancellationToken cancellationToken) { using (new TimeElapsedLogger("Loading file contents from disk", cancellationToken)) { using (var progress = _progressTrackerFactory.CreateTracker(entities.Files.Count)) { entities.Files.AsParallelWrapper().ForAll(fileEntry => { Invariants.Assert(fileEntry.Value.Contents == null); // ReSharper disable once AccessToDisposedClosure if (progress.Step()) { // ReSharper disable once AccessToDisposedClosure progress.DisplayProgress((i, n) => string.Format("Reading file {0:n0} of {1:n0}: {2}", i, n, fileEntry.Value.FileName.FullPath)); // Check for cancellation if (cancellationToken.IsCancellationRequested) { loadingContext.PartialProgressReporter.ReportProgressNow(); cancellationToken.ThrowIfCancellationRequested(); } } var contents = LoadSingleFileContents(entities, loadingContext, fileEntry.Value); if (contents != null) { entities.Files[fileEntry.Key] = fileEntry.Value.WithContents(contents); } }); } } Logger.LogInfo("Loaded {0:n0} text files from disk, skipped {1:n0} binary files.", loadingContext.LoadedTextFileCount, loadingContext.LoadedBinaryFileCount); }
private bool IsFileContentsUpToDate(FileSystemEntities entities, FullPathChanges fullPathChanges, FileWithContents existingFileWithContents) { Invariants.Assert(existingFileWithContents.Contents != null); var fullPath = existingFileWithContents.FileName.FullPath; if (fullPathChanges != null) { // We don't get file change events for file in symlinks, so we can't // rely on fullPathChanges contents for our heuristic of avoiding file // system access. if (!FileDatabaseSnapshot.IsContainedInSymLinkHelper(entities.Directories, existingFileWithContents.FileName)) { return(fullPathChanges.ShouldSkipLoadFileContents(fullPath)); } } // Do the "expensive" check by going to the file system. var fi = _fileSystem.GetFileInfoSnapshot(fullPath); return ((fi.Exists) && (fi.IsFile) && (fi.LastWriteTimeUtc == existingFileWithContents.Contents.UtcLastModified)); }
private void RunNextTaskIfAvailableAsync(TaskEntry task) { TaskEntryQueue.DequeueResult queueEntry; lock (_lock) { if (task == null) { // If there is a running task, bail, because we will be called again when the running task // finishes. if (_runningTask != null) { return; } } else { Invariants.Assert(ReferenceEquals(_runningTask, task)); } queueEntry = _taskQueue.Dequeue(_dateTimeProvider.UtcNow); _runningTask = queueEntry.TaskEntry; // May be null if only pdelayed tasks } if (queueEntry.TaskEntry != null) { // If there is a task available, run it RunTaskAsync(queueEntry.TaskEntry); } else if (queueEntry.HasPending) { // Run this method in a little while if there are pending tasks _customThreadPool.RunAsync(() => RunNextTaskIfAvailableAsync(null), TimeSpan.FromMilliseconds(50)); } }
private void RunTaskAsync(TaskEntry task) { Invariants.Assert(ReferenceEquals(_runningTask, task)); _customThreadPool.RunAsync(() => { Invariants.Assert(ReferenceEquals(_runningTask, task)); try { if (Logger.IsDebugEnabled) { Logger.LogDebug("Queue \"{0}\": Executing task \"{1}\" after waiting for {2:n0} msec", _description, task.Id.Description, (_dateTimeProvider.UtcNow - task.EnqueuedDateTimeUtc).TotalMilliseconds); } task.StopWatch.Start(); task.Action(_taskCancellationTracker.NewToken()); } finally { Invariants.Assert(ReferenceEquals(_runningTask, task)); task.StopWatch.Stop(); if (Logger.IsDebugEnabled) { Logger.LogDebug("Queue \"{0}\": Executed task \"{1}\" in {2:n0} msec", _description, task.Id.Description, task.StopWatch.ElapsedMilliseconds); } RunNextTaskIfAvailableAsync(task); } }); }
public static ArrayDiffsResult <T> BuildArrayDiffs <T>( IList <T> leftList, IList <T> rightList, IEqualityComparer <T> comparer) { comparer = comparer ?? EqualityComparer <T> .Default; var result = ProcessSpecialCases(leftList, rightList, comparer); if (result != null) { return(result.Value); } bool smallList = leftList.Count + rightList.Count <= SmallArrayThreshold; var result2 = smallList ? BuildArrayDiffsForSmallArrays(leftList, rightList, comparer) : BuildArrayDiffsForLargeArrays(leftList, rightList, comparer); // Quick check assumption about identity is verified: both list should not // contain duplicate elements. Invariants.Assert( result2.LeftOnlyItems.Count + result2.RightOnlyItems.Count + result2.CommonItems.Count * 2 == leftList.Count + rightList.Count); return(result2); }
public IFileDatabaseSnapshot BuildWithChangedFiles(IFileDatabaseSnapshot previousFileDatabaseSnapshot, FileSystemSnapshot fileSystemSnapshot, IEnumerable <ProjectFileName> changedFiles, Action onLoading, Action onLoaded, Action <IFileDatabaseSnapshot> onIntermadiateResult, CancellationToken cancellationToken) { using (new TimeElapsedLogger("Building file database from previous one and list of changed files", cancellationToken, InfoLogger.Instance)) { Invariants.Assert(previousFileDatabaseSnapshot is FileDatabaseSnapshot); var previousFileDatabase = (FileDatabaseSnapshot)previousFileDatabaseSnapshot; // Update file contents of file data entries of changed files. var filesToRead = changedFiles .Where(x => x.Project.IsFileSearchable(x.FileName) && previousFileDatabase.Files.ContainsKey(x.FileName)) .ToList(); if (filesToRead.Count == 0) { Logger.LogInfo("None of the changed file is searchable, return previous database snapshot"); return(previousFileDatabaseSnapshot); } // Read file contents. onLoading(); filesToRead.ForAll(x => { var newContents = _fileContentsFactory.ReadFileContents(x.FileName.FullPath); DangerousUpdateFileTableEntry(previousFileDatabase, x.FileName, newContents); }); onLoaded(); // Return new file database with updated file contents. return(new FileDatabaseSnapshot( previousFileDatabase.ProjectHashes, previousFileDatabase.Directories, previousFileDatabase.Files)); } }
public BuildOutputSpan ParseFullPath(string text) { var match = _fullPathRegex.Value.Match(text); if (!match.Success) { return(null); } var filenameMatch = match.Groups["filename"]; var filename = filenameMatch.Value; Invariants.Assert(!string.IsNullOrEmpty(filename), "RegEx is malformed: it should not match an empty filename"); int line; int column; ParseLineColumn(match, out line, out column); return(new BuildOutputSpan { Text = text, Index = filenameMatch.Index, Length = match.Length - filenameMatch.Index, FileName = filename, LineNumber = line, ColumnNumber = column }); }
private IHierarchyObject PreviousSibling(IHierarchyObject item) { if (item == null) { return(null); } var parent = item.GetParent(); if (parent == null) { return(null); } IHierarchyObject previous = null; foreach (var child in parent.GetAllChildren()) { if (child.Equals(item)) { return(previous); } previous = child; } Invariants.Assert(false); return(null); }
private FileContents ReadFileContentsWorker(IFileInfoSnapshot fileInfo) { const int trailingByteCount = 2; var block = _fileSystem.ReadFileNulTerminated(fileInfo.Path, fileInfo.Length, trailingByteCount); var contentsByteCount = block.ByteLength - trailingByteCount; // Padding added by ReadFileNulTerminated var kind = NativeMethods.Text_GetKind(block.Pointer, contentsByteCount); switch (kind) { case NativeMethods.TextKind.TextKind_Ascii: // Note: Since we don't support UTF16 regex, just load all utf8 files as ascii. case NativeMethods.TextKind.TextKind_Utf8: return(new AsciiFileContents(new FileContentsMemory(block, 0, contentsByteCount), fileInfo.LastWriteTimeUtc)); case NativeMethods.TextKind.TextKind_AsciiWithUtf8Bom: // Note: Since we don't support UTF16 regex, just load all utf8 files as ascii. case NativeMethods.TextKind.TextKind_Utf8WithBom: const int utf8BomSize = 3; return(new AsciiFileContents(new FileContentsMemory(block, utf8BomSize, contentsByteCount - utf8BomSize), fileInfo.LastWriteTimeUtc)); #if false case NativeMethods.TextKind.TextKind_Utf8WithBom: var utf16Block = Conversion.UTF8ToUnicode(block); block.Dispose(); return(new Utf16FileContents(new FileContentsMemory(utf16Block, 0, utf16Block.ByteLength), fileInfo.LastWriteTimeUtc)); #endif case NativeMethods.TextKind.TextKind_ProbablyBinary: block.Dispose(); return(new BinaryFileContents(fileInfo.LastWriteTimeUtc, fileInfo.Length)); default: Invariants.Assert(false); throw new InvalidOperationException(); } }
private bool IsFileContentsUpToDate(FileSystemEntities entities, FullPathChanges fullPathChanges, FileWithContents existingFileWithContents) { Invariants.Assert(existingFileWithContents.Contents != null); var fullPath = existingFileWithContents.FileName.FullPath; if (fullPathChanges != null) { // We don't get file change events for file in symlinks, so we can't // rely on fullPathChanges contents for our heuristic of avoiding file // system access. // Actually, since we cannot reliable detect changes in symlinks, we enable this // optimization anyways, as we rely on the user to manually refresh the index // (that results in a "null" value for fullPathChanges) //if (!FileDatabaseSnapshot.IsContainedInSymLinkHelper(entities.Directories, existingFileWithContents.FileName)) { return(fullPathChanges.ShouldSkipLoadFileContents(fullPath)); //} } // Do the "expensive" check by going to the file system. var fi = _fileSystem.GetFileInfoSnapshot(fullPath); return ((fi.Exists) && (fi.IsFile) && (fi.LastWriteTimeUtc == existingFileWithContents.Contents.UtcLastModified)); }
public FileExtract FilePositionSpanToFileExtract(FilePositionSpan filePositionSpan, int maxTextExtent) { maxTextExtent = Math.Max(maxTextExtent, filePositionSpan.Length); var spanStart = filePositionSpan.Position; var spanEnd = spanStart + filePositionSpan.Length; var lineStart = GetLineStart(spanStart, maxTextExtent); var lineEnd = GetLineEnd(spanEnd, maxTextExtent); // prefix - span - suffix var extractLength = lineEnd - lineStart; var spanLength = filePositionSpan.Length; Invariants.Assert(spanLength <= extractLength); var prefixLength = Math.Min(spanStart - lineStart, maxTextExtent - spanLength); Invariants.Assert(prefixLength >= 0); var suffixLength = Math.Min(lineEnd - spanEnd, maxTextExtent - spanLength - prefixLength); Invariants.Assert(suffixLength >= 0); lineStart = spanStart - prefixLength; lineEnd = spanEnd + suffixLength; var text = GetText(lineStart, lineEnd - lineStart); var lineCol = GetLineColumn(spanStart); return(new FileExtract { Text = text, Offset = lineStart, Length = lineEnd - lineStart, LineNumber = lineCol.Item1, ColumnNumber = lineCol.Item2 }); }
private void Grow() { Invariants.Assert(_count == _entries.Length); Invariants.Assert(_count == _buckets.Length); Invariants.Assert(_freeListHead == -1); var oldEntries = _entries; var oldLength = _entries.Length; var newLength = HashCode.GetPrime(GrowSize(oldLength)); var newBuckets = new int[newLength]; var newEntries = new Entry[newLength]; Array.Copy(_entries, newEntries, _entries.Length); for (var entryIndex = 0; entryIndex < oldEntries.Length; entryIndex++) { var oldEntry = oldEntries[entryIndex]; if (oldEntry.IsValid) { var newBucketIndex = GetBucketIndex(oldEntry.HashCode, newLength); newEntries[entryIndex].SetNextIndex(AdjustBucketIndexRead(newBuckets[newBucketIndex])); newBuckets[newBucketIndex] = AdjustBucketIndexWrite(entryIndex); } } _buckets = newBuckets; _entries = newEntries; }
public static int WrapQueryStatus( IOleCommandTarget receiver, IOleCommandTarget implementer, ref System.Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, System.IntPtr pCmdText) { Invariants.Assert(receiver != null); var commandId = new CommandID(pguidCmdGroup, (int)prgCmds[0].cmdID); if (LogCommand(commandId)) { Logger.LogInfo("WrapQueryStatus: => recv={0}, impl={1}, parent={2}", receiver, GetImplementerString(implementer), GetParentTargetString(implementer)); } var hr = (implementer == null) ? (int)Constants.OLECMDERR_E_NOTSUPPORTED : implementer.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); if (LogCommand(commandId)) { Logger.LogInfo("WrapQueryStatus: <= recv={0}, impl={1}, parent={2}, hr={3}, cmdf={4}", receiver, GetImplementerString(implementer), GetParentTargetString(implementer), HrToString(hr), CmdFlagsToString(prgCmds)); } return(hr); }
public static NodeViewModel CreateNodeViewModel(INodeTemplateFactory templateFactory, FileSystemEntry entry, NodeViewModel parent) { Invariants.Assert(entry != null); Invariants.Assert(parent != null); var directoryEntry = entry as DirectoryEntry; var node = directoryEntry != null ? (NodeViewModel) new DirectoryNodeViewModel(parent) : (NodeViewModel) new FileNodeViewModel(parent); node.Caption = entry.Name; node.Name = entry.Name; if (PathHelpers.IsAbsolutePath(node.Name)) { node.Template = templateFactory.ProjectTemplate; } else if (directoryEntry != null) { node.Template = templateFactory.DirectoryTemplate; } else { var extension = Path.GetExtension(entry.Name); Invariants.Assert(extension != null); node.Template = templateFactory.GetFileTemplate(extension); } return(node); }
private void ComputeNewStateLongTask(FileSystemSnapshot previousSnapshot, FileSystemSnapshot newSnapshot, FullPathChanges fullPathChanges, CancellationToken cancellationToken) { Invariants.Assert(_inTaskQueueTask); UpdateFileDatabase(newSnapshot, options => { // We only allow incremental updates if the last update was successfully completed // and if the file system snapshot version we are based on is the same as the // new file system snapshot we are processing if (previousSnapshot.Version == _currentFileSystemSnapshotVersion && options.PreviousUpdateCompleted && fullPathChanges != null) { return(CreateWithFileSystemChanges(newSnapshot, fullPathChanges, options, cancellationToken)); } else { Logger.LogInfo($"Starting a full database update: " + $"CurrentSnapshotVersion={_currentFileSystemSnapshotVersion}, " + $"PreviousUpdateCompleted={options.PreviousUpdateCompleted}, " + $"PreviousSnapshotVersion={previousSnapshot.Version}, " + $"FullPathChanges={fullPathChanges?.Entries.Count ?? -1}."); return(CreateFullScan(newSnapshot, options, cancellationToken)); } }); }
private IHierarchyObject NextSibling(IHierarchyObject item) { if (item == null) { return(null); } var parent = item.GetParent(); if (parent == null) { return(null); } bool found = false; foreach (var child in parent.GetAllChildren()) { if (found) { return(child); } if (child.Equals(item)) { found = true; } } Invariants.Assert(found); return(null); }
private void ActivateCurrentDatabase(FileSystemSnapshot fileSystemSnapshot, IFileDatabaseSnapshot databaseSnapshot, bool complete) { Invariants.Assert(_inTaskQueueTask); _currentFileDatabase = databaseSnapshot; _currentFileSystemSnapshotVersion = fileSystemSnapshot.Version; _previousUpdateCompleted = complete; // Success => we allow incremtal updates next time }
public Func <int, ApplyChangesResult> ComputeChangeApplier() { // Capture hierarchy version # for checking later that another // thread did not beat us. int hierarchyVersion = _hierarchy.Version; var oldHierarchies = _hierarchy.CloneHierarchyList(); // For new hierarchies: create tree and compute nodes // For comon existing hierarchies: create tree and compute nodes // For removed hierarchies: create (empty) tree and compute nodes List <RootEntry> rootEntries = CreateRootEntries(oldHierarchies).ToList(); rootEntries.ForAll(entry => { entry.ChangeApplier = entry.Builder.ComputeChangeApplier(); }); return(latestFileSystemTreeVersion => { // Apply if nobody beat us to is. if (_hierarchy.Version == hierarchyVersion) { Logger.LogInfo( "Updating VsHierarchyAggregate nodes for version {0} and file system tree version {1}", hierarchyVersion, _fileSystemTree.Version); rootEntries.ForAll(entry => { var result = entry.ChangeApplier(latestFileSystemTreeVersion); Invariants.Assert(result == ApplyChangesResult.Done); }); var newHierarchies = rootEntries .Where(x => !x.Hierarchy.IsEmpty) .Select(x => x.Hierarchy) .ToList(); _hierarchy.SetNewHierarchies(newHierarchies); return ApplyChangesResult.Done; } Logger.LogInfo( "VsHierarchyAggregate nodes have been updated concurrently, re-run or skip operation." + " Node verions={0}-{1}, Tree versions:{2}-{3}.", hierarchyVersion, _hierarchy.Version, _fileSystemTree.Version, latestFileSystemTreeVersion); // If the version of the hieararchy has changed since when we started, // another thread has passed us. This means the decisions we made // about the changes to apply are incorrect at this point. So, we run // again if we are processing the latest known version of the file // system tree, as we should be the winner (eventually) if (_fileSystemTree.Version == latestFileSystemTreeVersion) { // Termination notes: We make this call only when the VsHierarchy // version changes between the time we capture it and this point. return ApplyChangesResult.Retry; } return ApplyChangesResult.Bail; }); }
public void AddNode(NodeViewModel node) { Invariants.Assert(node.ItemId != VSConstants.VSITEMID_NIL); _itemIdMap.Add(node.ItemId, node); if (node.ItemId != RootNodeItemId) { _maxItemId = Math.Max(_maxItemId, node.ItemId); } }
private void TreeViewScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { Invariants.Assert(_treeViewScrollViewer != null); if (_treeViewResetHorizScroll) { _treeViewScrollViewer.ScrollToHorizontalOffset(_treeViewHorizScrollPos); _treeViewResetHorizScroll = false; } }
private DirectoryName GetAncestor(DirectoryName x, int count) { Invariants.Assert(x != null); for (var i = 0; i < count; i++) { x = x.Parent; } Invariants.Assert(x != null); return(x); }
private static int MapIndexOf <T>(IDictionary <T, int> items, T item) { int result; if (!items.TryGetValue(item, out result)) { return(-1); } Invariants.Assert(result >= 0); return(result); }
private Tuple <int, int> GetLineColumn(int offset) { var lineNumber = GetLineStartIndex(offset); Invariants.Assert(lineNumber >= 0); Invariants.Assert(lineNumber < _listStartOffsets.Count); var columnNumber = offset - _listStartOffsets[lineNumber]; return(Tuple.Create(lineNumber, columnNumber)); }
public static int WrapExec( IOleCommandTarget receiver, IOleCommandTarget implementer, ref System.Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, System.IntPtr pvaIn, System.IntPtr pvaOut) { Invariants.Assert(receiver != null); var commandId = new CommandID(pguidCmdGroup, (int)nCmdID); if (LogCommand(commandId)) { Logger.LogInfo("WrapExec: => recv={0}, impl={1}, parent={2}", receiver, GetImplementerString(implementer), GetParentTargetString(implementer)); } var hr = (implementer == null) ? (int)Constants.OLECMDERR_E_NOTSUPPORTED : implementer.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); // Ensures OleMenuCommandService returns OLECMDERR_E_NOTSUPPORTED. if (hr == VSConstants.S_OK && implementer is OleMenuCommandService) { // Ensure we return OLECMDERR_E_NOTSUPPORTED instead of S_OK if our // command does not support the command id. This is necessary so that // the VS Shell chains the Exec call to other IOleCommandTarget // implementations. var service = (OleMenuCommandService)implementer; var command = service.FindCommand(commandId); if (command != null) { if (!command.Supported) { hr = (int)Constants.OLECMDERR_E_NOTSUPPORTED; } } } if (LogCommand(commandId)) { Logger.LogInfo("WrapExec: <= recv={0}, impl={1}, parent={2}, hr={3}", receiver, GetImplementerString(implementer), GetParentTargetString(implementer), HrToString(hr)); } return(hr); }
private int GetDistanceToAbsolutePath(DirectoryName x) { Invariants.Assert(x != null); for (int result = 0;; result++) { if (x is AbsoluteDirectoryName) { return(result); } x = x.Parent; Invariants.Assert(x != null); } }
public static T ExecuteAndWait <T>(this ITaskQueue queue, Func <CancellationToken, T> task) { var result = default(T); var e = new ManualResetEvent(false); queue.ExecuteAsync(token => { result = task(token); e.Set(); }); e.WaitOne(); Invariants.Assert(result != null); return(result); }
/// <summary> /// Returns the item (or null) directly following <paramref name="item"/> in /// "previous sibling, parent" order. /// </summary> public IHierarchyObject GetPreviousItem(IHierarchyObject item) { if (item == null) { return(null); } // a // b // c // d // e // // Return "b" is we are on "c" // Return "d" if we are on "e" // Return "e" if we are on "a" // Return "a" if we are on "b" // var result = PreviousSibling(item); if (result == null) { var parent = item.GetParent(); if (parent != null) { return(parent); } // "a" case: get the very last child at the bottom of the tree while (true) { Invariants.Assert(item != null); var last = LastChild(item); if (last == null) { return(item); } item = last; } } while (true) { Invariants.Assert(result != null); var last = LastChild(result); if (last == null) { return(result); } result = last; } }
private int GetLineStartIndex(int offset) { Invariants.Assert(offset >= 0); Invariants.Assert(_listStartOffsets[0] == 0); var result = _listStartOffsets.BinarySearch(offset); if (result < 0) { var insertionIndex = ~result; return(insertionIndex - 1); } return(result); }