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 DeleteTextCommand(new BlockPosition(blockKey, 2), 3);
            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 + 2, blocks[index].Version);
        }
        public ReplaceTextCommand(
			BlockPosition position,
			int length,
			string text)
            : base(position, true)
        {
            // Save the text for the changes.
            Length = length;
            Text = text;

            // Create the commands in this command.
            var deleteCommand = new DeleteTextCommand(
                position, (int) position.TextIndex + Length);
            var insertCommand = new InsertTextCommand(position, Text);

            Commands.Add(deleteCommand);
            Commands.Add(insertCommand);
        }
        public ReplaceTextCommand(
            BlockPosition position,
            int length,
            string text)
            : base(position, true)
        {
            // Save the text for the changes.
            Length = length;
            Text   = text;

            // Create the commands in this command.
            var deleteCommand = new DeleteTextCommand(
                position, (int)position.TextIndex + Length);
            var insertCommand = new InsertTextCommand(position, Text);

            Commands.Add(deleteCommand);
            Commands.Add(insertCommand);
        }
        public DeleteMultilineTextCommand(
            BlockCollection blocks,
            BlockPosition startPosition,
            BlockPosition stopPosition)
            : base(true, false)
        {
            // Save the variables so we can set the position.
            this.startPosition = startPosition;
            this.stopPosition  = stopPosition;

            // If we are in the same line, we have a modified command.
            if (startPosition.BlockKey == stopPosition.BlockKey)
            {
                // We have a single-line delete.
                var singleDeleteCommand = new DeleteTextCommand(
                    startPosition, stopPosition.TextIndex);

                Commands.Add(singleDeleteCommand);
                return;
            }

            // Start by removing the text to the right of the first line.
            var deleteTextCommand = new DeleteTextCommand(
                startPosition, CharacterPosition.End);

            Commands.Add(deleteTextCommand);

            // Copy the final line text, from beginning to position, into the first
            // line. This will merge the top and bottom lines.
            var insertTextCommand = new InsertTextFromBlock(
                startPosition,
                stopPosition.BlockKey,
                stopPosition.TextIndex,
                CharacterPosition.End);

            Commands.Add(insertTextCommand);

            // Once we have a merged line, then just delete the remaining lines.
            // Figure out line ranges we'll be deleting text from.
            removedBlocks = new List <Block>();

            Block startBlock = blocks[startPosition.BlockKey];
            Block stopBlock  = blocks[stopPosition.BlockKey];

            int startIndex = blocks.IndexOf(startBlock);
            int stopIndex  = blocks.IndexOf(stopBlock);

            // Go through the remaining lines.
            for (int i = startIndex + 1;
                 i <= stopIndex;
                 i++)
            {
                // Get the block we're removing and add it to the list.
                Block removeBlock = blocks[i];

                removedBlocks.Add(removeBlock);

                // Add in a command to remove the block.
                var deleteBlockCommand = new DeleteBlockCommand(removeBlock.BlockKey);

                Commands.Add(deleteBlockCommand);
            }
        }
        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 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);
                        }
                    }
                }
            }
        }