public void TestUndoCommand() { // 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); // Act project.Commands.Undo(context); // Assert Assert.AreEqual(1, blocks.Count); Assert.AreEqual( new BlockPosition(blocks[0], 3), project.Commands.LastPosition); const int index = 0; Assert.AreEqual("abcd", blocks[index].Text); Assert.AreEqual(blockVersion + 4, blocks[index].Version); }
public void ProcessImmediateEdits( BlockCommandContext context, Block block, int textIndex) { // Get the plugin settings from the project. ImmediateBlockTypesSettings settings = Settings; // Grab the substring from the beginning to the index and compare that // in the dictionary. string text = block.Text.Substring(0, textIndex); if (!settings.Replacements.ContainsKey(text)) { // We want to fail as fast as possible. return; } // If the block type is already set to the same name, skip it. string blockTypeName = settings.Replacements[text]; BlockType blockType = Project.BlockTypes[blockTypeName]; if (block.BlockType == blockType) { return; } // Perform the substitution with a replace operation and a block change // operation. var replaceCommand = new ReplaceTextCommand( new BlockPosition(block.BlockKey, 0), textIndex, string.Empty); var changeCommand = new ChangeBlockTypeCommand(block.BlockKey, blockType); // Create a composite command that binds everything together. var compositeCommand = new CompositeCommand<BlockCommandContext>(true, false); compositeCommand.Commands.Add(replaceCommand); compositeCommand.Commands.Add(changeCommand); // Add the command to the deferred execution so the command could // be properly handled via the undo/redo management. block.Project.Commands.DeferDo(compositeCommand); }
public void ProcessImmediateEdits( BlockCommandContext context, Block block, int textIndex) { // If we aren't optimized, we have to pull the settings back in from the // project settings and optimize them. if (!optimizedSubstitions) { RetrieveSettings(); } // Pull out the edit text and add a leading space to simplify the // "whole word" substitutions. string editText = block.Text.Substring(0, textIndex); if (editText.Length - 1 < 0) { return; } // Figure out if we're at a word break. char finalCharacter = editText[editText.Length - 1]; bool isWordBreak = char.IsPunctuation(finalCharacter) || char.IsWhiteSpace(finalCharacter); // Go through the substitution elements and look for each one. foreach (RegisteredSubstitution substitution in Substitutions) { // If we are doing whole word searches, then we don't bother if // the final character isn't a word break or if it isn't a word // break before it. ReplaceTextCommand command; int searchLength = substitution.Search.Length; int startSearchIndex = editText.Length - searchLength; // If we are going to be searching before the string, then this // search term will never be valid. if (startSearchIndex < 0) { continue; } // Do the search based on the whole word or suffix search. if (substitution.IsWholeWord) { // Check to see if we have a valid search term. if (!isWordBreak) { continue; } if (startSearchIndex > 0 && char.IsPunctuation(editText[startSearchIndex - 1])) { continue; } if (startSearchIndex - 1 < 0) { continue; } // Make sure the string we're looking at actually is the same. string editSubstring = editText.Substring( startSearchIndex - 1, substitution.Search.Length); if (editSubstring != substitution.Search) { // The words don't match. continue; } // Perform the substitution with a replace operation. command = new ReplaceTextCommand( new BlockPosition(block.BlockKey, startSearchIndex - 1), searchLength + 1, substitution.Replacement + finalCharacter); } else { // Perform a straight comparison search. if (!editText.EndsWith(substitution.Search)) { continue; } // Figure out the replace operation. command = new ReplaceTextCommand( new BlockPosition(block.BlockKey, startSearchIndex), searchLength, substitution.Replacement); } // Add the command to the deferred execution so the command could // be properly handled via the undo/redo management. block.Project.Commands.DeferDo(command); } }
/// <summary> /// Gets the editor actions associated with the given TextSpan. /// </summary> /// <param name="block">The block.</param> /// <param name="textSpan">The text span.</param> /// <returns> /// A list of editor actions associated with this span. /// </returns> /// <remarks> /// This will be called within a read-only lock. /// </remarks> public IList<IEditorAction> GetEditorActions( Block block, TextSpan textSpan) { // We only get to this point if we have a misspelled word. string word = textSpan.GetText(block.Text); // Get the suggestions for the word. IList<SpellingSuggestion> suggestions = GetSuggestions(word); // Go through the suggestions and create an editor action for each one. // These will already be ordered coming out of the GetSuggestions() // method. BlockCommandSupervisor commands = block.Project.Commands; var actions = new List<IEditorAction>(suggestions.Count); foreach (SpellingSuggestion suggestion in suggestions) { // Figure out the operation we'll be using to implement the change. var command = new ReplaceTextCommand( new BlockPosition(block.BlockKey, textSpan.StartTextIndex), textSpan.Length, suggestion.Suggestion); // Create the suggestion action, along with the replacement command. var action = new EditorAction( string.Format("Change to \"{0}\"", suggestion.Suggestion), new HierarchicalPath("/Plugins/Spelling/Change"), context => commands.Do(command, context)); actions.Add(action); } // Add the additional editor actions from the plugins. foreach (ISpellingProjectPlugin controller in SpellingControllers) { IEnumerable<IEditorAction> additionalActions = controller.GetAdditionalEditorActions(word); actions.AddRange(additionalActions); } // Return all the change actions. return actions; }