public void TestUndoRedoCommand() { // Arrange var project = new Project(); var context = new BlockCommandContext(project); ProjectBlockCollection blocks = project.Blocks; Block block = blocks[0]; using (block.AcquireBlockLock(RequestLock.Write)) { block.SetText("abcd"); } int blockVersion = block.Version; BlockKey blockKey = block.BlockKey; var command = new ReplaceTextCommand( new BlockPosition(blockKey, 2), 1, "YES"); project.Commands.Do(command, context); project.Commands.Undo(context); // Act project.Commands.Redo(context); // Assert Assert.AreEqual(1, blocks.Count); Assert.AreEqual( new BlockPosition(blocks[0], 5), project.Commands.LastPosition); const int index = 0; Assert.AreEqual("abYESd", blocks[index].Text); Assert.AreEqual(blockVersion + 6, blocks[index].Version); }
/// <summary> /// Inserts the lines. /// </summary> /// <param name="project">The project.</param> /// <param name="lineCount">The line count.</param> private void InsertLines( Project project, int lineCount) { // Pull out some useful variables. ProjectBlockCollection blocks = project.Blocks; // Modify the first line, which is always there. using (blocks[0].AcquireBlockLock(RequestLock.Write)) { blocks[0].SetText("Line 1"); } // Add in the additional lines after the first one. for (int i = 1; i < lineCount; i++) { var block = new Block(blocks); using (block.AcquireBlockLock(RequestLock.Write)) { block.SetText("Line " + (i + 1)); } blocks.Add(block); } }
public void TestUndoRedoCommand() { // Arrange var project = new Project(); var context = new BlockCommandContext(project); ProjectBlockCollection blocks = project.Blocks; Block block = blocks[0]; using (block.AcquireBlockLock(RequestLock.Write)) { block.SetText("Testing 123"); } BlockKey blockKey = block.BlockKey; var command = new InsertAfterBlockCommand(blockKey, 1); project.Commands.Do(command, context); project.Commands.Undo(context); // Act project.Commands.Redo(context); // Assert Assert.AreEqual(2, blocks.Count); Assert.AreEqual( new BlockPosition(blocks[1], 0), project.Commands.LastPosition); int index = 0; Assert.AreEqual("Testing 123", blocks[index].Text); index++; Assert.AreEqual("", blocks[index].Text); }
public void ChangeBlockType( Block block, BlockType oldBlockType) { // We need a write lock on the blocks while we make this change. using (block.AcquireBlockLock(RequestLock.Write)) { // Report what we're doing if we have logging on. Log("ChangeBlockType: {0}: Old Type {1}", block, oldBlockType); //// Figure out the deltas for this block. //var deltas = new Dictionary<HierarchicalPath, int>(); //deltas[WordCounterPathUtility.GetPath(oldBlockType)] = -1; //deltas[WordCounterPathUtility.GetPath(block.BlockType)] = 1; //// Update the parent types. //UpdateDeltas(block, deltas); //UpdateDeltas(block.Project, deltas); } }
/// <summary> /// Processes any block analysis on the given block. /// </summary> /// <param name="block">The block.</param> public async void ProcessBlockAnalysis(Block block) { // If we don't have any analysis controllers, we don't have to do anything. if (BlockAnalyzers.Count == 0) { return; } // Keep track of the running tasks so we can wait for them to finish // (if needed). Interlocked.Increment(ref tasksRunning); try { // Grab information about the block inside a read lock. int blockVersion; HashSet <IBlockAnalyzerProjectPlugin> analysis; using (block.AcquireBlockLock(RequestLock.Read)) { blockVersion = block.Version; analysis = block.GetAnalysis(); } // Create a background task that will analyze the block. This will return // false if the block had changed in the process of analysis (which would // have triggered another background task). var analyzer = new BlockAnalyzer( block, blockVersion, BlockAnalyzers, analysis); Task task = Task.Factory.StartNew(analyzer.Run); // Wait for the task to complete in the background so we can then // decrement our running counter. await task; } finally { // Decrement the counter to keep track of running tasks. Interlocked.Decrement(ref tasksRunning); } }
public void WriteRead() { // Arrange: Cleanup any existing output file. DirectoryInfo testDirectory = PrepareTestDirectory(); // Arrange: Set up the plugin. ProjectBlockCollection blocks; BlockCommandSupervisor commands; PluginSupervisor plugins; FilesystemPersistenceProjectPlugin projectPlugin; SetupPlugin(out blocks, out commands, out plugins, out projectPlugin); PersistenceManager persistenceManager = PersistenceManager.Instance; // Arrange: Create a project with some interesting data and write it out. SetupComplexMultilineTest(blocks.Project, 10); blocks.Project.BlockTypes.Add("Custom Type", false); Block block = blocks[0]; block.Properties[new HierarchicalPath("/Test")] = "Custom Property"; block.TextSpans.Add(new TextSpan(1, 3, null, null)); using (block.AcquireBlockLock(RequestLock.Write)) { block.SetText("Incor Wurd Onz"); } plugins.WaitForBlockAnalzyers(); projectPlugin.Settings.SetIndividualDirectoryLayout(); projectPlugin.Save(testDirectory); // Act var projectFile = new FileInfo(Path.Combine(testDirectory.FullName, "Project.aiproj")); Project project = persistenceManager.ReadProject(projectFile); // Assert: Block Types block = project.Blocks[0]; BlockTypeSupervisor blockTypes = project.BlockTypes; blocks = project.Blocks; Assert.AreEqual(2, project.Plugins.Controllers.Count); Assert.NotNull(blockTypes["Custom Type"]); Assert.IsFalse(blockTypes["Custom Type"].IsStructural); // Assert: Blocks Assert.AreEqual(10, blocks.Count); Assert.AreEqual(blockTypes.Chapter, block.BlockType); Assert.AreEqual("Incor Wurd Onz", block.Text); Assert.AreEqual(blockTypes.Scene, blocks[1].BlockType); Assert.AreEqual("Line 2", blocks[1].Text); Assert.AreEqual(blockTypes.Epigraph, blocks[2].BlockType); Assert.AreEqual("Line 3", blocks[2].Text); Assert.AreEqual(blockTypes.EpigraphAttribution, blocks[3].BlockType); Assert.AreEqual("Line 4", blocks[3].Text); Assert.AreEqual(blockTypes.Paragraph, blocks[9].BlockType); Assert.AreEqual("Line 10", blocks[9].Text); // Assert: Verify content data. Assert.AreEqual(1, block.Properties.Count); Assert.AreEqual( "Custom Property", block.Properties[new HierarchicalPath("/Test")]); // Assert: Verify text spans. Assert.AreEqual(1, block.TextSpans.Count); Assert.AreEqual(1, block.TextSpans[0].StartTextIndex); Assert.AreEqual(3, block.TextSpans[0].StopTextIndex); Assert.IsNull(block.TextSpans[0].Controller); Assert.IsNull(block.TextSpans[0].Data); }
/// <summary> /// Analyzes the block and counts the word. Once counted, this updates /// the block and all parent blocks with the altered change. /// </summary> /// <param name="block">The block.</param> /// <param name="blockVersion">The block version of the initial request.</param> public void AnalyzeBlock( Block block, int blockVersion) { // Grab counts from the current block text. int newCount = 1; int newWordCount; int newCharacterCount; int newNonWhitespaceCount; string text = block.Text; WordCounter.CountWords( text, out newWordCount, out newCharacterCount, out newNonWhitespaceCount); // Grab the existing counts from the current block, if we have one. int oldCount; int oldWordCount; int oldCharacterCount; int oldNonWhitespaceCount; WordCounterPathUtility.GetCounts( this, block, out oldCount, out oldWordCount, out oldCharacterCount, out oldNonWhitespaceCount); // Calculate the deltas between the values. int delta = newCount - oldCount; int wordDelta = newWordCount - oldWordCount; int characterDelta = newCharacterCount - oldCharacterCount; int nonWhitespaceDelta = newNonWhitespaceCount - oldNonWhitespaceCount; // Build up a dictionary of changes so we can have a simple loop to // set them in the various elements. Dictionary <HierarchicalPath, int> deltas = WordCounterPathUtility.GetDeltas( this, block, delta, wordDelta, characterDelta, nonWhitespaceDelta); // Get a write lock on the blocks list and update that block and all // parent blocks in the document. using (block.AcquireBlockLock(RequestLock.Write)) { // Log that we are analyzing this block. Log("BEGIN AnalyzeBlock: {0}: Words {1:N0}", block, newWordCount); // First check to see if we've gotten stale. if (block.IsStale(blockVersion)) { return; } // Update the block and the document. UpdateDeltas(block, deltas); UpdateDeltas(block.Project, deltas); // Log that we finished processing this block. Log("END AnalyzeBlock: {0}: Words {1:N0}", block, newWordCount); } }
public void Do(BlockCommandContext context) { // We have to clear the undo buffer every time because we'll be creating // new blocks. addedBlocks.Clear(); // Start by breaking apart the lines on the newline. string[] lines = Text.Split('\n'); // Make changes to the first line by creating a command, adding it to the // list of commands we need an inverse for, and then performing it. Block block = context.Blocks[BlockPosition.BlockKey]; string remainingText = block.Text.Substring((int)BlockPosition.TextIndex); deleteFirstCommand = new DeleteTextCommand(BlockPosition, block.Text.Length); insertFirstCommand = new InsertTextCommand(BlockPosition, lines[0]); deleteFirstCommand.Do(context); insertFirstCommand.Do(context); // Update the final lines text with the remains of the first line. int lastLineLength = lines[lines.Length - 1].Length; lines[lines.Length - 1] += remainingText; // For the remaining lines, we need to insert each one in turn. if (UpdateTextPosition.HasFlag(DoTypes.Do)) { context.Position = BlockPosition.Empty; } if (lines.Length > 1) { // Go through all the lines in reverse order to insert them. int firstBlockIndex = context.Blocks.IndexOf(block); for (int i = lines.Length - 1; i > 0; i--) { // Insert the line and set its text value. var newBlock = new Block(context.Blocks); addedBlocks.Add(newBlock); using (newBlock.AcquireBlockLock(RequestLock.Write)) { newBlock.SetText(lines[i]); } context.Blocks.Insert(firstBlockIndex + 1, newBlock); // Update the last position as we go. if (context.Position == BlockPosition.Empty) { if (UpdateTextPosition.HasFlag(DoTypes.Do)) { context.Position = new BlockPosition( newBlock.BlockKey, (CharacterPosition)lastLineLength); } } } } }
public void AnalyzeBlock( Block block, int blockVersion) { // Grab the information about the block. string text; var originalMispelledWords = new TextSpanCollection(); using (block.AcquireBlockLock(RequestLock.Read)) { // If we are stale, then break out. if (block.IsStale(blockVersion)) { return; } // Grab the information from the block. We need the text and // alow the current spelling areas. text = block.Text; originalMispelledWords.AddRange( block.TextSpans.Where(span => span.Controller == this)); } // Split the word and perform spell-checking. var misspelledWords = new List <TextSpan>(); IList <TextSpan> words = Splitter.SplitAndNormalize(text); IEnumerable <TextSpan> misspelledSpans = words.Where(span => !IsCorrect(span.GetText(text))); foreach (TextSpan span in misspelledSpans) { // We aren't correct, so add it to the list. span.Controller = this; misspelledWords.Add(span); } // Look to see if we have any change from the original spelling // errors and this one. This will only happen if the count is // identical and every one in the original list is in the new list. if (originalMispelledWords.Count == misspelledWords.Count) { bool isMatch = originalMispelledWords.All(misspelledWords.Contains); if (isMatch) { // There are no new changes, so we don't have anything to // update. return; } } // Inside a write lock, we need to make modifications to the block's list. using (block.AcquireBlockLock(RequestLock.Write)) { // Check one last time to see if the block is stale. if (block.IsStale(blockVersion)) { return; } // Make the changes to the block's contents. block.TextSpans.Remove(this); block.TextSpans.AddRange(misspelledWords); // Raise that we changed the spelling on the block. block.RaiseTextSpansChanged(); } }