/// <summary> /// Processes a document change event and updates a given snapshot based on the doc change. /// </summary> /// <param name="result">The result.</param> /// <param name="currentFile">The current file.</param> /// <param name="lastDocChanges">The last document changes.</param> /// <param name="files">The files.</param> /// <param name="docChange">The document change.</param> /// <returns>The path of the current file.</returns> private string ProcessDocumentChange( EntireSnapshot result, string currentFile, Dictionary <string, DocumentChange> lastDocChanges, Dictionary <string, StringBuilder> files, Event docChange) { if (docChange is FileOpenCommand) { currentFile = ProcessFileOpenCommand( (FileOpenCommand)docChange, files, lastDocChanges, result); } else if (docChange is DocumentChange) { if (currentFile == null) { // Ignore document change events until a FileOpenCommand appears. // continue; } this.ApplyDocumentChange( (DocumentChange)docChange, files, currentFile, lastDocChanges); } return(currentFile); }
/// <summary> /// Initializes a new instance of the <see cref="EntireSnapshot"/> class. /// </summary> /// <param name="other">The existing snapshot object to copy from.</param> public EntireSnapshot(EntireSnapshot other) { if (other == null) { throw new ArgumentNullException(); } this.FilePaths = new List <string>(other.FilePaths); this.FileSnapshots = new Dictionary <string, FileSnapshot>(other.FileSnapshots); }
/// <summary> /// Calculates the snapshot at the given event. /// </summary> /// <param name="anEvent">The event.</param> /// <returns> /// The entire snapshot /// </returns> public EntireSnapshot CalculateSnapshotAtEvent(Event anEvent) { // Check the cache first. if (this.cache.ContainsKey(anEvent)) { return(this.cache[anEvent]); } Event lastEvent = null; EntireSnapshot lastKnownSnapshot = null; var priorEvents = this.cache.Keys.Where(x => x.ID < anEvent.ID); if (priorEvents.Count() > 0) { lastEvent = priorEvents.Aggregate((x, y) => x.ID > y.ID ? x : y); lastKnownSnapshot = this.cache[lastEvent]; } return(this.CalculateSnapshotAtEvent(lastEvent, lastKnownSnapshot, anEvent)); }
/// <summary> /// Processes the file open command. /// </summary> /// <param name="foc">The file open command.</param> /// <param name="files">The files.</param> /// <param name="lastDocChanges">The last document changes.</param> /// <param name="result">The result.</param> /// <returns>The new current file path.</returns> private static string ProcessFileOpenCommand( FileOpenCommand foc, Dictionary <string, StringBuilder> files, Dictionary <string, DocumentChange> lastDocChanges, EntireSnapshot result) { string currentFile = foc.FilePath; if (!result.FilePaths.Contains(currentFile)) { result.FilePaths.Insert(0, currentFile); lastDocChanges.Add(currentFile, null); if (foc.Snapshot == null) { files.Add(currentFile, null); } else { files.Add(currentFile, new StringBuilder(foc.Snapshot)); } } else { // Bring the current file to the front result.FilePaths.Remove(currentFile); result.FilePaths.Insert(0, currentFile); // If this command has a new snapshot, replace it. if (foc.Snapshot != null) { files[currentFile] = new StringBuilder(foc.Snapshot); } } return(currentFile); }
/// <summary> /// Calculates the snapshot at the given event. /// </summary> /// <param name="lastEvent">The last event associated with the last known snapshot.</param> /// <param name="lastKnownSnapshot">The last known snapshot.</param> /// <param name="anEvent">The event.</param> /// <returns> /// The entire snapshot /// </returns> public EntireSnapshot CalculateSnapshotAtEvent( Event lastEvent, EntireSnapshot lastKnownSnapshot, Event anEvent) { if (!this.LogProvider.LoggedEvents.Contains(anEvent) || (lastEvent != null && !this.LogProvider.LoggedEvents.Contains(lastEvent))) { throw new ArgumentException( "The passed event is not originated from the " + "LogProvider of this snapshot calculator"); } if ((lastEvent != null && lastKnownSnapshot == null) || (lastEvent == null && lastKnownSnapshot != null)) { throw new ArgumentException( "lastEvent and lastKnownSnapshot must be either both null or both non-null."); } EntireSnapshot result = lastKnownSnapshot != null ? new EntireSnapshot(lastKnownSnapshot) : new EntireSnapshot(); var docChanges = this.LogProvider.LoggedEvents; if (lastEvent != null) { docChanges = docChanges.SkipUntil(x => x == lastEvent); } docChanges = docChanges .TakeUntil(x => x == anEvent) .Where(x => this.IsValidFileOpenCommand(x) || x is DocumentChange); string currentFile = result.CurrentFile; var lastDocChanges = new Dictionary <string, DocumentChange>(); Dictionary <string, StringBuilder> files = new Dictionary <string, StringBuilder>(); foreach (var fileSnapshot in result.FileSnapshots.Values) { lastDocChanges.Add(fileSnapshot.FilePath, fileSnapshot.LastChange); files.Add( fileSnapshot.FilePath, fileSnapshot.Content != null ? new StringBuilder(fileSnapshot.Content) : null); } // calculation loop. foreach (Event docChange in docChanges) { currentFile = this.ProcessDocumentChange( result, currentFile, lastDocChanges, files, docChange); } // set the result foreach (string filePath in result.FilePaths) { FileSnapshot fileSnapshot = new FileSnapshot(); fileSnapshot.FilePath = filePath; fileSnapshot.Content = files[filePath] != null ? files[filePath].ToString() : null; fileSnapshot.LastChange = lastDocChanges[filePath]; result.FileSnapshots[filePath] = fileSnapshot; } // Add the current result to the cache. this.cache[anEvent] = result; return(result); }